Commit 58d7fc47 authored by Sam Lantinga's avatar Sam Lantinga

Fixed bug 1128

 Patrick Baggett      2011-02-16 22:58:33 PST

This enhancement is for both x86/x64 Windows.

The SDL implementation of mutexes uses the Win32 API interprocess
synchronization primitive called a "Mutex". This implementation is subpar
because it has a much higher overhead than an intraprocess mutex. The exact
technical details are below, but my tests have shown that for reasonably high
contention (10 threads on 4 physical cores), it has 13x higher overhead than
the Win32 CriticalSection API.

If this enhancement is accepted, I will write a patch to implement SDL mutexes
using the critical section API, which should dramatically reduce overhead and
improve scalability.


-- Tech details --
Normally, Win32 Mutexes are used across process boundaries to synchronize
separate processes. In order to lock or unlock them, a user->kernel space
transition is necessary, even in the uncontented case on a single CPU machine.
Win32 CriticalSection objects can only be used within the same process virtual
address space and thus to lock one, does not require a user->kernel space
transition for the uncontended case, and additionally may spin a short while
before going into kernel wait. This small spin allows a thread to obtain the
lock if the mutex is released shortly after the thread starts spinning, in
effect bypassing the overhead of user->kernel space transition which has higher
overhead than the spinning itself.
parent ea8037a6
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
struct SDL_mutex struct SDL_mutex
{ {
HANDLE id; CRITICAL_SECTION cs;
}; };
/* Create a mutex */ /* Create a mutex */
...@@ -38,17 +38,29 @@ SDL_mutex * ...@@ -38,17 +38,29 @@ SDL_mutex *
SDL_CreateMutex(void) SDL_CreateMutex(void)
{ {
SDL_mutex *mutex; SDL_mutex *mutex;
static DWORD (WINAPI*pf_SetCriticalSectionSpinCount)(LPCRITICAL_SECTION, DWORD) = NULL;
static HMODULE kernel32 = NULL;
/* One time logic - detect WinNT */
if(kernel32 == NULL) {
kernel32 = GetModuleHandleA("kernel32.dll");
if(kernel32) {
/* Attempt to resolve symbol -- Win9x gets NULL */
pf_SetCriticalSectionSpinCount = (DWORD (WINAPI*)(LPCRITICAL_SECTION, DWORD))GetProcAddress(kernel32, "SetCriticalSectionSpinCount");
}
else
kernel32 = (HMODULE)0x01; /* don't try to init again */
}
/* Allocate mutex memory */ /* Allocate mutex memory */
mutex = (SDL_mutex *) SDL_malloc(sizeof(*mutex)); mutex = (SDL_mutex *) SDL_malloc(sizeof(*mutex));
if (mutex) { if (mutex) {
/* Create the mutex, with initial value signaled */ /* Initialize */
mutex->id = CreateMutex(NULL, FALSE, NULL); InitializeCriticalSection(&mutex->cs);
if (!mutex->id) {
SDL_SetError("Couldn't create mutex"); /* On SMP systems, a non-zero spin count generally helps performance */
SDL_free(mutex); if(pf_SetCriticalSectionSpinCount) pf_SetCriticalSectionSpinCount(&mutex->cs, 2000);
mutex = NULL;
}
} else { } else {
SDL_OutOfMemory(); SDL_OutOfMemory();
} }
...@@ -60,10 +72,7 @@ void ...@@ -60,10 +72,7 @@ void
SDL_DestroyMutex(SDL_mutex * mutex) SDL_DestroyMutex(SDL_mutex * mutex)
{ {
if (mutex) { if (mutex) {
if (mutex->id) { DeleteCriticalSection(&mutex->cs);
CloseHandle(mutex->id);
mutex->id = 0;
}
SDL_free(mutex); SDL_free(mutex);
} }
} }
...@@ -76,10 +85,8 @@ SDL_mutexP(SDL_mutex * mutex) ...@@ -76,10 +85,8 @@ SDL_mutexP(SDL_mutex * mutex)
SDL_SetError("Passed a NULL mutex"); SDL_SetError("Passed a NULL mutex");
return -1; return -1;
} }
if (WaitForSingleObject(mutex->id, INFINITE) == WAIT_FAILED) {
SDL_SetError("Couldn't wait on mutex"); EnterCriticalSection(&mutex->cs);
return -1;
}
return (0); return (0);
} }
...@@ -91,10 +98,8 @@ SDL_mutexV(SDL_mutex * mutex) ...@@ -91,10 +98,8 @@ SDL_mutexV(SDL_mutex * mutex)
SDL_SetError("Passed a NULL mutex"); SDL_SetError("Passed a NULL mutex");
return -1; return -1;
} }
if (ReleaseMutex(mutex->id) == FALSE) {
SDL_SetError("Couldn't release mutex"); LeaveCriticalSection(&mutex->cs);
return -1;
}
return (0); return (0);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment