| Index: nspr/pr/src/md/windows/w95cv.c
|
| diff --git a/nspr/pr/src/md/windows/w95cv.c b/nspr/pr/src/md/windows/w95cv.c
|
| deleted file mode 100644
|
| index 27b34e6916058ff18ed8c465cb4861c2fe6fd856..0000000000000000000000000000000000000000
|
| --- a/nspr/pr/src/md/windows/w95cv.c
|
| +++ /dev/null
|
| @@ -1,367 +0,0 @@
|
| -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
| -/* This Source Code Form is subject to the terms of the Mozilla Public
|
| - * License, v. 2.0. If a copy of the MPL was not distributed with this
|
| - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
| -
|
| -/*
|
| - * w95cv.c -- Windows 95 Machine-Dependent Code for Condition Variables
|
| - *
|
| - * We implement our own condition variable wait queue. Each thread
|
| - * has a semaphore object (thread->md.blocked_sema) to block on while
|
| - * waiting on a condition variable.
|
| - *
|
| - * We use a deferred condition notify algorithm. When PR_NotifyCondVar
|
| - * or PR_NotifyAllCondVar is called, the condition notifies are simply
|
| - * recorded in the _MDLock structure. We defer the condition notifies
|
| - * until right after we unlock the lock. This way the awakened threads
|
| - * have a better chance to reaquire the lock.
|
| - */
|
| -
|
| -#include "primpl.h"
|
| -
|
| -/*
|
| - * AddThreadToCVWaitQueueInternal --
|
| - *
|
| - * Add the thread to the end of the condition variable's wait queue.
|
| - * The CV's lock must be locked when this function is called.
|
| - */
|
| -
|
| -static void
|
| -AddThreadToCVWaitQueueInternal(PRThread *thred, struct _MDCVar *cv)
|
| -{
|
| - 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;
|
| -}
|
| -
|
| -/*
|
| - * md_UnlockAndPostNotifies --
|
| - *
|
| - * Unlock the lock, and then do the deferred condition notifies.
|
| - * If waitThred and waitCV are not NULL, waitThred is added to
|
| - * the wait queue of waitCV before the lock is unlocked.
|
| - *
|
| - * This function is called by _PR_MD_WAIT_CV and _PR_MD_UNLOCK,
|
| - * the two places where a lock is unlocked.
|
| - */
|
| -static void
|
| -md_UnlockAndPostNotifies(
|
| - _MDLock *lock,
|
| - PRThread *waitThred,
|
| - _MDCVar *waitCV)
|
| -{
|
| - 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)
|
| - ZeroMemory(&lock->notified, 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 */
|
| - LeaveCriticalSection(&lock->mutex);
|
| -
|
| - 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 = ReleaseSemaphore(thred->md.blocked_sema, 1, NULL);
|
| - PR_ASSERT(rv != 0);
|
| - thred = next;
|
| - }
|
| - }
|
| - prev = notified;
|
| - notified = notified->link;
|
| - if (&post != prev) PR_DELETE(prev);
|
| - } while (NULL != notified);
|
| -}
|
| -
|
| -/*
|
| - * Notifies just get posted to the protecting mutex. The
|
| - * actual notification is done when the lock is released so that
|
| - * MP systems don't contend for a lock that they can't have.
|
| - */
|
| -static void md_PostNotifyToCvar(_MDCVar *cvar, _MDLock *lock,
|
| - PRBool broadcast)
|
| -{
|
| - 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;
|
| -}
|
| -
|
| -/*
|
| - * _PR_MD_NEW_CV() -- Creating new condition variable
|
| - * ... Solaris uses cond_init() in similar function.
|
| - *
|
| - * returns: -1 on failure
|
| - * 0 when it succeeds.
|
| - *
|
| - */
|
| -PRInt32
|
| -_PR_MD_NEW_CV(_MDCVar *cv)
|
| -{
|
| - cv->magic = _MD_MAGIC_CV;
|
| - /*
|
| - * The waitHead, waitTail, and nwait fields are zeroed
|
| - * when the PRCondVar structure is created.
|
| - */
|
| - return 0;
|
| -}
|
| -
|
| -void _PR_MD_FREE_CV(_MDCVar *cv)
|
| -{
|
| - cv->magic = (PRUint32)-1;
|
| - return;
|
| -}
|
| -
|
| -/*
|
| - * _PR_MD_WAIT_CV() -- Wait on condition variable
|
| - */
|
| -void _PR_MD_WAIT_CV(_MDCVar *cv, _MDLock *lock, PRIntervalTime timeout )
|
| -{
|
| - PRThread *thred = _PR_MD_CURRENT_THREAD();
|
| - DWORD rv;
|
| - DWORD msecs = (timeout == PR_INTERVAL_NO_TIMEOUT) ?
|
| - INFINITE : 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);
|
| - LeaveCriticalSection(&lock->mutex);
|
| - }
|
| -
|
| - /* Wait for notification or timeout; don't really care which */
|
| - rv = WaitForSingleObject(thred->md.blocked_sema, msecs);
|
| -
|
| - EnterCriticalSection(&(lock->mutex));
|
| -
|
| - PR_ASSERT(rv != WAIT_ABANDONED);
|
| - PR_ASSERT(rv != WAIT_FAILED);
|
| - PR_ASSERT(rv != WAIT_OBJECT_0 || thred->md.inCVWaitQueue == PR_FALSE);
|
| -
|
| - if (rv == WAIT_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
|
| - * ReleaseSemaphore call happens after WaitForSingleObject
|
| - * times out. Wait on the semaphore again to make it
|
| - * non-signaled. We assume this wait won't take long.
|
| - */
|
| - rv = WaitForSingleObject(thred->md.blocked_sema, INFINITE);
|
| - PR_ASSERT(rv == WAIT_OBJECT_0);
|
| - }
|
| - }
|
| - PR_ASSERT(thred->md.inCVWaitQueue == PR_FALSE);
|
| - return;
|
| -} /* --- end _PR_MD_WAIT_CV() --- */
|
| -
|
| -void _PR_MD_NOTIFY_CV(_MDCVar *cv, _MDLock *lock)
|
| -{
|
| - md_PostNotifyToCvar(cv, lock, PR_FALSE);
|
| - return;
|
| -}
|
| -
|
| -void _PR_MD_NOTIFYALL_CV(_MDCVar *cv, _MDLock *lock)
|
| -{
|
| - md_PostNotifyToCvar(cv, lock, PR_TRUE);
|
| - return;
|
| -}
|
| -
|
| -typedef BOOL (WINAPI *INITIALIZECRITICALSECTIONEX)(
|
| - CRITICAL_SECTION *lpCriticalSection,
|
| - DWORD dwSpinCount,
|
| - DWORD Flags);
|
| -
|
| -static INITIALIZECRITICALSECTIONEX sInitializeCriticalSectionEx;
|
| -
|
| -void _PR_MD_INIT_LOCKS(void)
|
| -{
|
| - /*
|
| - * Starting with Windows Vista, every CRITICAL_SECTION allocates an extra
|
| - * RTL_CRITICAL_SECTION_DEBUG object. Unfortunately, this debug object is
|
| - * not reclaimed by DeleteCriticalSection(), causing an apparent memory
|
| - * leak. This is a debugging "feature", not a bug. If we are running on
|
| - * Vista or later, use InitializeCriticalSectionEx() to allocate
|
| - * CRITICAL_SECTIONs without debug objects.
|
| - */
|
| - HMODULE hKernel32 = GetModuleHandle("kernel32.dll");
|
| - PR_ASSERT(hKernel32);
|
| - PR_ASSERT(!sInitializeCriticalSectionEx);
|
| - sInitializeCriticalSectionEx = (INITIALIZECRITICALSECTIONEX)
|
| - GetProcAddress(hKernel32, "InitializeCriticalSectionEx");
|
| -}
|
| -
|
| -/*
|
| - * By default, CRITICAL_SECTIONs are initialized with a spin count of 0.
|
| - * Joe Duffy's "Concurrent Programming on Windows" book suggests 1500 is
|
| - * a "reasonable starting point". On single-processor systems, the spin
|
| - * count is ignored and the critical section spin count is set to 0.
|
| - */
|
| -#define LOCK_SPIN_COUNT 1500
|
| -
|
| -PRStatus _PR_MD_NEW_LOCK(_MDLock *lock)
|
| -{
|
| - CRITICAL_SECTION *cs = &lock->mutex;
|
| - BOOL ok;
|
| -
|
| - if (sInitializeCriticalSectionEx) {
|
| - ok = sInitializeCriticalSectionEx(cs, LOCK_SPIN_COUNT,
|
| - CRITICAL_SECTION_NO_DEBUG_INFO);
|
| - } else {
|
| - ok = InitializeCriticalSectionAndSpinCount(cs, LOCK_SPIN_COUNT);
|
| - }
|
| - if (!ok) {
|
| - _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
|
| - return PR_FAILURE;
|
| - }
|
| -
|
| - lock->notified.length = 0;
|
| - lock->notified.link = NULL;
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -void _PR_MD_UNLOCK(_MDLock *lock)
|
| -{
|
| - if (0 != lock->notified.length) {
|
| - md_UnlockAndPostNotifies(lock, NULL, NULL);
|
| - } else {
|
| - LeaveCriticalSection(&lock->mutex);
|
| - }
|
| -}
|
|
|