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 26namespace webrtc { 27bool ConditionVariableWindows::_winSupportConditionVariablesPrimitive = false; 28static HMODULE library = NULL; 29 30PInitializeConditionVariable _PInitializeConditionVariable; 31PSleepConditionVariableCS _PSleepConditionVariableCS; 32PWakeConditionVariable _PWakeConditionVariable; 33PWakeAllConditionVariable _PWakeAllConditionVariable; 34 35typedef void (WINAPI *PInitializeConditionVariable)(PCONDITION_VARIABLE); 36typedef BOOL (WINAPI *PSleepConditionVariableCS)(PCONDITION_VARIABLE, 37 PCRITICAL_SECTION, DWORD); 38typedef void (WINAPI *PWakeConditionVariable)(PCONDITION_VARIABLE); 39typedef void (WINAPI *PWakeAllConditionVariable)(PCONDITION_VARIABLE); 40 41ConditionVariableWindows::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 112ConditionVariableWindows::~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 124void ConditionVariableWindows::SleepCS(CriticalSectionWrapper& critSect) 125{ 126 SleepCS(critSect, INFINITE); 127} 128 129bool 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 182void 183ConditionVariableWindows::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 202void 203ConditionVariableWindows::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