Bug 812085: Initialize Windows CRITICAL_SECTIONs without debug info and
authorwtc%google.com
Sun, 10 Feb 2013 19:14:25 +0000
changeset 4437 7e7d5e18015b48c42ae1780d3f47f64254f46a68
parent 4436 22d76c1a141fdc0a0defb21d94cc5d407617fcac
child 4438 2214cb4730f0a21d99ed7b8809a4d16054cd76d6
push idunknown
push userunknown
push dateunknown
bugs812085
Bug 812085: Initialize Windows CRITICAL_SECTIONs without debug info and with nonzero spin count (1500). The patch is contributed by Chris Peterson <cpeterson@mozilla.com>. r=wtc. Modified Files: pr/include/md/_win95.h pr/src/md/windows/w95cv.c
pr/include/md/_win95.h
pr/src/md/windows/w95cv.c
--- a/pr/include/md/_win95.h
+++ b/pr/include/md/_win95.h
@@ -374,19 +374,19 @@ extern PROsfd _MD_Accept(PRFileDesc *fd,
 #define _MD_RESUME_CPU              _PR_MD_RESUME_CPU
 #define _MD_BEGIN_SUSPEND_ALL()
 #define _MD_BEGIN_RESUME_ALL()
 #define _MD_END_SUSPEND_ALL()
 #define _MD_END_RESUME_ALL()
 
 /* --- Lock stuff --- */
 #define _PR_LOCK                      _MD_LOCK
-#define _PR_UNLOCK					  _MD_UNLOCK
+#define _PR_UNLOCK                    _MD_UNLOCK
 
-#define _MD_NEW_LOCK(lock)            (InitializeCriticalSection(&((lock)->mutex)),(lock)->notified.length=0,(lock)->notified.link=NULL,PR_SUCCESS)
+#define _MD_NEW_LOCK                  _PR_MD_NEW_LOCK
 #define _MD_FREE_LOCK(lock)           DeleteCriticalSection(&((lock)->mutex))
 #define _MD_LOCK(lock)                EnterCriticalSection(&((lock)->mutex))
 #define _MD_TEST_AND_LOCK(lock)       (EnterCriticalSection(&((lock)->mutex)),0)
 #define _MD_UNLOCK                    _PR_MD_UNLOCK
 
 /* --- lock and cv waiting --- */
 #define _MD_WAIT                      _PR_MD_WAIT
 #define _MD_WAKEUP_WAITER             _PR_MD_WAKEUP_WAITER
@@ -494,17 +494,17 @@ extern DWORD _pr_currentCPUIndex;
 
 /* --- Scheduler stuff --- */
 #define LOCK_SCHEDULER()                 0
 #define UNLOCK_SCHEDULER()               0
 #define _PR_LockSched()                	 0
 #define _PR_UnlockSched()                0
 
 /* --- Initialization stuff --- */
-#define _MD_INIT_LOCKS()
+#define _MD_INIT_LOCKS                   _PR_MD_INIT_LOCKS
 
 /* --- Stack stuff --- */
 #define _MD_INIT_STACK(stack, redzone)
 #define _MD_CLEAR_STACK(stack)
 
 /* --- Memory-mapped files stuff --- */
 
 struct _MDFileMap {
--- a/pr/src/md/windows/w95cv.c
+++ b/pr/src/md/windows/w95cv.c
@@ -299,17 +299,69 @@ void _PR_MD_NOTIFY_CV(_MDCVar *cv, _MDLo
 }
 
 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);
     }
-    return;
 }