src/thread/windows/SDL_sysmutex.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 17 Feb 2011 09:13:12 -0800
changeset 5335 2bb1233924f1
parent 5262 b530ef003506
child 5336 66d3c4a6d6f8
permissions -rw-r--r--
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.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2011 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* Mutex functions using the Win32 API */
    25 
    26 #include "../../core/windows/SDL_windows.h"
    27 
    28 #include "SDL_mutex.h"
    29 
    30 
    31 struct SDL_mutex
    32 {
    33     CRITICAL_SECTION cs;
    34 };
    35 
    36 /* Create a mutex */
    37 SDL_mutex *
    38 SDL_CreateMutex(void)
    39 {
    40     SDL_mutex *mutex;
    41     static DWORD (WINAPI*pf_SetCriticalSectionSpinCount)(LPCRITICAL_SECTION, DWORD) = NULL;
    42     static HMODULE kernel32 = NULL;
    43 
    44     /* One time logic - detect WinNT */
    45     if(kernel32 == NULL) {
    46         kernel32 = GetModuleHandleA("kernel32.dll");
    47 		if(kernel32) {
    48             /* Attempt to resolve symbol -- Win9x gets NULL */
    49             pf_SetCriticalSectionSpinCount = (DWORD (WINAPI*)(LPCRITICAL_SECTION, DWORD))GetProcAddress(kernel32, "SetCriticalSectionSpinCount");
    50         }
    51 		else
    52 			kernel32 = (HMODULE)0x01; /* don't try to init again */
    53 	}
    54 
    55 
    56     /* Allocate mutex memory */
    57     mutex = (SDL_mutex *) SDL_malloc(sizeof(*mutex));
    58     if (mutex) {
    59         /* Initialize */
    60         InitializeCriticalSection(&mutex->cs);
    61 
    62         /* On SMP systems, a non-zero spin count generally helps performance */
    63         if(pf_SetCriticalSectionSpinCount) pf_SetCriticalSectionSpinCount(&mutex->cs, 2000);
    64     } else {
    65         SDL_OutOfMemory();
    66     }
    67     return (mutex);
    68 }
    69 
    70 /* Free the mutex */
    71 void
    72 SDL_DestroyMutex(SDL_mutex * mutex)
    73 {
    74     if (mutex) {
    75         DeleteCriticalSection(&mutex->cs);
    76         SDL_free(mutex);
    77     }
    78 }
    79 
    80 /* Lock the mutex */
    81 int
    82 SDL_mutexP(SDL_mutex * mutex)
    83 {
    84     if (mutex == NULL) {
    85         SDL_SetError("Passed a NULL mutex");
    86         return -1;
    87     }
    88 
    89     EnterCriticalSection(&mutex->cs);
    90     return (0);
    91 }
    92 
    93 /* Unlock the mutex */
    94 int
    95 SDL_mutexV(SDL_mutex * mutex)
    96 {
    97     if (mutex == NULL) {
    98         SDL_SetError("Passed a NULL mutex");
    99         return -1;
   100     }
   101 
   102     LeaveCriticalSection(&mutex->cs);
   103     return (0);
   104 }
   105 
   106 /* vi: set ts=4 sw=4 expandtab: */