home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / md / unix / pthreads_user.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  11.4 KB  |  466 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "primpl.h"
  20. #include <sys/types.h>
  21. #include <unistd.h>
  22. #include <signal.h>
  23. #include <pthread.h>
  24.  
  25.  
  26. sigset_t ints_off;
  27. pthread_mutex_t    _pr_heapLock;
  28. pthread_key_t current_thread_key;
  29. pthread_key_t current_cpu_key;
  30. pthread_key_t last_thread_key;
  31. pthread_key_t intsoff_key;
  32.  
  33.  
  34. PRInt32 _pr_md_pthreads_created, _pr_md_pthreads_failed;
  35. PRInt32 _pr_md_pthreads = 1;
  36.  
  37. void _MD_EarlyInit(void)
  38. {
  39. extern PRInt32 _nspr_noclock;
  40.  
  41. #ifdef HPUX
  42.     _MD_hpux_install_sigfpe_handler();
  43. #endif
  44.  
  45.     if (pthread_key_create(¤t_thread_key, NULL) != 0) {
  46.         perror("pthread_key_create failed");
  47.         exit(1);
  48.     }
  49.     if (pthread_key_create(¤t_cpu_key, NULL) != 0) {
  50.         perror("pthread_key_create failed");
  51.         exit(1);
  52.     }
  53.     if (pthread_key_create(&last_thread_key, NULL) != 0) {
  54.         perror("pthread_key_create failed");
  55.         exit(1);
  56.     }
  57.     if (pthread_key_create(&intsoff_key, NULL) != 0) {
  58.         perror("pthread_key_create failed");
  59.         exit(1);
  60.     }
  61.  
  62.     sigemptyset(&ints_off);
  63.     sigaddset(&ints_off, SIGALRM);
  64.     sigaddset(&ints_off, SIGIO);
  65.     sigaddset(&ints_off, SIGCLD);
  66.  
  67.     /*
  68.      * disable clock interrupts
  69.      */
  70.     _nspr_noclock = 1;
  71.  
  72. }
  73.  
  74. void _MD_InitLocks()
  75. {
  76.     if (pthread_mutex_init(&_pr_heapLock, NULL) != 0) {
  77.         perror("pthread_mutex_init failed");
  78.         exit(1);
  79.     }
  80. }
  81.  
  82. PR_IMPLEMENT(void) _MD_FREE_LOCK(struct _MDLock *lockp)
  83. {
  84.     PRIntn _is;
  85.     PRThread *me = _PR_MD_CURRENT_THREAD();
  86.  
  87.     if (me && !_PR_IS_NATIVE_THREAD(me))
  88.         _PR_INTSOFF(_is); 
  89.     pthread_mutex_destroy(&lockp->mutex);
  90.     if (me && !_PR_IS_NATIVE_THREAD(me))
  91.         _PR_FAST_INTSON(_is);
  92. }
  93.  
  94.  
  95.  
  96. PR_IMPLEMENT(PRStatus) _MD_NEW_LOCK(struct _MDLock *lockp)
  97. {
  98.     PRStatus rv;
  99.     PRIntn is;
  100.     PRThread *me = _PR_MD_CURRENT_THREAD();    
  101.  
  102.     if (me && !_PR_IS_NATIVE_THREAD(me))
  103.         _PR_INTSOFF(is);
  104.     rv = pthread_mutex_init(&lockp->mutex, NULL);
  105.     if (me && !_PR_IS_NATIVE_THREAD(me))
  106.         _PR_FAST_INTSON(is);
  107.     return (rv == 0) ? PR_SUCCESS : PR_FAILURE;
  108. }
  109.  
  110.  
  111. PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
  112. {
  113.     if (isCurrent) {
  114.     (void) setjmp(CONTEXT(t));
  115.     }
  116.     *np = sizeof(CONTEXT(t)) / sizeof(PRWord);
  117.     return (PRWord *) CONTEXT(t);
  118. }
  119.  
  120. PR_IMPLEMENT(void)
  121. _MD_SetPriority(_MDThread *thread, PRThreadPriority newPri)
  122. {
  123.     /*
  124.      * XXX - to be implemented
  125.      */
  126.     return;
  127. }
  128.  
  129. PR_IMPLEMENT(PRStatus) _MD_InitThread(struct PRThread *thread)
  130. {
  131.     struct sigaction sigact;
  132.  
  133.     if (thread->flags & _PR_GLOBAL_SCOPE) {
  134.         thread->md.pthread = pthread_self();
  135. #if 0
  136.         /*
  137.          * set up SIGUSR1 handler; this is used to save state
  138.          * during PR_SuspendAll
  139.          */
  140.         sigact.sa_handler = save_context_and_block;
  141.         sigact.sa_flags = SA_RESTART;
  142.         /*
  143.          * Must mask clock interrupts
  144.          */
  145.         sigact.sa_mask = timer_set;
  146.         sigaction(SIGUSR1, &sigact, 0);
  147. #endif
  148.     }
  149.  
  150.     return PR_SUCCESS;
  151. }
  152.  
  153. PR_IMPLEMENT(void) _MD_ExitThread(struct PRThread *thread)
  154. {
  155.     if (thread->flags & _PR_GLOBAL_SCOPE) {
  156.         _MD_CLEAN_THREAD(thread);
  157.         _MD_SET_CURRENT_THREAD(NULL);
  158.     }
  159. }
  160.  
  161. PR_IMPLEMENT(void) _MD_CleanThread(struct PRThread *thread)
  162. {
  163.     if (thread->flags & _PR_GLOBAL_SCOPE) {
  164.         pthread_mutex_destroy(&thread->md.pthread_mutex);
  165.         pthread_cond_destroy(&thread->md.pthread_cond);
  166.     }
  167. }
  168.  
  169. PR_IMPLEMENT(void) _MD_SuspendThread(struct PRThread *thread)
  170. {
  171.     PRInt32 rv;
  172.  
  173.     PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) &&
  174.         (thread->flags & _PR_GCABLE_THREAD));
  175. #if 0
  176.     thread->md.suspending_id = getpid();
  177.     rv = kill(thread->md.id, SIGUSR1);
  178.     PR_ASSERT(rv == 0);
  179.     /*
  180.      * now, block the current thread/cpu until woken up by the suspended
  181.      * thread from it's SIGUSR1 signal handler
  182.      */
  183.     blockproc(getpid());
  184. #endif
  185. }
  186.  
  187. PR_IMPLEMENT(void) _MD_ResumeThread(struct PRThread *thread)
  188. {
  189.     PRInt32 rv;
  190.  
  191.     PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) &&
  192.         (thread->flags & _PR_GCABLE_THREAD));
  193. #if 0
  194.     rv = unblockproc(thread->md.id);
  195. #endif
  196. }
  197.  
  198. PR_IMPLEMENT(void) _MD_SuspendCPU(struct _PRCPU *thread)
  199. {
  200.     PRInt32 rv;
  201.  
  202. #if 0
  203.     cpu->md.suspending_id = getpid();
  204.     rv = kill(cpu->md.id, SIGUSR1);
  205.     PR_ASSERT(rv == 0);
  206.     /*
  207.      * now, block the current thread/cpu until woken up by the suspended
  208.      * thread from it's SIGUSR1 signal handler
  209.      */
  210.     blockproc(getpid());
  211. #endif
  212. }
  213.  
  214. PR_IMPLEMENT(void) _MD_ResumeCPU(struct _PRCPU *thread)
  215. {
  216. #if 0
  217.     unblockproc(cpu->md.id);
  218. #endif
  219. }
  220.  
  221.  
  222. #define PT_NANOPERMICRO 1000UL
  223. #define PT_BILLION 1000000000UL
  224.  
  225. PR_IMPLEMENT(PRStatus)
  226. _pt_wait(PRThread *thread, PRIntervalTime timeout)
  227. {
  228. int rv;
  229. struct timeval now;
  230. struct timespec tmo;
  231. PRUint32 ticks = PR_TicksPerSecond();
  232.  
  233.  
  234.     if (timeout != PR_INTERVAL_NO_TIMEOUT) {
  235.         tmo.tv_sec = timeout / ticks;
  236.         tmo.tv_nsec = timeout - (tmo.tv_sec * ticks);
  237.         tmo.tv_nsec = PR_IntervalToMicroseconds(PT_NANOPERMICRO *
  238.                                             tmo.tv_nsec);
  239.  
  240.         /* pthreads wants this in absolute time, off we go ... */
  241. #if defined(SOLARIS) && defined(_SVID_GETTOD)
  242.         (void)gettimeofday(&now);
  243. #else
  244.         (void)gettimeofday(&now, NULL);
  245. #endif
  246.         /* that one's usecs, this one's nsecs - grrrr! */
  247.         tmo.tv_sec += now.tv_sec;
  248.         tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec);
  249.         tmo.tv_sec += tmo.tv_nsec / PT_BILLION;
  250.         tmo.tv_nsec %= PT_BILLION;
  251.     }
  252.  
  253.     pthread_mutex_lock(&thread->md.pthread_mutex);
  254.     thread->md.wait--;
  255.     if (thread->md.wait < 0) {
  256.         if (timeout != PR_INTERVAL_NO_TIMEOUT) {
  257.             rv = pthread_cond_timedwait(&thread->md.pthread_cond,
  258.                     &thread->md.pthread_mutex, &tmo);
  259.         }
  260.         else
  261.             rv = pthread_cond_wait(&thread->md.pthread_cond,
  262.                     &thread->md.pthread_mutex);
  263.         if (rv != 0) {
  264.             thread->md.wait++;
  265.         }
  266.     } else
  267.         rv = 0;
  268.     pthread_mutex_unlock(&thread->md.pthread_mutex);
  269.  
  270.     return (rv == 0) ? PR_SUCCESS : PR_FAILURE;
  271. }
  272.  
  273. PR_IMPLEMENT(PRStatus)
  274. _MD_wait(PRThread *thread, PRIntervalTime ticks)
  275. {
  276.     if ( thread->flags & _PR_GLOBAL_SCOPE ) {
  277.         _MD_CHECK_FOR_EXIT();
  278.         if (_pt_wait(thread, ticks) == PR_FAILURE) {
  279.             _MD_CHECK_FOR_EXIT();
  280.             /*
  281.              * wait timed out
  282.              */
  283.             _PR_THREAD_LOCK(thread);
  284.             if (thread->wait.cvar) {
  285.                 /*
  286.                  * The thread will remove itself from the waitQ
  287.                  * of the cvar in _PR_WaitCondVar
  288.                  */
  289.                 thread->wait.cvar = NULL;
  290.                 thread->state =  _PR_RUNNING;
  291.                 _PR_THREAD_UNLOCK(thread);
  292.             }  else {
  293.                 _pt_wait(thread, PR_INTERVAL_NO_TIMEOUT);
  294.                 _PR_THREAD_UNLOCK(thread);
  295.             }
  296.         }
  297.     } else {
  298.         _PR_MD_SWITCH_CONTEXT(thread);
  299.     }
  300.     return PR_SUCCESS;
  301. }
  302.  
  303. PR_IMPLEMENT(PRStatus)
  304. _MD_WakeupWaiter(PRThread *thread)
  305. {
  306.     PRThread *me = _PR_MD_CURRENT_THREAD();
  307.     PRInt32 pid, rv;
  308.     PRIntn is;
  309.  
  310.     PR_ASSERT(_pr_md_idle_cpus >= 0);
  311.     if (thread == NULL) {
  312.         if (_pr_md_idle_cpus)
  313.             _MD_Wakeup_CPUs();
  314.     } else if (!_PR_IS_NATIVE_THREAD(thread)) {
  315.         /*
  316.          * If the thread is on my cpu's runq there is no need to
  317.          * wakeup any cpus
  318.          */
  319.         if (!_PR_IS_NATIVE_THREAD(me)) {
  320.             if (me->cpu != thread->cpu) {
  321.                 if (_pr_md_idle_cpus)
  322.                     _MD_Wakeup_CPUs();
  323.             }
  324.         } else {
  325.             if (_pr_md_idle_cpus)
  326.                 _MD_Wakeup_CPUs();
  327.         }
  328.     } else {
  329.         PR_ASSERT(_PR_IS_NATIVE_THREAD(thread));
  330.         if (!_PR_IS_NATIVE_THREAD(me))
  331.             _PR_INTSOFF(is);
  332.  
  333.         pthread_mutex_lock(&thread->md.pthread_mutex);
  334.         thread->md.wait++;
  335.         rv = pthread_cond_signal(&thread->md.pthread_cond);
  336.         PR_ASSERT(rv == 0);
  337.         pthread_mutex_unlock(&thread->md.pthread_mutex);
  338.  
  339.         if (!_PR_IS_NATIVE_THREAD(me))
  340.             _PR_FAST_INTSON(is);
  341.     } 
  342.     return PR_SUCCESS;
  343. }
  344.  
  345. /* These functions should not be called for AIX */
  346. PR_IMPLEMENT(void)
  347. _MD_YIELD(void)
  348. {
  349.     PR_NOT_REACHED("_MD_YIELD should not be called for AIX.");
  350. }
  351.  
  352. PR_IMPLEMENT(PRStatus)
  353. _MD_CreateThread(
  354.     PRThread *thread,
  355.     void (*start) (void *),
  356.     PRThreadPriority priority,
  357.     PRThreadScope scope,
  358.     PRThreadState state,
  359.     PRUint32 stackSize)
  360. {
  361.     PRIntn is;
  362.     PRThread *me = _PR_MD_CURRENT_THREAD();    
  363.     pthread_attr_t attr;
  364.  
  365.     if (!_PR_IS_NATIVE_THREAD(me))
  366.         _PR_INTSOFF(is);
  367.  
  368.     if (pthread_mutex_init(&thread->md.pthread_mutex, NULL) != 0) {
  369.         if (!_PR_IS_NATIVE_THREAD(me))
  370.             _PR_FAST_INTSON(is);
  371.         return PR_FAILURE;
  372.     }
  373.  
  374.     if (pthread_cond_init(&thread->md.pthread_cond, NULL) != 0) {
  375.         pthread_mutex_destroy(&thread->md.pthread_mutex);
  376.         if (!_PR_IS_NATIVE_THREAD(me))
  377.             _PR_FAST_INTSON(is);
  378.         return PR_FAILURE;
  379.     }
  380.     thread->flags |= _PR_GLOBAL_SCOPE;
  381.  
  382.     pthread_attr_init(&attr); /* initialize attr with default attributes */
  383.     if (pthread_attr_setstacksize(&attr, (size_t) stackSize) != 0) {
  384.         pthread_mutex_destroy(&thread->md.pthread_mutex);
  385.         pthread_cond_destroy(&thread->md.pthread_cond);
  386.         pthread_attr_destroy(&attr);
  387.         if (!_PR_IS_NATIVE_THREAD(me))
  388.             _PR_FAST_INTSON(is);
  389.         return PR_FAILURE;
  390.     }
  391.  
  392.     thread->md.wait = 0;
  393.     if (pthread_create(&thread->md.pthread, &attr, start, (void *)thread)
  394.                         == 0) {
  395.         _MD_ATOMIC_INCREMENT(&_pr_md_pthreads_created);
  396.         _MD_ATOMIC_INCREMENT(&_pr_md_pthreads);
  397.         if (!_PR_IS_NATIVE_THREAD(me))
  398.             _PR_FAST_INTSON(is);
  399.         return PR_SUCCESS;
  400.     } else {
  401.         pthread_mutex_destroy(&thread->md.pthread_mutex);
  402.         pthread_cond_destroy(&thread->md.pthread_cond);
  403.         pthread_attr_destroy(&attr);
  404.         _MD_ATOMIC_INCREMENT(&_pr_md_pthreads_failed);
  405.         if (!_PR_IS_NATIVE_THREAD(me))
  406.             _PR_FAST_INTSON(is);
  407.         return PR_FAILURE;
  408.     }
  409. }
  410.  
  411. PR_IMPLEMENT(void)
  412. _MD_InitRunningCPU(struct _PRCPU *cpu)
  413. {
  414.     extern int _pr_md_pipefd[2];
  415.  
  416.     _MD_unix_init_running_cpu(cpu);
  417.     cpu->md.pthread = pthread_self();
  418.     if (_pr_md_pipefd[0] >= 0) {
  419.         _PR_IOQ_MAX_OSFD(cpu) = _pr_md_pipefd[0];
  420.         FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(cpu));
  421.     }
  422. }
  423.  
  424.  
  425. void
  426. _MD_CleanupBeforeExit(void)
  427. {
  428. #if 0
  429.     extern PRInt32    _pr_cpus_exit;
  430.  
  431.     _pr_irix_exit_now = 1;
  432.     if (_pr_numCPU > 1) {
  433.         /*
  434.          * Set a global flag, and wakeup all cpus which will notice the flag
  435.          * and exit.
  436.          */
  437.         _pr_cpus_exit = getpid();
  438.         _MD_Wakeup_CPUs();
  439.         while(_pr_numCPU > 1) {
  440.             _PR_WAIT_SEM(_pr_irix_exit_sem);
  441.             _pr_numCPU--;
  442.         }
  443.     }
  444.     /*
  445.      * cause global threads on the recycle list to exit
  446.      */
  447.      _PR_DEADQ_LOCK;
  448.      if (_PR_NUM_DEADNATIVE != 0) {
  449.     PRThread *thread;
  450.         PRCList *ptr;
  451.  
  452.         ptr = _PR_DEADNATIVEQ.next;
  453.         while( ptr != &_PR_DEADNATIVEQ ) {
  454.             thread = _PR_THREAD_PTR(ptr);
  455.         _MD_CVAR_POST_SEM(thread);
  456.                 ptr = ptr->next;
  457.         } 
  458.      }
  459.      _PR_DEADQ_UNLOCK;
  460.      while(_PR_NUM_DEADNATIVE > 1) {
  461.     _PR_WAIT_SEM(_pr_irix_exit_sem);
  462.     _PR_DEC_DEADNATIVE;
  463.      }
  464. #endif
  465. }
  466.