Back to index

lightning-sunbird  0.9+nobinonly
prcthr.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "primpl.h"
00039 
00040 #if defined(WIN95)
00041 /*
00042 ** Some local variables report warnings on Win95 because the code paths 
00043 ** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
00044 ** The pragma suppresses the warning.
00045 ** 
00046 */
00047 #pragma warning(disable : 4101)
00048 #endif
00049 
00050 
00051 extern PRLock *_pr_sleeplock;  /* allocated and initialized in prinit */
00052 /* 
00053 ** Routines common to both native and user threads.
00054 **
00055 **
00056 ** Clean up a thread object, releasing all of the attached data. Do not
00057 ** free the object itself (it may not have been malloc'd)
00058 */
00059 void _PR_CleanupThread(PRThread *thread)
00060 {
00061     /* Free up per-thread-data */
00062     _PR_DestroyThreadPrivate(thread);
00063 
00064     /* Free any thread dump procs */
00065     if (thread->dumpArg) {
00066         PR_DELETE(thread->dumpArg);
00067     }
00068     thread->dump = 0;
00069 
00070     PR_DELETE(thread->errorString);
00071     thread->errorStringSize = 0;
00072     thread->errorStringLength = 0;
00073     thread->environment = NULL;
00074 }
00075 
00076 PR_IMPLEMENT(PRStatus) PR_Yield()
00077 {
00078     static PRBool warning = PR_TRUE;
00079     if (warning) warning = _PR_Obsolete(
00080         "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)");
00081     return (PR_Sleep(PR_INTERVAL_NO_WAIT));
00082 }
00083 
00084 /*
00085 ** Make the current thread sleep until "timeout" ticks amount of time
00086 ** has expired. If "timeout" is PR_INTERVAL_NO_WAIT then the call is
00087 ** equivalent to a yield. Waiting for an infinite amount of time is
00088 ** allowed in the expectation that another thread will interrupt().
00089 **
00090 ** A single lock is used for all threads calling sleep. Each caller
00091 ** does get its own condition variable since each is expected to have
00092 ** a unique 'timeout'.
00093 */
00094 PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime timeout)
00095 {
00096     PRStatus rv = PR_SUCCESS;
00097 
00098     if (!_pr_initialized) _PR_ImplicitInitialization();
00099 
00100     if (PR_INTERVAL_NO_WAIT == timeout)
00101     {
00102         /*
00103         ** This is a simple yield, nothing more, nothing less.
00104         */
00105         PRIntn is;
00106         PRThread *me = PR_GetCurrentThread();
00107         PRUintn pri = me->priority;
00108         _PRCPU *cpu = _PR_MD_CURRENT_CPU();
00109 
00110         if ( _PR_IS_NATIVE_THREAD(me) ) _PR_MD_YIELD();
00111         else
00112         {
00113             _PR_INTSOFF(is);
00114             _PR_RUNQ_LOCK(cpu);
00115             if (_PR_RUNQREADYMASK(cpu) >> pri) {
00116                 me->cpu = cpu;
00117                 me->state = _PR_RUNNABLE;
00118                 _PR_ADD_RUNQ(me, cpu, pri);
00119                 _PR_RUNQ_UNLOCK(cpu);
00120 
00121                 PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("PR_Yield: yielding"));
00122                 _PR_MD_SWITCH_CONTEXT(me);
00123                 PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("PR_Yield: done"));
00124 
00125                 _PR_FAST_INTSON(is);
00126             }
00127             else
00128             {
00129                 _PR_RUNQ_UNLOCK(cpu);
00130                 _PR_INTSON(is);
00131             }
00132         }
00133     }
00134     else
00135     {
00136         /*
00137         ** This is waiting for some finite period of time.
00138         ** A thread in this state is interruptible (PR_Interrupt()),
00139         ** but the lock and cvar used are local to the implementation
00140         ** and not visible to the caller, therefore not notifiable.
00141         */
00142         PRCondVar *cv;
00143         PRIntervalTime timein;
00144 
00145         timein = PR_IntervalNow();
00146         cv = PR_NewCondVar(_pr_sleeplock);
00147         PR_ASSERT(cv != NULL);
00148         PR_Lock(_pr_sleeplock);
00149         do
00150         {
00151             PRIntervalTime delta = PR_IntervalNow() - timein;
00152             if (delta > timeout) break;
00153             rv = PR_WaitCondVar(cv, timeout - delta);
00154         } while (rv == PR_SUCCESS);
00155         PR_Unlock(_pr_sleeplock);
00156         PR_DestroyCondVar(cv);
00157     }
00158     return rv;
00159 }
00160 
00161 PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thread)
00162 {
00163     return thread->id;
00164 }
00165 
00166 PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread)
00167 {
00168     return (PRThreadPriority) thread->priority;
00169 }
00170 
00171 PR_IMPLEMENT(PRThread *) PR_GetCurrentThread()
00172 {
00173     if (!_pr_initialized) _PR_ImplicitInitialization();
00174     return _PR_MD_CURRENT_THREAD();
00175 }
00176 
00177 /*
00178 ** Set the interrupt flag for a thread. The thread will be unable to
00179 ** block in i/o functions when this happens. Also, any PR_Wait's in
00180 ** progress will be undone. The interrupt remains in force until
00181 ** PR_ClearInterrupt is called.
00182 */
00183 PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thread)
00184 {
00185 #ifdef _PR_GLOBAL_THREADS_ONLY
00186     PRCondVar *victim;
00187 
00188     _PR_THREAD_LOCK(thread);
00189     thread->flags |= _PR_INTERRUPT;
00190     victim = thread->wait.cvar;
00191     _PR_THREAD_UNLOCK(thread);
00192     if ((NULL != victim) && (!(thread->flags & _PR_INTERRUPT_BLOCKED))) {
00193         int haveLock = (victim->lock->owner == _PR_MD_CURRENT_THREAD());
00194 
00195         if (!haveLock) PR_Lock(victim->lock);
00196         PR_NotifyAllCondVar(victim);
00197         if (!haveLock) PR_Unlock(victim->lock);
00198     }
00199     return PR_SUCCESS;
00200 #else  /* ! _PR_GLOBAL_THREADS_ONLY */
00201     PRIntn is;
00202     PRThread *me = _PR_MD_CURRENT_THREAD();
00203 
00204             if (!_PR_IS_NATIVE_THREAD(me))
00205               _PR_INTSOFF(is);
00206 
00207             _PR_THREAD_LOCK(thread);
00208             thread->flags |= _PR_INTERRUPT;
00209         switch (thread->state) {
00210                 case _PR_COND_WAIT:
00211                         /*
00212                          * call is made with thread locked;
00213                          * on return lock is released
00214                          */
00215                                           if (!(thread->flags & _PR_INTERRUPT_BLOCKED))
00216                             _PR_NotifyLockedThread(thread);
00217                         break;
00218                 case _PR_IO_WAIT:
00219                         /*
00220                          * Need to hold the thread lock when calling
00221                          * _PR_Unblock_IO_Wait().  On return lock is
00222                          * released. 
00223                          */
00224 #if defined(XP_UNIX) || defined(WINNT) || defined(WIN16)
00225                                           if (!(thread->flags & _PR_INTERRUPT_BLOCKED))
00226                             _PR_Unblock_IO_Wait(thread);
00227 #else
00228                         _PR_THREAD_UNLOCK(thread);
00229 #endif
00230                         break;
00231                 case _PR_RUNNING:
00232                 case _PR_RUNNABLE:
00233                 case _PR_LOCK_WAIT:
00234                 default:
00235                             _PR_THREAD_UNLOCK(thread);
00236                         break;
00237         }
00238             if (!_PR_IS_NATIVE_THREAD(me))
00239               _PR_INTSON(is);
00240             return PR_SUCCESS;
00241 #endif  /* _PR_GLOBAL_THREADS_ONLY */
00242 }
00243 
00244 /*
00245 ** Clear the interrupt flag for self.
00246 */
00247 PR_IMPLEMENT(void) PR_ClearInterrupt()
00248 {
00249     PRIntn is;
00250     PRThread *me = _PR_MD_CURRENT_THREAD();
00251 
00252         if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
00253     _PR_THREAD_LOCK(me);
00254          me->flags &= ~_PR_INTERRUPT;
00255     _PR_THREAD_UNLOCK(me);
00256         if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
00257 }
00258 
00259 PR_IMPLEMENT(void) PR_BlockInterrupt()
00260 {
00261     PRIntn is;
00262     PRThread *me = _PR_MD_CURRENT_THREAD();
00263 
00264     if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
00265     _PR_THREAD_LOCK(me);
00266     _PR_THREAD_BLOCK_INTERRUPT(me);
00267     _PR_THREAD_UNLOCK(me);
00268     if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
00269 }  /* PR_BlockInterrupt */
00270 
00271 PR_IMPLEMENT(void) PR_UnblockInterrupt()
00272 {
00273     PRIntn is;
00274     PRThread *me = _PR_MD_CURRENT_THREAD();
00275 
00276     if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
00277     _PR_THREAD_LOCK(me);
00278     _PR_THREAD_UNBLOCK_INTERRUPT(me);
00279     _PR_THREAD_UNLOCK(me);
00280     if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
00281 }  /* PR_UnblockInterrupt */
00282 
00283 /*
00284 ** Return the thread stack pointer of the given thread.
00285 */
00286 PR_IMPLEMENT(void *) PR_GetSP(PRThread *thread)
00287 {
00288         return (void *)_PR_MD_GET_SP(thread);
00289 }
00290 
00291 PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thread)
00292 {
00293         return thread->environment;
00294 }
00295 
00296 PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thread, void *env)
00297 {
00298         thread->environment = env;
00299 }
00300 
00301 
00302 PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask)
00303 {
00304 #ifdef HAVE_THREAD_AFFINITY
00305     return _PR_MD_GETTHREADAFFINITYMASK(thread, mask);
00306 #else
00307 
00308 #if defined(XP_MAC)
00309 #pragma unused (thread, mask)
00310 #endif
00311 
00312     return 0;
00313 #endif
00314 }
00315 
00316 PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask )
00317 {
00318 #ifdef HAVE_THREAD_AFFINITY
00319 #ifndef IRIX
00320     return _PR_MD_SETTHREADAFFINITYMASK(thread, mask);
00321 #else
00322        return 0;
00323 #endif
00324 #else
00325 
00326 #if defined(XP_MAC)
00327 #pragma unused (thread, mask)
00328 #endif
00329 
00330     return 0;
00331 #endif
00332 }
00333 
00334 /* This call is thread unsafe if another thread is calling SetConcurrency()
00335  */
00336 PR_IMPLEMENT(PRInt32) PR_SetCPUAffinityMask(PRUint32 mask)
00337 {
00338 #ifdef HAVE_THREAD_AFFINITY
00339     PRCList *qp;
00340     extern PRUint32 _pr_cpu_affinity_mask;
00341 
00342     if (!_pr_initialized) _PR_ImplicitInitialization();
00343 
00344     _pr_cpu_affinity_mask = mask;
00345 
00346     qp = _PR_CPUQ().next;
00347     while(qp != &_PR_CPUQ()) {
00348         _PRCPU *cpu;
00349 
00350         cpu = _PR_CPU_PTR(qp);
00351         PR_SetThreadAffinityMask(cpu->thread, mask);
00352 
00353         qp = qp->next;
00354     }
00355 #endif
00356 
00357 #if defined(XP_MAC)
00358 #pragma unused (mask)
00359 #endif
00360 
00361     return 0;
00362 }
00363 
00364 PRUint32 _pr_recycleThreads = 0;
00365 PR_IMPLEMENT(void) PR_SetThreadRecycleMode(PRUint32 count)
00366 {
00367     _pr_recycleThreads = count;
00368 }
00369 
00370 PR_IMPLEMENT(PRThread*) PR_CreateThreadGCAble(PRThreadType type,
00371                                      void (*start)(void *arg),
00372                                      void *arg,
00373                                      PRThreadPriority priority,
00374                                      PRThreadScope scope,
00375                                      PRThreadState state,
00376                                      PRUint32 stackSize)
00377 {
00378     return _PR_CreateThread(type, start, arg, priority, scope, state, 
00379                             stackSize, _PR_GCABLE_THREAD);
00380 }
00381 
00382 #ifdef SOLARIS
00383 PR_IMPLEMENT(PRThread*) PR_CreateThreadBound(PRThreadType type,
00384                                      void (*start)(void *arg),
00385                                      void *arg,
00386                                      PRUintn priority,
00387                                      PRThreadScope scope,
00388                                      PRThreadState state,
00389                                      PRUint32 stackSize)
00390 {
00391     return _PR_CreateThread(type, start, arg, priority, scope, state, 
00392                             stackSize, _PR_BOUND_THREAD);
00393 }
00394 #endif
00395 
00396 
00397 PR_IMPLEMENT(PRThread*) PR_AttachThreadGCAble(
00398     PRThreadType type, PRThreadPriority priority, PRThreadStack *stack)
00399 {
00400 #ifdef XP_MAC
00401 #pragma unused (type, priority, stack)
00402 #endif
00403     /* $$$$ not sure how to finese this one */
00404     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
00405     return NULL;
00406 }
00407 
00408 PR_IMPLEMENT(void) PR_SetThreadGCAble()
00409 {
00410     if (!_pr_initialized) _PR_ImplicitInitialization();
00411     PR_Lock(_pr_activeLock);
00412         _PR_MD_CURRENT_THREAD()->flags |= _PR_GCABLE_THREAD;
00413         PR_Unlock(_pr_activeLock);        
00414 }
00415 
00416 PR_IMPLEMENT(void) PR_ClearThreadGCAble()
00417 {
00418     if (!_pr_initialized) _PR_ImplicitInitialization();
00419     PR_Lock(_pr_activeLock);
00420         _PR_MD_CURRENT_THREAD()->flags &= (~_PR_GCABLE_THREAD);
00421         PR_Unlock(_pr_activeLock);
00422 }
00423 
00424 PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thread)
00425 {
00426 #ifdef XP_MAC
00427 #pragma unused( thread )
00428 #endif
00429     if (!_pr_initialized) _PR_ImplicitInitialization();
00430 
00431     if (_PR_IS_NATIVE_THREAD(thread)) {
00432        return (thread->flags & _PR_BOUND_THREAD) ? PR_GLOBAL_BOUND_THREAD :
00433                                                                       PR_GLOBAL_THREAD;
00434     } else
00435         return PR_LOCAL_THREAD;
00436 }
00437 
00438 PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thread)
00439 {
00440     return (thread->flags & _PR_SYSTEM) ? PR_SYSTEM_THREAD : PR_USER_THREAD;
00441 }
00442 
00443 PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thread)
00444 {
00445     return (NULL == thread->term) ? PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD;
00446 }  /* PR_GetThreadState */