Back to index

lightning-sunbird  0.9+nobinonly
Functions
os2cv.c File Reference
#include "primpl.h"

Go to the source code of this file.

Functions

static void AddThreadToCVWaitQueueInternal (PRThread *thred, struct _MDCVar *cv)
void md_UnlockAndPostNotifies (_MDLock *lock, PRThread *waitThred, _MDCVar *waitCV)
static void md_PostNotifyToCvar (_MDCVar *cvar, _MDLock *lock, PRBool broadcast)
PRInt32 _PR_MD_NEW_CV (_MDCVar *cv)
void _PR_MD_FREE_CV (_MDCVar *cv)
void _PR_MD_WAIT_CV (_MDCVar *cv, _MDLock *lock, PRIntervalTime timeout)
void _PR_MD_NOTIFY_CV (_MDCVar *cv, _MDLock *lock)
PRStatus _PR_MD_NEW_LOCK (_MDLock *lock)
void _PR_MD_NOTIFYALL_CV (_MDCVar *cv, _MDLock *lock)

Function Documentation

Definition at line 292 of file os2cv.c.

{
    cv->magic = (PRUint32)-1;
    return;
}

Definition at line 282 of file os2cv.c.

{
    cv->magic = _MD_MAGIC_CV;
    /*
     * The waitHead, waitTail, and nwait fields are zeroed
     * when the PRCondVar structure is created.
     */
    return 0;
} 

Definition at line 388 of file os2cv.c.

