home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / threads / prcthr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  11.9 KB  |  415 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.  
  21. /* 
  22. ** Routines common to both native and user threads.
  23. **
  24. **
  25. ** Clean up a thread object, releasing all of the attached data. Do not
  26. ** free the object itself (it may not have been malloc'd)
  27. */
  28. void _PR_CleanupThread(PRThread *thread)
  29. {
  30.     PRUintn i;
  31.     void **ptd;
  32.     _PRPerThreadExit *pte;
  33.     PRThreadPrivateDTOR *destructor;
  34.  
  35.     /* Free up per-thread-data */
  36.     ptd = thread->privateData;
  37.     destructor = _pr_tpd_destructors;
  38.     for (i = 0; i < thread->tpdLength; i++, ptd++, destructor++)
  39.     {
  40.             if (*destructor && *ptd) (**destructor)(*ptd);
  41.             *ptd = NULL;
  42.     }
  43.  
  44.     /* Free any thread dump procs */
  45.     if (thread->dumpArg) {
  46.         PR_DELETE(thread->dumpArg);
  47.     }
  48.     thread->dump = 0;
  49.  
  50.     /* Invoke per-thread exit functions */
  51.     pte = &thread->ptes[0];
  52.     for (i = 0; i < thread->numExits; i++, pte++) {
  53.         if (pte->func) {
  54.             (*pte->func)(pte->arg);
  55.             pte->func = 0;
  56.         }
  57.     }
  58.     if (thread->ptes) {
  59.         PR_DELETE(thread->ptes);
  60.         thread->numExits = 0;
  61.     }
  62.     PR_ASSERT(thread->numExits == 0);
  63.     PR_DELETE(thread->errorString);
  64.     thread->errorStringSize = 0;
  65.     thread->environment = NULL;
  66. }
  67.  
  68. PR_IMPLEMENT(PRStatus) PR_Yield()
  69. {
  70.     static PRBool warning = PR_TRUE;
  71.     if (warning) warning = _PR_Obsolete(
  72.         "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)");
  73.     return (PR_Sleep(PR_INTERVAL_NO_WAIT));
  74. }
  75.  
  76. /*
  77. ** Make the current thread sleep until "timeout" ticks amount of time
  78. ** has expired. If "timeout" is PR_INTERVAL_NO_WAIT then the call is
  79. ** equivalent to a yield. Waiting for an infinite amount of time is
  80. ** allowed in the expectation that another thread will interrupt().
  81. **
  82. ** A single lock is used for all threads calling sleep. Each caller
  83. ** does get its own condition variable since each is expected to have
  84. ** a unique 'timeout'.
  85. */
  86. PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime timeout)
  87. {
  88.     static PRLock *ml = NULL;
  89.     PRStatus rv = PR_SUCCESS;
  90.     if (PR_INTERVAL_NO_WAIT == timeout)
  91.     {
  92.         /*
  93.         ** This is a simple yield, nothing more, nothing less.
  94.         */
  95.         PRIntn is;
  96.         PRThread *me = PR_GetCurrentThread();
  97.         PRUintn pri = me->priority;
  98.         _PRCPU *cpu = _PR_MD_CURRENT_CPU();
  99.  
  100.         if ( _PR_IS_NATIVE_THREAD(me) ) _PR_MD_YIELD();
  101.         else
  102.         {
  103.             _PR_INTSOFF(is);
  104.             _PR_RUNQ_LOCK(cpu);
  105.             if (_PR_RUNQREADYMASK(cpu) >> pri) {
  106.                 me->cpu = cpu;
  107.                 me->state = _PR_RUNNABLE;
  108.                 _PR_ADD_RUNQ(me, cpu, pri);
  109.                 _PR_RUNQ_UNLOCK(cpu);
  110.  
  111.                 PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("PR_Yield: yielding"));
  112.                 _PR_MD_SWITCH_CONTEXT(me);
  113.                 PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("PR_Yield: done"));
  114.  
  115.                 _PR_FAST_INTSON(is);
  116.             }
  117.             else
  118.             {
  119.                 _PR_RUNQ_UNLOCK(cpu);
  120.                 _PR_INTSON(is);
  121.             }
  122.         }
  123.     }
  124.     else
  125.     {
  126.         /*
  127.         ** This is waiting for some finite period of time.
  128.         ** A thread in this state is interruptible (PR_Interrupt()),
  129.         ** but the lock and cvar used are local to the implementation
  130.         ** and not visible to the caller, therefore not notifiable.
  131.         */
  132.         if (ml == NULL) ml = PR_NewLock();
  133.  
  134.         if (ml == NULL) rv = PR_FAILURE;
  135.         else
  136.         {
  137.             PRCondVar *cv = PR_NewCondVar(ml);
  138.             PRIntervalTime timein = PR_IntervalNow();
  139.  
  140.             PR_Lock(ml);
  141.             while (rv == PR_SUCCESS)
  142.             {
  143.                 PRIntervalTime delta = PR_IntervalNow() - timein;
  144.                 if (delta > timeout) break;
  145.                 rv = PR_WaitCondVar(cv, timeout - delta);
  146.             }
  147.             PR_Unlock(ml);
  148.  
  149.             PR_DestroyCondVar(cv);
  150.         }
  151.     }
  152.         return rv;
  153. }
  154.  
  155. PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thread)
  156. {
  157.     return thread->id;
  158. }
  159.  
  160. PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread)
  161. {
  162.     return (PRThreadPriority) thread->priority;
  163. }
  164.  
  165. PR_IMPLEMENT(PRThread *) PR_GetCurrentThread()
  166. {
  167.     if (!_pr_initialized) _PR_ImplicitInitialization();
  168.     return _PR_MD_CURRENT_THREAD();
  169. }
  170.  
  171. /*
  172. ** Set the interrupt flag for a thread. The thread will be unable to
  173. ** block in i/o functions when this happens. Also, any PR_Wait's in
  174. ** progress will be undone. The interrupt remains in force until
  175. ** PR_ClearInterrupt is called.
  176. */
  177. PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thread)
  178. {
  179. #ifdef _PR_GLOBAL_THREADS_ONLY
  180.     PRCondVar *victim;
  181.  
  182.     _PR_THREAD_LOCK(thread);
  183.     thread->flags |= _PR_INTERRUPT;
  184.     victim = thread->wait.cvar;
  185.     _PR_THREAD_UNLOCK(thread);
  186.     if (NULL != victim) {
  187.         int haveLock = (victim->lock->owner == _PR_MD_CURRENT_THREAD());
  188.  
  189.         if (!haveLock) PR_Lock(victim->lock);
  190.         PR_NotifyAllCondVar(victim);
  191.         if (!haveLock) PR_Unlock(victim->lock);
  192.     }
  193.     return PR_SUCCESS;
  194. #else  /* ! _PR_GLOBAL_THREADS_ONLY */
  195.     PRIntn is;
  196.     PRThread *me = _PR_MD_CURRENT_THREAD();
  197.  
  198.             if (!_PR_IS_NATIVE_THREAD(me))
  199.                 _PR_INTSOFF(is);
  200.  
  201.             _PR_THREAD_LOCK(thread);
  202.             thread->flags |= _PR_INTERRUPT;
  203.         switch (thread->state) {
  204.                 case _PR_COND_WAIT:
  205.                         /*
  206.                          * call is made with thread locked;
  207.                          * on return lock is released
  208.                          */
  209.                         _PR_NotifyLockedThread(thread);
  210.                         break;
  211.                 case _PR_IO_WAIT:
  212.                         /*
  213.                          * Need to hold the thread lock when calling
  214.                          * _PR_Unblock_IO_Wait().  On return lock is
  215.                          * released. 
  216.                          */
  217. #if defined(XP_UNIX) || defined(WINNT) || defined(WIN16)
  218.                         _PR_Unblock_IO_Wait(thread);
  219. #else
  220.                         _PR_THREAD_UNLOCK(thread);
  221. #endif
  222.                         break;
  223.                 case _PR_RUNNING:
  224.                 case _PR_RUNNABLE:
  225.                 case _PR_LOCK_WAIT:
  226.                 default:
  227.                             _PR_THREAD_UNLOCK(thread);
  228.                         break;
  229.         }
  230.             if (!_PR_IS_NATIVE_THREAD(me))
  231.                 _PR_INTSON(is);
  232.             return PR_SUCCESS;
  233. #endif  /* _PR_GLOBAL_THREADS_ONLY */
  234. }
  235.  
  236. /*
  237. ** Clear the interrupt flag for self.
  238. */
  239. PR_IMPLEMENT(void) PR_ClearInterrupt()
  240. {
  241.     PRIntn is;
  242.     PRThread *me = _PR_MD_CURRENT_THREAD();
  243.  
  244.         if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
  245.     _PR_THREAD_LOCK(me);
  246.          me->flags &= ~_PR_INTERRUPT;
  247.     _PR_THREAD_UNLOCK(me);
  248.         if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
  249. }
  250.  
  251. /*
  252. ** Return the thread stack pointer of the given thread.
  253. */
  254. PR_IMPLEMENT(void *) PR_GetSP(PRThread *thread)
  255. {
  256.         return (void *)_PR_MD_GET_SP(thread);
  257. }
  258.  
  259. PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thread)
  260. {
  261.         return thread->environment;
  262. }
  263.  
  264. PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thread, void *env)
  265. {
  266.         thread->environment = env;
  267. }
  268.  
  269.  
  270. PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask)
  271. {
  272. #ifdef HAVE_THREAD_AFFINITY
  273. /*
  274.  * Irix ignores the thread argument
  275.  */
  276. #ifndef IRIX
  277.     if (_PR_IS_NATIVE_THREAD(thread)) 
  278.         return _PR_MD_GETTHREADAFFINITYMASK(thread, mask);
  279.     else
  280.         return 0;
  281. #else
  282.         return _PR_MD_GETTHREADAFFINITYMASK(thread, mask);
  283. #endif        /* !IRIX */
  284. #else
  285.  
  286. #if defined(XP_MAC)
  287. #pragma unused (thread, mask)
  288. #endif
  289.  
  290.     return 0;
  291. #endif
  292. }
  293.  
  294. PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask )
  295. {
  296. #ifdef HAVE_THREAD_AFFINITY
  297. #ifndef IRIX
  298.     return _PR_MD_SETTHREADAFFINITYMASK(thread, mask);
  299. #endif
  300. #else
  301.  
  302. #if defined(XP_MAC)
  303. #pragma unused (thread, mask)
  304. #endif
  305.  
  306.     return 0;
  307. #endif
  308. }
  309.  
  310. /* This call is thread unsafe if another thread is calling SetConcurrency()
  311.  */
  312. PR_IMPLEMENT(PRInt32) PR_SetCPUAffinityMask(PRUint32 mask)
  313. {
  314. #ifdef HAVE_THREAD_AFFINITY
  315.     PRCList *qp;
  316.     extern PRUint32 _pr_cpu_affinity_mask;
  317.  
  318.     if (!_pr_initialized) _PR_ImplicitInitialization();
  319.  
  320.     _pr_cpu_affinity_mask = mask;
  321.  
  322.     qp = _PR_CPUQ().next;
  323.     while(qp != &_PR_CPUQ()) {
  324.         _PRCPU *cpu;
  325.  
  326.         cpu = _PR_CPU_PTR(qp);
  327.         PR_SetThreadAffinityMask(cpu->thread, mask);
  328.  
  329.         qp = qp->next;
  330.     }
  331. #endif
  332.  
  333. #if defined(XP_MAC)
  334. #pragma unused (mask)
  335. #endif
  336.  
  337.     return 0;
  338. }
  339.  
  340. PRUint32 _pr_recycleThreads = 0;
  341. PR_IMPLEMENT(void) PR_SetThreadRecycleMode(PRUint32 count)
  342. {
  343.     _pr_recycleThreads = count;
  344. }
  345.  
  346. PR_IMPLEMENT(PRThread*) PR_CreateThreadGCAble(PRThreadType type,
  347.                                      void (*start)(void *arg),
  348.                                      void *arg,
  349.                                      PRThreadPriority priority,
  350.                                      PRThreadScope scope,
  351.                                      PRThreadState state,
  352.                                      PRUint32 stackSize)
  353. {
  354.     return _PR_CreateThread(type, start, arg, priority, scope, state, 
  355.                             stackSize, _PR_GCABLE_THREAD);
  356. }
  357.  
  358. #ifdef SOLARIS
  359. PR_IMPLEMENT(PRThread*) PR_CreateThreadBound(PRThreadType type,
  360.                                      void (*start)(void *arg),
  361.                                      void *arg,
  362.                                      PRUintn priority,
  363.                                      PRThreadScope scope,
  364.                                      PRThreadState state,
  365.                                      PRUint32 stackSize)
  366. {
  367.     return _PR_CreateThread(type, start, arg, priority, scope, state, 
  368.                             stackSize, _PR_BOUND_THREAD);
  369. }
  370. #endif
  371.  
  372.  
  373. PR_IMPLEMENT(PRThread*) PR_AttachThreadGCAble(
  374.     PRThreadType type, PRThreadPriority priority, PRThreadStack *stack)
  375. {
  376.     if (!_pr_initialized) _PR_ImplicitInitialization();
  377.     return _PRI_AttachThread(type, priority, stack, _PR_GCABLE_THREAD);
  378. }
  379.  
  380. PR_IMPLEMENT(void) PR_SetThreadGCAble()
  381. {
  382.     if (!_pr_initialized) _PR_ImplicitInitialization();
  383.     PR_Lock(_pr_activeLock);
  384.         _PR_MD_CURRENT_THREAD()->flags |= _PR_GCABLE_THREAD;
  385.         PR_Unlock(_pr_activeLock);        
  386. }
  387.  
  388. PR_IMPLEMENT(void) PR_ClearThreadGCAble()
  389. {
  390.     if (!_pr_initialized) _PR_ImplicitInitialization();
  391.     PR_Lock(_pr_activeLock);
  392.         _PR_MD_CURRENT_THREAD()->flags &= (~_PR_GCABLE_THREAD);
  393.         PR_Unlock(_pr_activeLock);
  394. }
  395.  
  396. PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thread)
  397. {
  398.     if (!_pr_initialized) _PR_ImplicitInitialization();
  399.  
  400.     if (_PR_IS_NATIVE_THREAD(thread))
  401.         return PR_GLOBAL_THREAD;
  402.     else
  403.         return PR_LOCAL_THREAD;
  404. }
  405.  
  406. PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thread)
  407. {
  408.     return (thread->flags & _PR_SYSTEM) ? PR_SYSTEM_THREAD : PR_USER_THREAD;
  409. }
  410.  
  411. PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thread)
  412. {
  413.     return (NULL == thread->term) ? PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD;
  414. }  /* PR_GetThreadState */
  415.