Back to index

lightning-sunbird  0.9+nobinonly
Functions | Variables
prucv.c File Reference
#include "primpl.h"
#include "prinrval.h"
#include "prtypes.h"
#include "prpdce.h"

Go to the source code of this file.

Functions

PRBool _PR_NotifyThread (PRThread *thread, PRThread *me)
void _PR_NotifyLockedThread (PRThread *thread)
PRStatus _PR_WaitCondVar (PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout)
void _PR_NotifyCondVar (PRCondVar *cvar, PRThread *me)
PRUint32 _PR_CondVarToString (PRCondVar *cvar, char *buf, PRUint32 buflen)
void _PR_ClockInterrupt (void)
 PR_IMPLEMENT (PRCondVar *)
 PR_IMPLEMENT (void)
 PR_IMPLEMENT (PRStatus)

Variables

PRThreadsuspendAllThread

Function Documentation

Definition at line 339 of file prucv.c.

{
    PRThread *thread, *me = _PR_MD_CURRENT_THREAD();
    _PRCPU *cpu = me->cpu;
    PRIntervalTime elapsed, now;
 
    PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);
    /* Figure out how much time elapsed since the last clock tick */
    now = PR_IntervalNow();
    elapsed = now - cpu->last_clock;
    cpu->last_clock = now;

#ifndef XP_MAC
    PR_LOG(_pr_clock_lm, PR_LOG_MAX,
          ("ExpireWaits: elapsed=%lld usec", elapsed));
#endif

    while(1) {
        _PR_SLEEPQ_LOCK(cpu);
        if (_PR_SLEEPQ(cpu).next == &_PR_SLEEPQ(cpu)) {
            _PR_SLEEPQ_UNLOCK(cpu);
            break;
        }

        thread = _PR_THREAD_PTR(_PR_SLEEPQ(cpu).next);
        PR_ASSERT(thread->cpu == cpu);

        if (elapsed < thread->sleep) {
            thread->sleep -= elapsed;
            _PR_SLEEPQMAX(thread->cpu) -= elapsed;
            _PR_SLEEPQ_UNLOCK(cpu);
            break;
        }
        _PR_SLEEPQ_UNLOCK(cpu);

        PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));

        _PR_THREAD_LOCK(thread);

        if (thread->cpu != cpu) {
            /*
            ** The thread was switched to another CPU
            ** between the time we unlocked the sleep
            ** queue and the time we acquired the thread
            ** lock, so it is none of our business now.
            */
            _PR_THREAD_UNLOCK(thread);
            continue;
        }

        /*
        ** Consume this sleeper's amount of elapsed time from the elapsed
        ** time value. The next remaining piece of elapsed time will be
        ** available for the next sleeping thread's timer.
        */
        _PR_SLEEPQ_LOCK(cpu);
        PR_ASSERT(!(thread->flags & _PR_ON_PAUSEQ));
        if (thread->flags & _PR_ON_SLEEPQ) {
            _PR_DEL_SLEEPQ(thread, PR_FALSE);
            elapsed -= thread->sleep;
            _PR_SLEEPQ_UNLOCK(cpu);
        } else {
            /* Thread was already handled; Go get another one */
            _PR_SLEEPQ_UNLOCK(cpu);
            _PR_THREAD_UNLOCK(thread);
            continue;
        }

        /* Notify the thread waiting on the condition variable */
        if (thread->flags & _PR_SUSPENDING) {
              PR_ASSERT((thread->state == _PR_IO_WAIT) ||
                            (thread->state == _PR_COND_WAIT));
            /*
            ** Thread is suspended and its condition timeout
            ** expired. Transfer thread from sleepQ to suspendQ.
            */
            thread->wait.cvar = NULL;
            _PR_MISCQ_LOCK(cpu);
            thread->state = _PR_SUSPENDED;
            _PR_ADD_SUSPENDQ(thread, cpu);
            _PR_MISCQ_UNLOCK(cpu);
        } else {
            if (thread->wait.cvar) {
                PRThreadPriority pri;

                /* Do work very similar to what _PR_NotifyThread does */
                PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) );

                /* Make thread runnable */
                pri = thread->priority;
                thread->state = _PR_RUNNABLE;
                PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));

                PR_ASSERT(thread->cpu == cpu);
                _PR_RUNQ_LOCK(cpu);
                _PR_ADD_RUNQ(thread, cpu, pri);
                _PR_RUNQ_UNLOCK(cpu);

                if (pri > me->priority)
                    _PR_SET_RESCHED_FLAG();

                thread->wait.cvar = NULL;

                _PR_MD_WAKEUP_WAITER(thread);

            } else if (thread->io_pending == PR_TRUE) {
                /* Need to put IO sleeper back on runq */
                int pri = thread->priority;

                thread->io_suspended = PR_TRUE;
#ifdef WINNT
                            /*
                             * For NT, record the cpu on which I/O was issued
                             * I/O cancellation is done on the same cpu
                             */
                thread->md.thr_bound_cpu = cpu;
#endif

                            PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
                PR_ASSERT(thread->cpu == cpu);
                thread->state = _PR_RUNNABLE;
                _PR_RUNQ_LOCK(cpu);
                _PR_ADD_RUNQ(thread, cpu, pri);
                _PR_RUNQ_UNLOCK(cpu);
            }
        }
        _PR_THREAD_UNLOCK(thread);
    }
}

Here is the caller graph for this function:

PRUint32 _PR_CondVarToString ( PRCondVar cvar,
char *  buf,
PRUint32  buflen 
)

Definition at line 322 of file prucv.c.

{
    PRUint32 nb;

    if (cvar->lock->owner) {
       nb = PR_snprintf(buf, buflen, "[%p] owner=%ld[%p]",
                      cvar, cvar->lock->owner->id, cvar->lock->owner);
    } else {
       nb = PR_snprintf(buf, buflen, "[%p]", cvar);
    }
    return nb;
}

Here is the call graph for this function:

void _PR_NotifyCondVar ( PRCondVar cvar,
PRThread me 
)

Definition at line 286 of file prucv.c.

{
#ifdef _PR_GLOBAL_THREADS_ONLY
    _PR_MD_NOTIFY_CV(&cvar->md, &cvar->lock->ilock);
#else  /* _PR_GLOBAL_THREADS_ONLY */

    PRCList *q;
    PRIntn is;

    if ( !_PR_IS_NATIVE_THREAD(me))
       _PR_INTSOFF(is);
    PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);

    _PR_CVAR_LOCK(cvar);
    q = cvar->condQ.next;
    while (q != &cvar->condQ) {
#ifndef XP_MAC
        PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("_PR_NotifyCondVar: cvar=%p", cvar));
#endif
        if (_PR_THREAD_CONDQ_PTR(q)->wait.cvar)  {
            if (_PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me) == PR_TRUE)
                break;
        }
        q = q->next;
    }
    _PR_CVAR_UNLOCK(cvar);

    if ( !_PR_IS_NATIVE_THREAD(me))
       _PR_INTSON(is);

#endif  /* _PR_GLOBAL_THREADS_ONLY */
}

Here is the call graph for this function:

Definition at line 131 of file prucv.c.

{
    PRThread *me = _PR_MD_CURRENT_THREAD();
    PRCondVar *cvar;
    PRThreadPriority pri;

    if ( !_PR_IS_NATIVE_THREAD(me))
       PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);

    cvar = thread->wait.cvar;
    thread->wait.cvar = NULL;
    _PR_THREAD_UNLOCK(thread);

    _PR_CVAR_LOCK(cvar);
    _PR_THREAD_LOCK(thread);

    if (!_PR_IS_NATIVE_THREAD(thread)) {
            _PR_SLEEPQ_LOCK(thread->cpu);
            /* The notify and timeout can collide; in which case both may
             * attempt to delete from the sleepQ; only let one do it.
             */
            if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ))
                _PR_DEL_SLEEPQ(thread, PR_TRUE);
            _PR_SLEEPQ_UNLOCK(thread->cpu);

           /* Make thread runnable */
           pri = thread->priority;
           thread->state = _PR_RUNNABLE;

           PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));

            _PR_AddThreadToRunQ(me, thread);
            _PR_THREAD_UNLOCK(thread);

            _PR_MD_WAKEUP_WAITER(thread);
    } else {
           if (thread->flags & _PR_SUSPENDING) {
              /*
               * set thread state to SUSPENDED; a Resume operation
               * on the thread will enable the thread to run
               */
              thread->state = _PR_SUSPENDED;
            } else
              thread->state = _PR_RUNNING;
            _PR_THREAD_UNLOCK(thread);
            _PR_MD_WAKEUP_WAITER(thread);
    }    

    _PR_CVAR_UNLOCK(cvar);
    return;
}