{
#ifdef USE_RAMSEM
    // It's better if this API traps when pCriticalSect is not a valid
    // pointer, because we can't return an error code and if we just return
    // the API caller will have nasty bugs that are hard to find.
   
    PRAMSEM pramsem = (PRAMSEM)(&(lock->mutex));
    /* First time, set up addresses of processor specific functions
     */
    if (plisCurrent == NULL)
    {
        SEL selGlobal = 0, selLocal = 0;
   
        /* Convert 16 bit global information segment to 32 bit address
         * by performing CRMA on the 16 bit address: "shift" operation
         * to convert sel to flat, "and" operation to mask the address
         * to 32-bit
         */
        Dos16GetInfoSeg(&selGlobal, &selLocal);
        plisCurrent = (PLINFOSEG)(((ULONG)selLocal << 13) &
                      (ULONG)0x1fff0000);
   
    }
   
    memset(pramsem, 0, sizeof(pramsem));
    DosCreateEventSem(0, &pramsem->hevSem, DC_SEM_SHARED, 0);
   
    lock->notified.length=0;
    lock->notified.link=NULL;
    return PR_SUCCESS;
#else
    DosCreateMutexSem(0, &(lock->mutex), 0, 0);
    (lock)->notified.length=0;
    (lock)->notified.link=NULL;
    return PR_SUCCESS;
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _PR_MD_NOTIFY_CV ( _MDCVar cv,
_MDLock lock 
)

Definition at line 381 of file os2cv.c.

{
    md_PostNotifyToCvar(cv, lock, PR_FALSE);
    return;
}

Here is the call graph for this function:

void _PR_MD_NOTIFYALL_CV ( _MDCVar cv,
_MDLock lock 
)

Definition at line 428 of file os2cv.c.

{
    md_PostNotifyToCvar(cv, lock, PR_TRUE);
    return;
}

Here is the call graph for this function:

void _PR_MD_WAIT_CV ( _MDCVar cv,
_MDLock lock,
PRIntervalTime  timeout 
)

Definition at line 302 of file os2cv.c.

{
    PRThread *thred = _PR_MD_CURRENT_THREAD();
    ULONG rv, count;
    ULONG msecs = (timeout == PR_INTERVAL_NO_TIMEOUT) ?
            SEM_INDEFINITE_WAIT : PR_IntervalToMilliseconds(timeout);

    /*
     * If we have pending notifies, post them now.
     */
    if (0 != lock->notified.length) {
        md_UnlockAndPostNotifies(lock, thred, cv);
    } else {
        AddThreadToCVWaitQueueInternal(thred, cv);
#ifdef USE_RAMSEM
        SemReleasex86( &lock->mutex, 0 );
#else
        DosReleaseMutexSem(lock->mutex); 
#endif
    }

    /* Wait for notification or timeout; don't really care which */
    rv = DosWaitEventSem(thred->md.blocked_sema, msecs);
    if (rv == NO_ERROR) {
        DosResetEventSem(thred->md.blocked_sema, &count);
    }

#ifdef USE_RAMSEM
    SemRequest486(&(lock->mutex), -1);
#else
    DosRequestMutexSem((lock->mutex), SEM_INDEFINITE_WAIT);
#endif

    PR_ASSERT(rv == NO_ERROR || rv == ERROR_TIMEOUT);

    if(rv == ERROR_TIMEOUT)
    {
       if (thred->md.inCVWaitQueue) {
           PR_ASSERT((cv->waitTail != NULL && cv->waitHead != NULL)
                   || (cv->waitTail == NULL && cv->waitHead == NULL));
           cv->nwait -= 1;
           thred->md.inCVWaitQueue = PR_FALSE;
           if (cv->waitHead == thred) {
               cv->waitHead = thred->md.next;
               if (cv->waitHead == NULL) {
                   cv->waitTail = NULL;
               } else {
                   cv->waitHead->md.prev = NULL;
               }
           } else {
               PR_ASSERT(thred->md.prev != NULL);
               thred->md.prev->md.next = thred->md.next;
               if (thred->md.next != NULL) {
                   thred->md.next->md.prev = thred->md.prev;
               } else {
                   PR_ASSERT(cv->waitTail == thred);
                   cv->waitTail = thred->md.prev;
               }
           }
           thred->md.next = thred->md.prev = NULL;
       } else {
           /*
            * This thread must have been notified, but the
            * SemRelease call happens after SemRequest
            * times out.  Wait on the semaphore again to make it
            * non-signaled.  We assume this wait won't take long.
            */
           rv = DosWaitEventSem(thred->md.blocked_sema, SEM_INDEFINITE_WAIT);
           if (rv == NO_ERROR) {
               DosResetEventSem(thred->md.blocked_sema, &count);
           }
           PR_ASSERT(rv == NO_ERROR);
       }
    }
    PR_ASSERT(thred->md.inCVWaitQueue == PR_FALSE);
    return;
} /* --- end _PR_MD_WAIT_CV() --- */

Here is the call graph for this function:

static void AddThreadToCVWaitQueueInternal ( PRThread thred,
struct _MDCVar cv 
) [static]

Definition at line 98 of file os2cv.c.

{
    PR_ASSERT((cv->waitTail != NULL && cv->waitHead != NULL)
            || (cv->waitTail == NULL && cv->waitHead == NULL));
    cv->nwait += 1;
    thred->md.inCVWaitQueue = PR_TRUE;
    thred->md.next = NULL;
    thred->md.prev = cv->waitTail;
    if (cv->waitHead == NULL) {
        cv->waitHead = thred;
    } else {
        cv->waitTail->md.next = thred;
    }
    cv->waitTail = thred;
}

Here is the caller graph for this function:

static void md_PostNotifyToCvar ( _MDCVar cvar,
_MDLock lock,
PRBool  broadcast 
) [static]

Definition at line 239 of file os2cv.c.

{
    PRIntn index = 0;
    _MDNotified *notified = &lock->notified;

    while (1) {
        for (index = 0; index < notified->length; ++index) {
            if (notified->cv[index].cv == cvar) {
                if (broadcast) {
                    notified->cv[index].times = -1;
                } else if (-1 != notified->cv[index].times) {
                    notified->cv[index].times += 1;
                }
                return;
            }
        }
        /* if not full, enter new CV in this array */
        if (notified->length < _MD_CV_NOTIFIED_LENGTH) break;

        /* if there's no link, create an empty array and link it */
        if (NULL == notified->link) {
            notified->link = PR_NEWZAP(_MDNotified);
        }

        notified = notified->link;
    }

    /* A brand new entry in the array */
    notified->cv[index].times = (broadcast) ? -1 : 1;
    notified->cv[index].cv = cvar;
    notified->length += 1;
}

Here is the caller graph for this function:

void md_UnlockAndPostNotifies ( _MDLock lock,
PRThread waitThred,
_MDCVar waitCV 
)

Definition at line 125 of file os2cv.c.

{
    PRIntn index;
    _MDNotified post;
    _MDNotified *notified, *prev = NULL;

    /*
     * Time to actually notify any conditions that were affected
     * while the lock was held.  Get a copy of the list that's in
     * the lock structure and then zero the original.  If it's
     * linked to other such structures, we own that storage.
     */
    post = lock->notified;  /* a safe copy; we own the lock */

#if defined(DEBUG)
    memset(&lock->notified, 0, sizeof(_MDNotified));  /* reset */
#else
    lock->notified.length = 0;  /* these are really sufficient */
    lock->notified.link = NULL;
#endif

    /* 
     * Figure out how many threads we need to wake up.
     */
    notified = &post;  /* this is where we start */
    do {
        for (index = 0; index < notified->length; ++index) {
            _MDCVar *cv = notified->cv[index].cv;
            PRThread *thred;
            int i;
            
            /* Fast special case: no waiting threads */
            if (cv->waitHead == NULL) {
                notified->cv[index].notifyHead = NULL;
                continue;
            }

            /* General case */
            if (-1 == notified->cv[index].times) {
                /* broadcast */
                thred = cv->waitHead;
                while (thred != NULL) {
                    thred->md.inCVWaitQueue = PR_FALSE;
                    thred = thred->md.next;
                }
                notified->cv[index].notifyHead = cv->waitHead;
                cv->waitHead = cv->waitTail = NULL;
                cv->nwait = 0;
            } else {
                thred = cv->waitHead;
                i = notified->cv[index].times;
                while (thred != NULL && i > 0) {
                    thred->md.inCVWaitQueue = PR_FALSE;
                    thred = thred->md.next;
                    i--;
                }
                notified->cv[index].notifyHead = cv->waitHead;
                cv->waitHead = thred;
                if (cv->waitHead == NULL) {
                    cv->waitTail = NULL;
                } else {
                    if (cv->waitHead->md.prev != NULL) {
                        cv->waitHead->md.prev->md.next = NULL;
                        cv->waitHead->md.prev = NULL;
                    }
                }
                cv->nwait -= notified->cv[index].times - i;
            }
        }
        notified = notified->link;
    } while (NULL != notified);

    if (waitThred) {
        AddThreadToCVWaitQueueInternal(waitThred, waitCV);
    }

    /* Release the lock before notifying */
#ifdef USE_RAMSEM
      SemReleasex86(&lock->mutex, 0);
#else
      DosReleaseMutexSem(lock->mutex);
#endif

    notified = &post;  /* this is where we start */
    do {
        for (index = 0; index < notified->length; ++index) {
            PRThread *thred;
            PRThread *next;

            thred = notified->cv[index].notifyHead;
            while (thred != NULL) {
                BOOL rv;

                next = thred->md.next;
                thred->md.prev = thred->md.next = NULL;
                rv = DosPostEventSem(thred->md.blocked_sema);
                PR_ASSERT(rv == NO_ERROR);
                thred = next;
            }
        }
        prev = notified;
        notified = notified->link;
        if (&post != prev) PR_DELETE(prev);
    } while (NULL != notified);
}

Here is the call graph for this function:

Here is the caller graph for this function: