diff nspr/pr/src/md/windows/w95cv.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nspr/pr/src/md/windows/w95cv.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,367 @@
+/* -*- 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);
+    }
+}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)