nsprpub/pr/src/threads/combined/prucv.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/src/threads/combined/prucv.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,655 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +
    1.10 +#include "primpl.h"
    1.11 +#include "prinrval.h"
    1.12 +#include "prtypes.h"
    1.13 +
    1.14 +#if defined(WIN95)
    1.15 +/*
    1.16 +** Some local variables report warnings on Win95 because the code paths 
    1.17 +** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
    1.18 +** The pragma suppresses the warning.
    1.19 +** 
    1.20 +*/
    1.21 +#pragma warning(disable : 4101)
    1.22 +#endif
    1.23 +
    1.24 +
    1.25 +/*
    1.26 +** Notify one thread that it has finished waiting on a condition variable
    1.27 +** Caller must hold the _PR_CVAR_LOCK(cv)
    1.28 +*/
    1.29 +PRBool _PR_NotifyThread (PRThread *thread, PRThread *me)
    1.30 +{
    1.31 +    PRBool rv;
    1.32 +
    1.33 +    PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);
    1.34 +
    1.35 +    _PR_THREAD_LOCK(thread);
    1.36 +    PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
    1.37 +    if ( !_PR_IS_NATIVE_THREAD(thread) ) {
    1.38 +        if (thread->wait.cvar != NULL) {
    1.39 +            thread->wait.cvar = NULL;
    1.40 +
    1.41 +            _PR_SLEEPQ_LOCK(thread->cpu);
    1.42 +            /* The notify and timeout can collide; in which case both may
    1.43 +             * attempt to delete from the sleepQ; only let one do it.
    1.44 +             */
    1.45 +            if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ))
    1.46 +                _PR_DEL_SLEEPQ(thread, PR_TRUE);
    1.47 +            _PR_SLEEPQ_UNLOCK(thread->cpu);
    1.48 +
    1.49 +	    if (thread->flags & _PR_SUSPENDING) {
    1.50 +		/*
    1.51 +		 * set thread state to SUSPENDED; a Resume operation
    1.52 +		 * on the thread will move it to the runQ
    1.53 +		 */
    1.54 +            	thread->state = _PR_SUSPENDED;
    1.55 +		_PR_MISCQ_LOCK(thread->cpu);
    1.56 +		_PR_ADD_SUSPENDQ(thread, thread->cpu);
    1.57 +		_PR_MISCQ_UNLOCK(thread->cpu);
    1.58 +            	_PR_THREAD_UNLOCK(thread);
    1.59 +	    } else {
    1.60 +            	/* Make thread runnable */
    1.61 +            	thread->state = _PR_RUNNABLE;
    1.62 +            	_PR_THREAD_UNLOCK(thread);
    1.63 +
    1.64 +                _PR_AddThreadToRunQ(me, thread);
    1.65 +                _PR_MD_WAKEUP_WAITER(thread);
    1.66 +            }
    1.67 +
    1.68 +            rv = PR_TRUE;
    1.69 +        } else {
    1.70 +            /* Thread has already been notified */
    1.71 +            _PR_THREAD_UNLOCK(thread);
    1.72 +            rv = PR_FALSE;
    1.73 +        }
    1.74 +    } else { /* If the thread is a native thread */
    1.75 +        if (thread->wait.cvar) {
    1.76 +            thread->wait.cvar = NULL;
    1.77 +
    1.78 +	    if (thread->flags & _PR_SUSPENDING) {
    1.79 +		/*
    1.80 +		 * set thread state to SUSPENDED; a Resume operation
    1.81 +		 * on the thread will enable the thread to run
    1.82 +		 */
    1.83 +            	thread->state = _PR_SUSPENDED;
    1.84 +	     } else
    1.85 +            	thread->state = _PR_RUNNING;
    1.86 +            _PR_THREAD_UNLOCK(thread);
    1.87 +            _PR_MD_WAKEUP_WAITER(thread);
    1.88 +            rv = PR_TRUE;
    1.89 +        } else {
    1.90 +            _PR_THREAD_UNLOCK(thread);
    1.91 +            rv = PR_FALSE;
    1.92 +        }    
    1.93 +    }    
    1.94 +
    1.95 +    return rv;
    1.96 +}
    1.97 +
    1.98 +/*
    1.99 + * Notify thread waiting on cvar; called when thread is interrupted
   1.100 + * 	The thread lock is held on entry and released before return
   1.101 + */
   1.102 +void _PR_NotifyLockedThread (PRThread *thread)
   1.103 +{
   1.104 +    PRThread *me = _PR_MD_CURRENT_THREAD();
   1.105 +    PRCondVar *cvar;
   1.106 +    PRThreadPriority pri;
   1.107 +
   1.108 +    if ( !_PR_IS_NATIVE_THREAD(me))
   1.109 +    	PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);
   1.110 +
   1.111 +    cvar = thread->wait.cvar;
   1.112 +    thread->wait.cvar = NULL;
   1.113 +    _PR_THREAD_UNLOCK(thread);
   1.114 +
   1.115 +    _PR_CVAR_LOCK(cvar);
   1.116 +    _PR_THREAD_LOCK(thread);
   1.117 +
   1.118 +    if (!_PR_IS_NATIVE_THREAD(thread)) {
   1.119 +            _PR_SLEEPQ_LOCK(thread->cpu);
   1.120 +            /* The notify and timeout can collide; in which case both may
   1.121 +             * attempt to delete from the sleepQ; only let one do it.
   1.122 +             */
   1.123 +            if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ))
   1.124 +                _PR_DEL_SLEEPQ(thread, PR_TRUE);
   1.125 +            _PR_SLEEPQ_UNLOCK(thread->cpu);
   1.126 +
   1.127 +	    /* Make thread runnable */
   1.128 +	    pri = thread->priority;
   1.129 +	    thread->state = _PR_RUNNABLE;
   1.130 +
   1.131 +	    PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
   1.132 +
   1.133 +            _PR_AddThreadToRunQ(me, thread);
   1.134 +            _PR_THREAD_UNLOCK(thread);
   1.135 +
   1.136 +            _PR_MD_WAKEUP_WAITER(thread);
   1.137 +    } else {
   1.138 +	    if (thread->flags & _PR_SUSPENDING) {
   1.139 +		/*
   1.140 +		 * set thread state to SUSPENDED; a Resume operation
   1.141 +		 * on the thread will enable the thread to run
   1.142 +		 */
   1.143 +            	thread->state = _PR_SUSPENDED;
   1.144 +	     } else
   1.145 +            	thread->state = _PR_RUNNING;
   1.146 +            _PR_THREAD_UNLOCK(thread);
   1.147 +            _PR_MD_WAKEUP_WAITER(thread);
   1.148 +    }    
   1.149 +
   1.150 +    _PR_CVAR_UNLOCK(cvar);
   1.151 +    return;
   1.152 +}
   1.153 +
   1.154 +/*
   1.155 +** Make the given thread wait for the given condition variable
   1.156 +*/
   1.157 +PRStatus _PR_WaitCondVar(
   1.158 +    PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout)
   1.159 +{
   1.160 +    PRIntn is;
   1.161 +    PRStatus rv = PR_SUCCESS;
   1.162 +
   1.163 +    PR_ASSERT(thread == _PR_MD_CURRENT_THREAD());
   1.164 +    PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
   1.165 +
   1.166 +#ifdef _PR_GLOBAL_THREADS_ONLY
   1.167 +    if (_PR_PENDING_INTERRUPT(thread)) {
   1.168 +        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1.169 +        thread->flags &= ~_PR_INTERRUPT;
   1.170 +        return PR_FAILURE;
   1.171 +    }
   1.172 +
   1.173 +    thread->wait.cvar = cvar;
   1.174 +    lock->owner = NULL;
   1.175 +    _PR_MD_WAIT_CV(&cvar->md,&lock->ilock, timeout);
   1.176 +    thread->wait.cvar = NULL;
   1.177 +    lock->owner = thread;
   1.178 +    if (_PR_PENDING_INTERRUPT(thread)) {
   1.179 +        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1.180 +        thread->flags &= ~_PR_INTERRUPT;
   1.181 +        return PR_FAILURE;
   1.182 +    }
   1.183 +
   1.184 +    return PR_SUCCESS;
   1.185 +#else  /* _PR_GLOBAL_THREADS_ONLY */
   1.186 +
   1.187 +    if ( !_PR_IS_NATIVE_THREAD(thread))
   1.188 +    	_PR_INTSOFF(is);
   1.189 +
   1.190 +    _PR_CVAR_LOCK(cvar);
   1.191 +    _PR_THREAD_LOCK(thread);
   1.192 +
   1.193 +    if (_PR_PENDING_INTERRUPT(thread)) {
   1.194 +        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1.195 +        thread->flags &= ~_PR_INTERRUPT;
   1.196 +    	_PR_CVAR_UNLOCK(cvar);
   1.197 +    	_PR_THREAD_UNLOCK(thread);
   1.198 +    	if ( !_PR_IS_NATIVE_THREAD(thread))
   1.199 +    		_PR_INTSON(is);
   1.200 +        return PR_FAILURE;
   1.201 +    }
   1.202 +
   1.203 +    thread->state = _PR_COND_WAIT;
   1.204 +    thread->wait.cvar = cvar;
   1.205 +
   1.206 +    /*
   1.207 +    ** Put the caller thread on the condition variable's wait Q
   1.208 +    */
   1.209 +    PR_APPEND_LINK(&thread->waitQLinks, &cvar->condQ);
   1.210 +
   1.211 +    /* Note- for global scope threads, we don't put them on the
   1.212 +     *       global sleepQ, so each global thread must put itself
   1.213 +     *       to sleep only for the time it wants to.
   1.214 +     */
   1.215 +    if ( !_PR_IS_NATIVE_THREAD(thread) ) {
   1.216 +        _PR_SLEEPQ_LOCK(thread->cpu);
   1.217 +        _PR_ADD_SLEEPQ(thread, timeout);
   1.218 +        _PR_SLEEPQ_UNLOCK(thread->cpu);
   1.219 +    }
   1.220 +    _PR_CVAR_UNLOCK(cvar);
   1.221 +    _PR_THREAD_UNLOCK(thread);
   1.222 +   
   1.223 +    /* 
   1.224 +    ** Release lock protecting the condition variable and thereby giving time 
   1.225 +    ** to the next thread which can potentially notify on the condition variable
   1.226 +    */
   1.227 +    PR_Unlock(lock);
   1.228 +
   1.229 +    PR_LOG(_pr_cvar_lm, PR_LOG_MIN,
   1.230 +	   ("PR_Wait: cvar=%p waiting for %d", cvar, timeout));
   1.231 +
   1.232 +    rv = _PR_MD_WAIT(thread, timeout);
   1.233 +
   1.234 +    _PR_CVAR_LOCK(cvar);
   1.235 +    PR_REMOVE_LINK(&thread->waitQLinks);
   1.236 +    _PR_CVAR_UNLOCK(cvar);
   1.237 +
   1.238 +    PR_LOG(_pr_cvar_lm, PR_LOG_MIN,
   1.239 +	   ("PR_Wait: cvar=%p done waiting", cvar));
   1.240 +
   1.241 +    if ( !_PR_IS_NATIVE_THREAD(thread))
   1.242 +    	_PR_INTSON(is);
   1.243 +
   1.244 +    /* Acquire lock again that we had just relinquished */
   1.245 +    PR_Lock(lock);
   1.246 +
   1.247 +    if (_PR_PENDING_INTERRUPT(thread)) {
   1.248 +        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1.249 +        thread->flags &= ~_PR_INTERRUPT;
   1.250 +        return PR_FAILURE;
   1.251 +    }
   1.252 +
   1.253 +    return rv;
   1.254 +#endif  /* _PR_GLOBAL_THREADS_ONLY */
   1.255 +}
   1.256 +
   1.257 +void _PR_NotifyCondVar(PRCondVar *cvar, PRThread *me)
   1.258 +{
   1.259 +#ifdef _PR_GLOBAL_THREADS_ONLY
   1.260 +    _PR_MD_NOTIFY_CV(&cvar->md, &cvar->lock->ilock);
   1.261 +#else  /* _PR_GLOBAL_THREADS_ONLY */
   1.262 +
   1.263 +    PRCList *q;
   1.264 +    PRIntn is;
   1.265 +
   1.266 +    if ( !_PR_IS_NATIVE_THREAD(me))
   1.267 +    	_PR_INTSOFF(is);
   1.268 +    PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);
   1.269 +
   1.270 +    _PR_CVAR_LOCK(cvar);
   1.271 +    q = cvar->condQ.next;
   1.272 +    while (q != &cvar->condQ) {
   1.273 +        PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("_PR_NotifyCondVar: cvar=%p", cvar));
   1.274 +        if (_PR_THREAD_CONDQ_PTR(q)->wait.cvar)  {
   1.275 +            if (_PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me) == PR_TRUE)
   1.276 +                break;
   1.277 +        }
   1.278 +        q = q->next;
   1.279 +    }
   1.280 +    _PR_CVAR_UNLOCK(cvar);
   1.281 +
   1.282 +    if ( !_PR_IS_NATIVE_THREAD(me))
   1.283 +    	_PR_INTSON(is);
   1.284 +
   1.285 +#endif  /* _PR_GLOBAL_THREADS_ONLY */
   1.286 +}
   1.287 +
   1.288 +/*
   1.289 +** Cndition variable debugging log info.
   1.290 +*/
   1.291 +PRUint32 _PR_CondVarToString(PRCondVar *cvar, char *buf, PRUint32 buflen)
   1.292 +{
   1.293 +    PRUint32 nb;
   1.294 +
   1.295 +    if (cvar->lock->owner) {
   1.296 +	nb = PR_snprintf(buf, buflen, "[%p] owner=%ld[%p]",
   1.297 +			 cvar, cvar->lock->owner->id, cvar->lock->owner);
   1.298 +    } else {
   1.299 +	nb = PR_snprintf(buf, buflen, "[%p]", cvar);
   1.300 +    }
   1.301 +    return nb;
   1.302 +}
   1.303 +
   1.304 +/*
   1.305 +** Expire condition variable waits that are ready to expire. "now" is the current
   1.306 +** time.
   1.307 +*/
   1.308 +void _PR_ClockInterrupt(void)
   1.309 +{
   1.310 +    PRThread *thread, *me = _PR_MD_CURRENT_THREAD();
   1.311 +    _PRCPU *cpu = me->cpu;
   1.312 +    PRIntervalTime elapsed, now;
   1.313 + 
   1.314 +    PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);
   1.315 +    /* Figure out how much time elapsed since the last clock tick */
   1.316 +    now = PR_IntervalNow();
   1.317 +    elapsed = now - cpu->last_clock;
   1.318 +    cpu->last_clock = now;
   1.319 +
   1.320 +    PR_LOG(_pr_clock_lm, PR_LOG_MAX,
   1.321 +	   ("ExpireWaits: elapsed=%lld usec", elapsed));
   1.322 +
   1.323 +    while(1) {
   1.324 +        _PR_SLEEPQ_LOCK(cpu);
   1.325 +        if (_PR_SLEEPQ(cpu).next == &_PR_SLEEPQ(cpu)) {
   1.326 +            _PR_SLEEPQ_UNLOCK(cpu);
   1.327 +            break;
   1.328 +        }
   1.329 +
   1.330 +        thread = _PR_THREAD_PTR(_PR_SLEEPQ(cpu).next);
   1.331 +        PR_ASSERT(thread->cpu == cpu);
   1.332 +
   1.333 +        if (elapsed < thread->sleep) {
   1.334 +            thread->sleep -= elapsed;
   1.335 +            _PR_SLEEPQMAX(thread->cpu) -= elapsed;
   1.336 +            _PR_SLEEPQ_UNLOCK(cpu);
   1.337 +            break;
   1.338 +        }
   1.339 +        _PR_SLEEPQ_UNLOCK(cpu);
   1.340 +
   1.341 +        PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));
   1.342 +
   1.343 +        _PR_THREAD_LOCK(thread);
   1.344 +
   1.345 +        if (thread->cpu != cpu) {
   1.346 +            /*
   1.347 +            ** The thread was switched to another CPU
   1.348 +            ** between the time we unlocked the sleep
   1.349 +            ** queue and the time we acquired the thread
   1.350 +            ** lock, so it is none of our business now.
   1.351 +            */
   1.352 +            _PR_THREAD_UNLOCK(thread);
   1.353 +            continue;
   1.354 +        }
   1.355 +
   1.356 +        /*
   1.357 +        ** Consume this sleeper's amount of elapsed time from the elapsed
   1.358 +        ** time value. The next remaining piece of elapsed time will be
   1.359 +        ** available for the next sleeping thread's timer.
   1.360 +        */
   1.361 +        _PR_SLEEPQ_LOCK(cpu);
   1.362 +        PR_ASSERT(!(thread->flags & _PR_ON_PAUSEQ));
   1.363 +        if (thread->flags & _PR_ON_SLEEPQ) {
   1.364 +            _PR_DEL_SLEEPQ(thread, PR_FALSE);
   1.365 +            elapsed -= thread->sleep;
   1.366 +            _PR_SLEEPQ_UNLOCK(cpu);
   1.367 +        } else {
   1.368 +            /* Thread was already handled; Go get another one */
   1.369 +            _PR_SLEEPQ_UNLOCK(cpu);
   1.370 +            _PR_THREAD_UNLOCK(thread);
   1.371 +            continue;
   1.372 +        }
   1.373 +
   1.374 +        /* Notify the thread waiting on the condition variable */
   1.375 +        if (thread->flags & _PR_SUSPENDING) {
   1.376 +		PR_ASSERT((thread->state == _PR_IO_WAIT) ||
   1.377 +				(thread->state == _PR_COND_WAIT));
   1.378 +            /*
   1.379 +            ** Thread is suspended and its condition timeout
   1.380 +            ** expired. Transfer thread from sleepQ to suspendQ.
   1.381 +            */
   1.382 +            thread->wait.cvar = NULL;
   1.383 +            _PR_MISCQ_LOCK(cpu);
   1.384 +            thread->state = _PR_SUSPENDED;
   1.385 +            _PR_ADD_SUSPENDQ(thread, cpu);
   1.386 +            _PR_MISCQ_UNLOCK(cpu);
   1.387 +        } else {
   1.388 +            if (thread->wait.cvar) {
   1.389 +                PRThreadPriority pri;
   1.390 +
   1.391 +                /* Do work very similar to what _PR_NotifyThread does */
   1.392 +                PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) );
   1.393 +
   1.394 +                /* Make thread runnable */
   1.395 +                pri = thread->priority;
   1.396 +                thread->state = _PR_RUNNABLE;
   1.397 +                PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
   1.398 +
   1.399 +                PR_ASSERT(thread->cpu == cpu);
   1.400 +                _PR_RUNQ_LOCK(cpu);
   1.401 +                _PR_ADD_RUNQ(thread, cpu, pri);
   1.402 +                _PR_RUNQ_UNLOCK(cpu);
   1.403 +
   1.404 +                if (pri > me->priority)
   1.405 +                    _PR_SET_RESCHED_FLAG();
   1.406 +
   1.407 +                thread->wait.cvar = NULL;
   1.408 +
   1.409 +                _PR_MD_WAKEUP_WAITER(thread);
   1.410 +
   1.411 +            } else if (thread->io_pending == PR_TRUE) {
   1.412 +                /* Need to put IO sleeper back on runq */
   1.413 +                int pri = thread->priority;
   1.414 +
   1.415 +                thread->io_suspended = PR_TRUE;
   1.416 +#ifdef WINNT
   1.417 +				/*
   1.418 +				 * For NT, record the cpu on which I/O was issued
   1.419 +				 * I/O cancellation is done on the same cpu
   1.420 +				 */
   1.421 +                thread->md.thr_bound_cpu = cpu;
   1.422 +#endif
   1.423 +
   1.424 +				PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
   1.425 +                PR_ASSERT(thread->cpu == cpu);
   1.426 +                thread->state = _PR_RUNNABLE;
   1.427 +                _PR_RUNQ_LOCK(cpu);
   1.428 +                _PR_ADD_RUNQ(thread, cpu, pri);
   1.429 +                _PR_RUNQ_UNLOCK(cpu);
   1.430 +            }
   1.431 +        }
   1.432 +        _PR_THREAD_UNLOCK(thread);
   1.433 +    }
   1.434 +}
   1.435 +
   1.436 +/************************************************************************/
   1.437 +
   1.438 +/*
   1.439 +** Create a new condition variable.
   1.440 +** 	"lock" is the lock to use with the condition variable.
   1.441 +**
   1.442 +** Condition variables are synchronization objects that threads can use
   1.443 +** to wait for some condition to occur.
   1.444 +**
   1.445 +** This may fail if memory is tight or if some operating system resource
   1.446 +** is low.
   1.447 +*/
   1.448 +PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock)
   1.449 +{
   1.450 +    PRCondVar *cvar;
   1.451 +
   1.452 +    cvar = PR_NEWZAP(PRCondVar);
   1.453 +    if (cvar) {
   1.454 +        if (_PR_InitCondVar(cvar, lock) != PR_SUCCESS) {
   1.455 +            PR_DELETE(cvar);
   1.456 +            return NULL;
   1.457 +        }
   1.458 +    } else {
   1.459 +        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   1.460 +    }
   1.461 +    return cvar;
   1.462 +}
   1.463 +
   1.464 +PRStatus _PR_InitCondVar(PRCondVar *cvar, PRLock *lock)
   1.465 +{
   1.466 +    PR_ASSERT(lock != NULL);
   1.467 +
   1.468 +#ifdef _PR_GLOBAL_THREADS_ONLY
   1.469 +    if(_PR_MD_NEW_CV(&cvar->md)) {
   1.470 +        PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
   1.471 +        return PR_FAILURE;
   1.472 +    }
   1.473 +#endif
   1.474 +    if (_PR_MD_NEW_LOCK(&(cvar->ilock)) != PR_SUCCESS) {
   1.475 +        PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
   1.476 +        return PR_FAILURE;
   1.477 +    }
   1.478 +    cvar->lock = lock;
   1.479 +    PR_INIT_CLIST(&cvar->condQ);
   1.480 +    return PR_SUCCESS;
   1.481 +}
   1.482 +
   1.483 +/*
   1.484 +** Destroy a condition variable. There must be no thread
   1.485 +** waiting on the condvar. The caller is responsible for guaranteeing
   1.486 +** that the condvar is no longer in use.
   1.487 +**
   1.488 +*/
   1.489 +PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar)
   1.490 +{
   1.491 +    _PR_FreeCondVar(cvar);
   1.492 +    PR_DELETE(cvar);
   1.493 +}
   1.494 +
   1.495 +void _PR_FreeCondVar(PRCondVar *cvar)
   1.496 +{
   1.497 +    PR_ASSERT(cvar->condQ.next == &cvar->condQ);
   1.498 +
   1.499 +#ifdef _PR_GLOBAL_THREADS_ONLY
   1.500 +    _PR_MD_FREE_CV(&cvar->md);
   1.501 +#endif
   1.502 +    _PR_MD_FREE_LOCK(&(cvar->ilock));
   1.503 +}
   1.504 +
   1.505 +/*
   1.506 +** Wait for a notify on the condition variable. Sleep for "tiemout" amount
   1.507 +** of ticks (if "timeout" is zero then the sleep is indefinite). While
   1.508 +** the thread is waiting it unlocks lock. When the wait has
   1.509 +** finished the thread regains control of the condition variable after
   1.510 +** locking the associated lock.
   1.511 +**
   1.512 +** The thread waiting on the condvar will be resumed when the condvar is
   1.513 +** notified (assuming the thread is the next in line to receive the
   1.514 +** notify) or when the timeout elapses.
   1.515 +**
   1.516 +** Returns PR_FAILURE if the caller has not locked the lock associated
   1.517 +** with the condition variable or the thread has been interrupted.
   1.518 +*/
   1.519 +extern PRThread *suspendAllThread;
   1.520 +PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout)
   1.521 +{
   1.522 +    PRThread *me = _PR_MD_CURRENT_THREAD();
   1.523 +
   1.524 +	PR_ASSERT(cvar->lock->owner == me);
   1.525 +	PR_ASSERT(me != suspendAllThread);
   1.526 +    	if (cvar->lock->owner != me) return PR_FAILURE;
   1.527 +
   1.528 +	return _PR_WaitCondVar(me, cvar, cvar->lock, timeout);
   1.529 +}
   1.530 +
   1.531 +/*
   1.532 +** Notify the highest priority thread waiting on the condition
   1.533 +** variable. If a thread is waiting on the condition variable (using
   1.534 +** PR_Wait) then it is awakened and begins waiting on the lock.
   1.535 +*/
   1.536 +PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar)
   1.537 +{
   1.538 +    PRThread *me = _PR_MD_CURRENT_THREAD();
   1.539 +
   1.540 +    PR_ASSERT(cvar->lock->owner == me);
   1.541 +    PR_ASSERT(me != suspendAllThread);
   1.542 +    if (cvar->lock->owner != me) return PR_FAILURE;
   1.543 +
   1.544 +    _PR_NotifyCondVar(cvar, me);
   1.545 +    return PR_SUCCESS;
   1.546 +}
   1.547 +
   1.548 +/*
   1.549 +** Notify all of the threads waiting on the condition variable. All of
   1.550 +** threads are notified in turn. The highest priority thread will
   1.551 +** probably acquire the lock.
   1.552 +*/
   1.553 +PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar)
   1.554 +{
   1.555 +    PRCList *q;
   1.556 +    PRIntn is;
   1.557 +    PRThread *me = _PR_MD_CURRENT_THREAD();
   1.558 +
   1.559 +    PR_ASSERT(cvar->lock->owner == me);
   1.560 +    if (cvar->lock->owner != me) return PR_FAILURE;
   1.561 +
   1.562 +#ifdef _PR_GLOBAL_THREADS_ONLY
   1.563 +    _PR_MD_NOTIFYALL_CV(&cvar->md, &cvar->lock->ilock);
   1.564 +    return PR_SUCCESS;
   1.565 +#else  /* _PR_GLOBAL_THREADS_ONLY */
   1.566 +    if ( !_PR_IS_NATIVE_THREAD(me))
   1.567 +    	_PR_INTSOFF(is);
   1.568 +    _PR_CVAR_LOCK(cvar);
   1.569 +    q = cvar->condQ.next;
   1.570 +    while (q != &cvar->condQ) {
   1.571 +		PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar));
   1.572 +		_PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me);
   1.573 +		q = q->next;
   1.574 +    }
   1.575 +    _PR_CVAR_UNLOCK(cvar);
   1.576 +    if (!_PR_IS_NATIVE_THREAD(me))
   1.577 +    	_PR_INTSON(is);
   1.578 +
   1.579 +    return PR_SUCCESS;
   1.580 +#endif  /* _PR_GLOBAL_THREADS_ONLY */
   1.581 +}
   1.582 +
   1.583 +
   1.584 +/*********************************************************************/
   1.585 +/*********************************************************************/
   1.586 +/********************ROUTINES FOR DCE EMULATION***********************/
   1.587 +/*********************************************************************/
   1.588 +/*********************************************************************/
   1.589 +#include "prpdce.h"
   1.590 +
   1.591 +PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void)
   1.592 +{
   1.593 +    PRCondVar *cvar = PR_NEWZAP(PRCondVar);
   1.594 +    if (NULL != cvar)
   1.595 +    {
   1.596 +        if (_PR_MD_NEW_LOCK(&(cvar->ilock)) == PR_FAILURE)
   1.597 +        {
   1.598 +		    PR_DELETE(cvar); cvar = NULL;
   1.599 +	    }
   1.600 +	    else
   1.601 +	    {
   1.602 +	        PR_INIT_CLIST(&cvar->condQ);
   1.603 +            cvar->lock = _PR_NAKED_CV_LOCK;
   1.604 +	    }
   1.605 +
   1.606 +    }
   1.607 +    return cvar;
   1.608 +}
   1.609 +
   1.610 +PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar)
   1.611 +{
   1.612 +    PR_ASSERT(cvar->condQ.next == &cvar->condQ);
   1.613 +    PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
   1.614 +
   1.615 +    _PR_MD_FREE_LOCK(&(cvar->ilock));
   1.616 + 
   1.617 +    PR_DELETE(cvar);
   1.618 +}
   1.619 +
   1.620 +PR_IMPLEMENT(PRStatus) PRP_NakedWait(
   1.621 +	PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout)
   1.622 +{
   1.623 +    PRThread *me = _PR_MD_CURRENT_THREAD();
   1.624 +    PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
   1.625 +	return _PR_WaitCondVar(me, cvar, lock, timeout);
   1.626 +}  /* PRP_NakedWait */
   1.627 +
   1.628 +PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar)
   1.629 +{
   1.630 +    PRThread *me = _PR_MD_CURRENT_THREAD();
   1.631 +    PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
   1.632 +
   1.633 +    _PR_NotifyCondVar(cvar, me);
   1.634 +
   1.635 +    return PR_SUCCESS;
   1.636 +}  /* PRP_NakedNotify */
   1.637 +
   1.638 +PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar)
   1.639 +{
   1.640 +    PRCList *q;
   1.641 +    PRIntn is;
   1.642 +    PRThread *me = _PR_MD_CURRENT_THREAD();
   1.643 +    PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
   1.644 +
   1.645 +    if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
   1.646 +	_PR_MD_LOCK( &(cvar->ilock) );
   1.647 +    q = cvar->condQ.next;
   1.648 +    while (q != &cvar->condQ) {
   1.649 +		PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar));
   1.650 +		_PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me);
   1.651 +		q = q->next;
   1.652 +    }
   1.653 +	_PR_MD_UNLOCK( &(cvar->ilock) );
   1.654 +    if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
   1.655 +
   1.656 +    return PR_SUCCESS;
   1.657 +}  /* PRP_NakedBroadcast */
   1.658 +

mercurial