Here is the call graph for this function:

PRBool _PR_NotifyThread ( PRThread thread,
PRThread me 
)

Definition at line 58 of file prucv.c.

{
    PRBool rv;

    PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);

    _PR_THREAD_LOCK(thread);
    PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
    if ( !_PR_IS_NATIVE_THREAD(thread) ) {
        if (thread->wait.cvar != NULL) {
            thread->wait.cvar = NULL;

            _PR_SLEEPQ_LOCK(thread->cpu);
            /* The notify and timeout can collide; in which case both may
             * attempt to delete from the sleepQ; only let one do it.
             */
            if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ))
                _PR_DEL_SLEEPQ(thread, PR_TRUE);
            _PR_SLEEPQ_UNLOCK(thread->cpu);

           if (thread->flags & _PR_SUSPENDING) {
              /*
               * set thread state to SUSPENDED; a Resume operation
               * on the thread will move it to the runQ
               */
              thread->state = _PR_SUSPENDED;
              _PR_MISCQ_LOCK(thread->cpu);
              _PR_ADD_SUSPENDQ(thread, thread->cpu);
              _PR_MISCQ_UNLOCK(thread->cpu);
              _PR_THREAD_UNLOCK(thread);
           } else {
              /* Make thread runnable */
              thread->state = _PR_RUNNABLE;
              _PR_THREAD_UNLOCK(thread);

                _PR_AddThreadToRunQ(me, thread);
                _PR_MD_WAKEUP_WAITER(thread);
            }

            rv = PR_TRUE;
        } else {
            /* Thread has already been notified */
            _PR_THREAD_UNLOCK(thread);
            rv = PR_FALSE;
        }
    } else { /* If the thread is a native thread */
        if (thread->wait.cvar) {
            thread->wait.cvar = NULL;

           if (thread->flags & _PR_SUSPENDING) {
              /*
               * set thread state to SUSPENDED; a Resume operation
               * on the thread will enable the thread to run
               */
              thread->state = _PR_SUSPENDED;
            } else
              thread->state = _PR_RUNNING;
            _PR_THREAD_UNLOCK(thread);
            _PR_MD_WAKEUP_WAITER(thread);
            rv = PR_TRUE;
        } else {
            _PR_THREAD_UNLOCK(thread);
            rv = PR_FALSE;
        }    
    }    

    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRStatus _PR_WaitCondVar ( PRThread thread,
PRCondVar cvar,
PRLock lock,
PRIntervalTime  timeout 
)

Definition at line 186 of file prucv.c.

{
    PRIntn is;
    PRStatus rv = PR_SUCCESS;

    PR_ASSERT(thread == _PR_MD_CURRENT_THREAD());
    PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));

#ifdef _PR_GLOBAL_THREADS_ONLY
    if (_PR_PENDING_INTERRUPT(thread)) {
        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
        thread->flags &= ~_PR_INTERRUPT;
        return PR_FAILURE;
    }

    thread->wait.cvar = cvar;
    lock->owner = NULL;
    _PR_MD_WAIT_CV(&cvar->md,&lock->ilock, timeout);
    thread->wait.cvar = NULL;
    lock->owner = thread;
    if (_PR_PENDING_INTERRUPT(thread)) {
        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
        thread->flags &= ~_PR_INTERRUPT;
        return PR_FAILURE;
    }

    return PR_SUCCESS;
#else  /* _PR_GLOBAL_THREADS_ONLY */

    if ( !_PR_IS_NATIVE_THREAD(thread))
       _PR_INTSOFF(is);

    _PR_CVAR_LOCK(cvar);
    _PR_THREAD_LOCK(thread);

    if (_PR_PENDING_INTERRUPT(thread)) {
        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
        thread->flags &= ~_PR_INTERRUPT;
       _PR_CVAR_UNLOCK(cvar);
       _PR_THREAD_UNLOCK(thread);
       if ( !_PR_IS_NATIVE_THREAD(thread))
              _PR_INTSON(is);
        return PR_FAILURE;
    }

    thread->state = _PR_COND_WAIT;
    thread->wait.cvar = cvar;

    /*
    ** Put the caller thread on the condition variable's wait Q
    */
    PR_APPEND_LINK(&thread->waitQLinks, &cvar->condQ);

    /* Note- for global scope threads, we don't put them on the
     *       global sleepQ, so each global thread must put itself
     *       to sleep only for the time it wants to.
     */
    if ( !_PR_IS_NATIVE_THREAD(thread) ) {
        _PR_SLEEPQ_LOCK(thread->cpu);
        _PR_ADD_SLEEPQ(thread, timeout);
        _PR_SLEEPQ_UNLOCK(thread->cpu);
    }
    _PR_CVAR_UNLOCK(cvar);
    _PR_THREAD_UNLOCK(thread);
   
    /* 
    ** Release lock protecting the condition variable and thereby giving time 
    ** to the next thread which can potentially notify on the condition variable
    */
    PR_Unlock(lock);

    PR_LOG(_pr_cvar_lm, PR_LOG_MIN,
          ("PR_Wait: cvar=%p waiting for %d", cvar, timeout));

    rv = _PR_MD_WAIT(thread, timeout);

    _PR_CVAR_LOCK(cvar);
    PR_REMOVE_LINK(&thread->waitQLinks);
    _PR_CVAR_UNLOCK(cvar);

    PR_LOG(_pr_cvar_lm, PR_LOG_MIN,
          ("PR_Wait: cvar=%p done waiting", cvar));

    if ( !_PR_IS_NATIVE_THREAD(thread))
       _PR_INTSON(is);

    /* Acquire lock again that we had just relinquished */
    PR_Lock(lock);

    if (_PR_PENDING_INTERRUPT(thread)) {
        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
        thread->flags &= ~_PR_INTERRUPT;
        return PR_FAILURE;
    }

    return rv;
#endif  /* _PR_GLOBAL_THREADS_ONLY */
}

Here is the caller graph for this function:

Definition at line 481 of file prucv.c.

{
    PRCondVar *cvar;

    PR_ASSERT(lock != NULL);

    cvar = PR_NEWZAP(PRCondVar);
    if (cvar) {
#ifdef _PR_GLOBAL_THREADS_ONLY
       if(_PR_MD_NEW_CV(&cvar->md)) {
              PR_DELETE(cvar);
              PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
              return NULL;
       }
#endif
        if (_PR_MD_NEW_LOCK(&(cvar->ilock)) == PR_FAILURE) {
              PR_DELETE(cvar);
              PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
              return NULL;
       }
    cvar->lock = lock;
       PR_INIT_CLIST(&cvar->condQ);

    } else {
        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    }
    return cvar;
}

Here is the call graph for this function:

Definition at line 516 of file prucv.c.

{
    PR_ASSERT(cvar->condQ.next == &cvar->condQ);

#ifdef _PR_GLOBAL_THREADS_ONLY
    _PR_MD_FREE_CV(&cvar->md);
#endif
    _PR_MD_FREE_LOCK(&(cvar->ilock));
 
    PR_DELETE(cvar);
}

Definition at line 543 of file prucv.c.

Here is the call graph for this function:


Variable Documentation

Definition at line 87 of file pruthr.c.