blob: 98a1e8865fc8c732e0744070292af65a9ccfb6e6 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
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
andrew@webrtc.org59ccd5c2011-12-15 00:17:43 +000021#include "condition_variable_win.h"
andrew@webrtc.org59ccd5c2011-12-15 00:17:43 +000022#include "critical_section_win.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000023#include "trace.h"
24
25namespace webrtc {
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000026
27bool ConditionVariableWindows::win_support_condition_variables_primitive_ =
28 false;
niklase@google.com470e71d2011-07-07 08:21:25 +000029static HMODULE library = NULL;
30
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000031PInitializeConditionVariable PInitializeConditionVariable_;
32PSleepConditionVariableCS PSleepConditionVariableCS_;
33PWakeConditionVariable PWakeConditionVariable_;
34PWakeAllConditionVariable PWakeAllConditionVariable_;
niklase@google.com470e71d2011-07-07 08:21:25 +000035
36typedef void (WINAPI *PInitializeConditionVariable)(PCONDITION_VARIABLE);
37typedef BOOL (WINAPI *PSleepConditionVariableCS)(PCONDITION_VARIABLE,
38 PCRITICAL_SECTION, DWORD);
39typedef void (WINAPI *PWakeConditionVariable)(PCONDITION_VARIABLE);
40typedef void (WINAPI *PWakeAllConditionVariable)(PCONDITION_VARIABLE);
41
42ConditionVariableWindows::ConditionVariableWindows()
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000043 : eventID_(WAKEALL_0) {
44 if (!library) {
45 // Use native implementation if supported (i.e Vista+)
46 library = LoadLibrary(TEXT("Kernel32.dll"));
47 if (library) {
48 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Loaded Kernel.dll");
niklase@google.com470e71d2011-07-07 08:21:25 +000049
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000050 PInitializeConditionVariable_ =
51 (PInitializeConditionVariable) GetProcAddress(
52 library, "InitializeConditionVariable");
53 PSleepConditionVariableCS_ = (PSleepConditionVariableCS) GetProcAddress(
54 library, "SleepConditionVariableCS");
55 PWakeConditionVariable_ = (PWakeConditionVariable) GetProcAddress(
56 library, "WakeConditionVariable");
57 PWakeAllConditionVariable_ = (PWakeAllConditionVariable) GetProcAddress(
58 library, "WakeAllConditionVariable");
niklase@google.com470e71d2011-07-07 08:21:25 +000059
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000060 if (PInitializeConditionVariable_ && PSleepConditionVariableCS_
61 && PWakeConditionVariable_ && PWakeAllConditionVariable_) {
62 WEBRTC_TRACE(
63 kTraceStateInfo, kTraceUtility, -1,
64 "Loaded native condition variables");
65 win_support_condition_variables_primitive_ = true;
66 }
niklase@google.com470e71d2011-07-07 08:21:25 +000067 }
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000068 }
niklase@google.com470e71d2011-07-07 08:21:25 +000069
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000070 if (win_support_condition_variables_primitive_) {
71 PInitializeConditionVariable_(&condition_variable_);
niklase@google.com470e71d2011-07-07 08:21:25 +000072
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000073 events_[WAKEALL_0] = NULL;
74 events_[WAKEALL_1] = NULL;
75 events_[WAKE] = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +000076
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000077 } else {
78 memset(&num_waiters_[0], 0, sizeof(num_waiters_));
niklase@google.com470e71d2011-07-07 08:21:25 +000079
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000080 InitializeCriticalSection(&num_waiters_crit_sect_);
niklase@google.com470e71d2011-07-07 08:21:25 +000081
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000082 events_[WAKEALL_0] = CreateEvent(NULL, // no security attributes
83 TRUE, // manual-reset, sticky event
84 FALSE, // initial state non-signaled
85 NULL); // no name for event
niklase@google.com470e71d2011-07-07 08:21:25 +000086
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000087 events_[WAKEALL_1] = CreateEvent(NULL, // no security attributes
88 TRUE, // manual-reset, sticky event
89 FALSE, // initial state non-signaled
90 NULL); // no name for event
niklase@google.com470e71d2011-07-07 08:21:25 +000091
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000092 events_[WAKE] = CreateEvent(NULL, // no security attributes
93 FALSE, // auto-reset, sticky event
94 FALSE, // initial state non-signaled
95 NULL); // no name for event
96 }
niklase@google.com470e71d2011-07-07 08:21:25 +000097}
98
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000099ConditionVariableWindows::~ConditionVariableWindows() {
100 if (!win_support_condition_variables_primitive_) {
101 CloseHandle(events_[WAKE]);
102 CloseHandle(events_[WAKEALL_1]);
103 CloseHandle(events_[WAKEALL_0]);
niklase@google.com470e71d2011-07-07 08:21:25 +0000104
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +0000105 DeleteCriticalSection(&num_waiters_crit_sect_);
106 }
107}
108
109void ConditionVariableWindows::SleepCS(CriticalSectionWrapper& crit_sect) {
110 SleepCS(crit_sect, INFINITE);
111}
112
113bool ConditionVariableWindows::SleepCS(CriticalSectionWrapper& crit_sect,
114 unsigned long max_time_in_ms) {
115 CriticalSectionWindows* cs =
116 reinterpret_cast<CriticalSectionWindows*>(&crit_sect);
117
118 if (win_support_condition_variables_primitive_) {
119 BOOL ret_val = PSleepConditionVariableCS_(
120 &condition_variable_, &(cs->crit), max_time_in_ms);
121 return (ret_val == 0) ? false : true;
122 } else {
123 EnterCriticalSection(&num_waiters_crit_sect_);
124
125 // Get the eventID for the event that will be triggered by next
126 // WakeAll() call and start waiting for it.
127 const EventWakeUpType eventID =
128 (WAKEALL_0 == eventID_) ? WAKEALL_1 : WAKEALL_0;
129
130 ++(num_waiters_[eventID]);
131 LeaveCriticalSection(&num_waiters_crit_sect_);
132
133 LeaveCriticalSection(&cs->crit);
134 HANDLE events[2];
135 events[0] = events_[WAKE];
136 events[1] = events_[eventID];
137 const DWORD result = WaitForMultipleObjects(2, // Wait on 2 events.
138 events, FALSE, // Wait for either.
139 max_time_in_ms);
140
141 const bool ret_val = (result != WAIT_TIMEOUT);
142
143 EnterCriticalSection(&num_waiters_crit_sect_);
144 --(num_waiters_[eventID]);
145
146 // Last waiter should only be true for WakeAll(). WakeAll() correspond
147 // to position 1 in events[] -> (result == WAIT_OBJECT_0 + 1)
148 const bool last_waiter = (result == WAIT_OBJECT_0 + 1)
149 && (num_waiters_[eventID] == 0);
150 LeaveCriticalSection(&num_waiters_crit_sect_);
151
152 if (last_waiter) {
153 // Reset/unset the WakeAll() event since all threads have been
154 // released.
155 ResetEvent(events_[eventID]);
niklase@google.com470e71d2011-07-07 08:21:25 +0000156 }
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +0000157
158 EnterCriticalSection(&cs->crit);
159 return ret_val;
160 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000161}
162
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +0000163void ConditionVariableWindows::Wake() {
164 if (win_support_condition_variables_primitive_) {
165 PWakeConditionVariable_(&condition_variable_);
166 } else {
167 EnterCriticalSection(&num_waiters_crit_sect_);
168 const bool have_waiters = (num_waiters_[WAKEALL_0] > 0)
169 || (num_waiters_[WAKEALL_1] > 0);
170 LeaveCriticalSection(&num_waiters_crit_sect_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000171
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +0000172 if (have_waiters) {
173 SetEvent(events_[WAKE]);
niklase@google.com470e71d2011-07-07 08:21:25 +0000174 }
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +0000175 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000176}
177
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +0000178void ConditionVariableWindows::WakeAll() {
179 if (win_support_condition_variables_primitive_) {
180 PWakeAllConditionVariable_(&condition_variable_);
181 } else {
182 EnterCriticalSection(&num_waiters_crit_sect_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000183
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +0000184 // Update current WakeAll() event
185 eventID_ = (WAKEALL_0 == eventID_) ? WAKEALL_1 : WAKEALL_0;
186
187 // Trigger current event
188 const EventWakeUpType eventID = eventID_;
189 const bool have_waiters = num_waiters_[eventID] > 0;
190 LeaveCriticalSection(&num_waiters_crit_sect_);
191
192 if (have_waiters) {
193 SetEvent(events_[eventID]);
niklase@google.com470e71d2011-07-07 08:21:25 +0000194 }
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +0000195 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000196}
197
niklase@google.com470e71d2011-07-07 08:21:25 +0000198} // namespace webrtc