Home | History | Annotate | Download | only in source
      1 /*
      2  *  Use of this source code is governed by the ACE copyright license which
      3  *  can be found in the LICENSE file in the third_party_mods/ace directory of
      4  *  the source tree or at http://www1.cse.wustl.edu/~schmidt/ACE-copying.html.
      5  */
      6 /*
      7  *  This source code contain modifications to the original source code
      8  *  which can be found here:
      9  *  http://www.cs.wustl.edu/~schmidt/win32-cv-1.html (section 3.2).
     10  *  Modifications:
     11  *  1) Dynamic detection of native support for condition variables.
     12  *  2) Use of WebRTC defined types and classes. Renaming of some functions.
     13  *  3) Introduction of a second event for wake all functionality. This prevents
     14  *     a thread from spinning on the same condition variable, preventing other
     15  *     threads from waking up.
     16  */
     17 
     18 // TODO (hellner): probably nicer to split up native and generic
     19 // implementation into two different files
     20 
     21 #include "condition_variable_win.h"
     22 
     23 #include "critical_section_win.h"
     24 #include "trace.h"
     25 
     26 namespace webrtc {
     27 bool ConditionVariableWindows::_winSupportConditionVariablesPrimitive = false;
     28 static HMODULE library = NULL;
     29 
     30 PInitializeConditionVariable  _PInitializeConditionVariable;
     31 PSleepConditionVariableCS     _PSleepConditionVariableCS;
     32 PWakeConditionVariable        _PWakeConditionVariable;
     33 PWakeAllConditionVariable     _PWakeAllConditionVariable;
     34 
     35 typedef void (WINAPI *PInitializeConditionVariable)(PCONDITION_VARIABLE);
     36 typedef BOOL (WINAPI *PSleepConditionVariableCS)(PCONDITION_VARIABLE,
     37                                                  PCRITICAL_SECTION, DWORD);
     38 typedef void (WINAPI *PWakeConditionVariable)(PCONDITION_VARIABLE);
     39 typedef void (WINAPI *PWakeAllConditionVariable)(PCONDITION_VARIABLE);
     40 
     41 ConditionVariableWindows::ConditionVariableWindows()
     42     : _eventID(WAKEALL_0)
     43 {
     44     if (!library)
     45     {
     46         // Use native implementation if supported (i.e Vista+)
     47         library = LoadLibrary(TEXT("Kernel32.dll"));
     48         if (library)
     49         {
     50             WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
     51                          "Loaded Kernel.dll");
     52 
     53             _PInitializeConditionVariable =
     54                 (PInitializeConditionVariable) GetProcAddress(
     55                     library,
     56                     "InitializeConditionVariable");
     57             _PSleepConditionVariableCS =
     58                 (PSleepConditionVariableCS)GetProcAddress(
     59                     library,
     60                     "SleepConditionVariableCS");
     61             _PWakeConditionVariable =
     62                 (PWakeConditionVariable)GetProcAddress(
     63                     library,
     64                      "WakeConditionVariable");
     65             _PWakeAllConditionVariable =
     66                 (PWakeAllConditionVariable)GetProcAddress(
     67                     library,
     68                     "WakeAllConditionVariable");
     69 
     70             if(_PInitializeConditionVariable &&
     71                _PSleepConditionVariableCS &&
     72                _PWakeConditionVariable &&
     73                _PWakeAllConditionVariable)
     74             {
     75                 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
     76                              "Loaded native condition variables");
     77                 _winSupportConditionVariablesPrimitive = true;
     78             }
     79         }
     80     }
     81 
     82     if (_winSupportConditionVariablesPrimitive)
     83     {
     84         _PInitializeConditionVariable(&_conditionVariable);
     85 
     86         _events[WAKEALL_0] = NULL;
     87         _events[WAKEALL_1] = NULL;
     88         _events[WAKE] = NULL;
     89 
     90     } else {
     91         memset(&_numWaiters[0],0,sizeof(_numWaiters));
     92 
     93         InitializeCriticalSection(&_numWaitersCritSect);
     94 
     95         _events[WAKEALL_0] = CreateEvent(NULL,  // no security attributes
     96                                          TRUE,  // manual-reset, sticky event
     97                                          FALSE, // initial state non-signaled
     98                                          NULL); // no name for event
     99 
    100         _events[WAKEALL_1] = CreateEvent(NULL,  // no security attributes
    101                                          TRUE,  // manual-reset, sticky event
    102                                          FALSE, // initial state non-signaled
    103                                          NULL); // no name for event
    104 
    105         _events[WAKE] = CreateEvent(NULL,  // no security attributes
    106                                     FALSE, // auto-reset, sticky event
    107                                     FALSE, // initial state non-signaled
    108                                     NULL); // no name for event
    109     }
    110 }
    111 
    112 ConditionVariableWindows::~ConditionVariableWindows()
    113 {
    114     if(!_winSupportConditionVariablesPrimitive)
    115     {
    116         CloseHandle(_events[WAKE]);
    117         CloseHandle(_events[WAKEALL_1]);
    118         CloseHandle(_events[WAKEALL_0]);
    119 
    120         DeleteCriticalSection(&_numWaitersCritSect);
    121     }
    122 }
    123 
    124 void ConditionVariableWindows::SleepCS(CriticalSectionWrapper& critSect)
    125 {
    126     SleepCS(critSect, INFINITE);
    127 }
    128 
    129 bool ConditionVariableWindows::SleepCS(CriticalSectionWrapper& critSect,
    130                                        unsigned long maxTimeInMS)
    131 {
    132     CriticalSectionWindows* cs = reinterpret_cast<CriticalSectionWindows*>(
    133                                      &critSect);
    134 
    135     if(_winSupportConditionVariablesPrimitive)
    136     {
    137         BOOL retVal = _PSleepConditionVariableCS(&_conditionVariable,
    138                                                  &(cs->crit),maxTimeInMS);
    139         return (retVal == 0) ? false : true;
    140 
    141     }else
    142     {
    143         EnterCriticalSection(&_numWaitersCritSect);
    144         // Get the eventID for the event that will be triggered by next
    145         // WakeAll() call and start waiting for it.
    146         const EventWakeUpType eventID = (WAKEALL_0 == _eventID) ?
    147                                             WAKEALL_1 : WAKEALL_0;
    148         ++(_numWaiters[eventID]);
    149         LeaveCriticalSection(&_numWaitersCritSect);
    150 
    151         LeaveCriticalSection(&cs->crit);
    152         HANDLE events[2];
    153         events[0] = _events[WAKE];
    154         events[1] = _events[eventID];
    155         const DWORD result = WaitForMultipleObjects(2, // Wait on 2 events.
    156                                                     events,
    157                                                     FALSE, // Wait for either.
    158                                                     maxTimeInMS);
    159 
    160         const bool retVal = (result != WAIT_TIMEOUT);
    161 
    162         EnterCriticalSection(&_numWaitersCritSect);
    163         --(_numWaiters[eventID]);
    164         // Last waiter should only be true for WakeAll(). WakeAll() correspond
    165         // to position 1 in events[] -> (result == WAIT_OBJECT_0 + 1)
    166         const bool lastWaiter = (result == WAIT_OBJECT_0 + 1) &&
    167                                 (_numWaiters[eventID] == 0);
    168         LeaveCriticalSection(&_numWaitersCritSect);
    169 
    170         if (lastWaiter)
    171         {
    172             // Reset/unset the WakeAll() event since all threads have been
    173             // released.
    174             ResetEvent(_events[eventID]);
    175         }
    176 
    177         EnterCriticalSection(&cs->crit);
    178         return retVal;
    179     }
    180 }
    181 
    182 void
    183 ConditionVariableWindows::Wake()
    184 {
    185     if(_winSupportConditionVariablesPrimitive)
    186     {
    187         _PWakeConditionVariable(&_conditionVariable);
    188     }else
    189     {
    190         EnterCriticalSection(&_numWaitersCritSect);
    191         const bool haveWaiters = (_numWaiters[WAKEALL_0] > 0) ||
    192                                  (_numWaiters[WAKEALL_1] > 0);
    193         LeaveCriticalSection(&_numWaitersCritSect);
    194 
    195         if (haveWaiters)
    196         {
    197             SetEvent(_events[WAKE]);
    198         }
    199     }
    200 }
    201 
    202 void
    203 ConditionVariableWindows::WakeAll()
    204 {
    205     if(_winSupportConditionVariablesPrimitive)
    206     {
    207         _PWakeAllConditionVariable(&_conditionVariable);
    208     }else
    209     {
    210         EnterCriticalSection(&_numWaitersCritSect);
    211         // Update current WakeAll() event
    212         _eventID = (WAKEALL_0 == _eventID) ? WAKEALL_1 : WAKEALL_0;
    213         // Trigger current event
    214         const EventWakeUpType eventID = _eventID;
    215         const bool haveWaiters = _numWaiters[eventID] > 0;
    216         LeaveCriticalSection(&_numWaitersCritSect);
    217 
    218         if (haveWaiters)
    219         {
    220             SetEvent(_events[eventID]);
    221         }
    222     }
    223 }
    224 } // namespace webrtc
    225