webrtc_m130/webrtc/system_wrappers/source/condition_variable_event_win.cc
henrike@webrtc.org 686001dd96 Split condition_variable_win.cc into native (for Vista and newer OS versions) and generic implementation (based on events).
Note that this means that there is no new code. The code has been taken directly from condition_variable_win.cc/h compensating minimally to be able to split up the two code paths.

Tested by:
1) Disabling native implementation and send to try bots.
2) Only return native implementation (i.e. if native implementation returns NULL there will be a crash when using the condition variable) and send to try bots.
3) The final cl sent to trybots.
All tests pass.

The changes are due to static analyzer code complaints.

BUG=N/A

Review URL: https://webrtc-codereview.appspot.com/1191004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3728 4adac7df-926f-26a2-2b94-8c16560cd09d
2013-03-26 14:16:05 +00:00

128 lines
4.5 KiB
C++

/*
* Use of this source code is governed by the ACE copyright license which
* can be found in the LICENSE file in the third_party_mods/ace directory of
* the source tree or at http://www1.cse.wustl.edu/~schmidt/ACE-copying.html.
*/
/*
* This source code contain modifications to the original source code
* which can be found here:
* http://www.cs.wustl.edu/~schmidt/win32-cv-1.html (section 3.2).
* Modifications:
* 1) Dynamic detection of native support for condition variables.
* 2) Use of WebRTC defined types and classes. Renaming of some functions.
* 3) Introduction of a second event for wake all functionality. This prevents
* a thread from spinning on the same condition variable, preventing other
* threads from waking up.
*/
#include "webrtc/system_wrappers/source/condition_variable_event_win.h"
#include "webrtc/system_wrappers/source/critical_section_win.h"
namespace webrtc {
ConditionVariableEventWin::ConditionVariableEventWin() : eventID_(WAKEALL_0) {
memset(&num_waiters_[0], 0, sizeof(num_waiters_));
InitializeCriticalSection(&num_waiters_crit_sect_);
events_[WAKEALL_0] = CreateEvent(NULL, // no security attributes
TRUE, // manual-reset, sticky event
FALSE, // initial state non-signaled
NULL); // no name for event
events_[WAKEALL_1] = CreateEvent(NULL, // no security attributes
TRUE, // manual-reset, sticky event
FALSE, // initial state non-signaled
NULL); // no name for event
events_[WAKE] = CreateEvent(NULL, // no security attributes
FALSE, // auto-reset, sticky event
FALSE, // initial state non-signaled
NULL); // no name for event
}
ConditionVariableEventWin::~ConditionVariableEventWin() {
CloseHandle(events_[WAKE]);
CloseHandle(events_[WAKEALL_1]);
CloseHandle(events_[WAKEALL_0]);
DeleteCriticalSection(&num_waiters_crit_sect_);
}
void ConditionVariableEventWin::SleepCS(CriticalSectionWrapper& crit_sect) {
SleepCS(crit_sect, INFINITE);
}
bool ConditionVariableEventWin::SleepCS(CriticalSectionWrapper& crit_sect,
unsigned long max_time_in_ms) {
EnterCriticalSection(&num_waiters_crit_sect_);
// Get the eventID for the event that will be triggered by next
// WakeAll() call and start waiting for it.
const EventWakeUpType eventID =
(WAKEALL_0 == eventID_) ? WAKEALL_1 : WAKEALL_0;
++(num_waiters_[eventID]);
LeaveCriticalSection(&num_waiters_crit_sect_);
CriticalSectionWindows* cs =
static_cast<CriticalSectionWindows*>(&crit_sect);
LeaveCriticalSection(&cs->crit);
HANDLE events[2];
events[0] = events_[WAKE];
events[1] = events_[eventID];
const DWORD result = WaitForMultipleObjects(2, // Wait on 2 events.
events,
FALSE, // Wait for either.
max_time_in_ms);
const bool ret_val = (result != WAIT_TIMEOUT);
EnterCriticalSection(&num_waiters_crit_sect_);
--(num_waiters_[eventID]);
// Last waiter should only be true for WakeAll(). WakeAll() correspond
// to position 1 in events[] -> (result == WAIT_OBJECT_0 + 1)
const bool last_waiter = (result == WAIT_OBJECT_0 + 1) &&
(num_waiters_[eventID] == 0);
LeaveCriticalSection(&num_waiters_crit_sect_);
if (last_waiter) {
// Reset/unset the WakeAll() event since all threads have been
// released.
ResetEvent(events_[eventID]);
}
EnterCriticalSection(&cs->crit);
return ret_val;
}
void ConditionVariableEventWin::Wake() {
EnterCriticalSection(&num_waiters_crit_sect_);
const bool have_waiters = (num_waiters_[WAKEALL_0] > 0) ||
(num_waiters_[WAKEALL_1] > 0);
LeaveCriticalSection(&num_waiters_crit_sect_);
if (have_waiters) {
SetEvent(events_[WAKE]);
}
}
void ConditionVariableEventWin::WakeAll() {
EnterCriticalSection(&num_waiters_crit_sect_);
// Update current WakeAll() event
eventID_ = (WAKEALL_0 == eventID_) ? WAKEALL_1 : WAKEALL_0;
// Trigger current event
const EventWakeUpType eventID = eventID_;
const bool have_waiters = num_waiters_[eventID] > 0;
LeaveCriticalSection(&num_waiters_crit_sect_);
if (have_waiters) {
SetEvent(events_[eventID]);
}
}
} // namespace webrtc