diff --git a/webrtc/system_wrappers/source/condition_variable.cc b/webrtc/system_wrappers/source/condition_variable.cc index d97f1d7c7f..f36f7e2403 100644 --- a/webrtc/system_wrappers/source/condition_variable.cc +++ b/webrtc/system_wrappers/source/condition_variable.cc @@ -8,21 +8,29 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h" + #if defined(_WIN32) #include -#include "condition_variable_win.h" -#include "condition_variable_wrapper.h" +#include "webrtc/system_wrappers/source/condition_variable_event_win.h" +#include "webrtc/system_wrappers/source/condition_variable_native_win.h" #elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) #include -#include "condition_variable_posix.h" -#include "condition_variable_wrapper.h" +#include "webrtc/system_wrappers/source/condition_variable_posix.h" #endif namespace webrtc { ConditionVariableWrapper* ConditionVariableWrapper::CreateConditionVariable() { #if defined(_WIN32) - return new ConditionVariableWindows; + // Try to create native condition variable implementation. + ConditionVariableWrapper* ret_val = ConditionVariableNativeWin::Create(); + if (!ret_val) { + // Native condition variable implementation does not exist. Create generic + // condition variable based on events. + ret_val = new ConditionVariableEventWin(); + } + return ret_val; #elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) return ConditionVariablePosix::Create(); #else diff --git a/webrtc/system_wrappers/source/condition_variable_event_win.cc b/webrtc/system_wrappers/source/condition_variable_event_win.cc new file mode 100644 index 0000000000..20efaf039b --- /dev/null +++ b/webrtc/system_wrappers/source/condition_variable_event_win.cc @@ -0,0 +1,127 @@ +/* + * 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(&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 diff --git a/webrtc/system_wrappers/source/condition_variable_event_win.h b/webrtc/system_wrappers/source/condition_variable_event_win.h new file mode 100644 index 0000000000..fce45d3daa --- /dev/null +++ b/webrtc/system_wrappers/source/condition_variable_event_win.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_EVENT_WIN_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_EVENT_WIN_H_ + +#include + +#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h" + +namespace webrtc { + +class ConditionVariableEventWin : public ConditionVariableWrapper { + public: + ConditionVariableEventWin(); + virtual ~ConditionVariableEventWin(); + + void SleepCS(CriticalSectionWrapper& crit_sect); + bool SleepCS(CriticalSectionWrapper& crit_sect, unsigned long max_time_inMS); + void Wake(); + void WakeAll(); + + private: + enum EventWakeUpType { + WAKEALL_0 = 0, + WAKEALL_1 = 1, + WAKE = 2, + EVENT_COUNT = 3 + }; + + unsigned int num_waiters_[2]; + EventWakeUpType eventID_; + CRITICAL_SECTION num_waiters_crit_sect_; + HANDLE events_[EVENT_COUNT]; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_EVENT_WIN_H_ diff --git a/webrtc/system_wrappers/source/condition_variable_native_win.cc b/webrtc/system_wrappers/source/condition_variable_native_win.cc new file mode 100644 index 0000000000..d97c6fe0cb --- /dev/null +++ b/webrtc/system_wrappers/source/condition_variable_native_win.cc @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/system_wrappers/interface/trace.h" +#include "webrtc/system_wrappers/source/condition_variable_native_win.h" +#include "webrtc/system_wrappers/source/critical_section_win.h" + +namespace webrtc { + +static HMODULE library = NULL; + +PInitializeConditionVariable PInitializeConditionVariable_; +PSleepConditionVariableCS PSleepConditionVariableCS_; +PWakeConditionVariable PWakeConditionVariable_; +PWakeAllConditionVariable PWakeAllConditionVariable_; + +typedef void (WINAPI *PInitializeConditionVariable)(PCONDITION_VARIABLE); +typedef BOOL (WINAPI *PSleepConditionVariableCS)(PCONDITION_VARIABLE, + PCRITICAL_SECTION, DWORD); +typedef void (WINAPI *PWakeConditionVariable)(PCONDITION_VARIABLE); +typedef void (WINAPI *PWakeAllConditionVariable)(PCONDITION_VARIABLE); + +ConditionVariableNativeWin::ConditionVariableNativeWin() { +} + +ConditionVariableNativeWin::~ConditionVariableNativeWin() { +} + +ConditionVariableWrapper* ConditionVariableNativeWin::Create() { + ConditionVariableNativeWin* ret_val = new ConditionVariableNativeWin(); + if (!ret_val->Init()) { + delete ret_val; + return NULL; + } + return ret_val; +} + +bool ConditionVariableNativeWin::Init() { + bool win_support_condition_variables_primitive = true; + if (!library) { + // Native implementation is supported on Vista+. + library = LoadLibrary(TEXT("Kernel32.dll")); + // TODO(henrike): this code results in an attempt to load the above dll + // every time the previous attempt failed. Only try to load once. + if (library) { + // TODO(henrike): not thread safe as reading and writing to library is not + // serialized. Fix. + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Loaded Kernel.dll"); + + PInitializeConditionVariable_ = + (PInitializeConditionVariable) GetProcAddress( + library, "InitializeConditionVariable"); + PSleepConditionVariableCS_ = (PSleepConditionVariableCS) GetProcAddress( + library, "SleepConditionVariableCS"); + PWakeConditionVariable_ = (PWakeConditionVariable) GetProcAddress( + library, "WakeConditionVariable"); + PWakeAllConditionVariable_ = (PWakeAllConditionVariable) GetProcAddress( + library, "WakeAllConditionVariable"); + + if (PInitializeConditionVariable_ && PSleepConditionVariableCS_ + && PWakeConditionVariable_ && PWakeAllConditionVariable_) { + WEBRTC_TRACE( + kTraceStateInfo, kTraceUtility, -1, + "Loaded native condition variables"); + } else { + win_support_condition_variables_primitive = false; + } + } + } + if (!win_support_condition_variables_primitive) { + return false; + } + PInitializeConditionVariable_(&condition_variable_); + return true; +} + +void ConditionVariableNativeWin::SleepCS(CriticalSectionWrapper& crit_sect) { + SleepCS(crit_sect, INFINITE); +} + +bool ConditionVariableNativeWin::SleepCS(CriticalSectionWrapper& crit_sect, + unsigned long max_time_in_ms) { + CriticalSectionWindows* cs = + static_cast(&crit_sect); + BOOL ret_val = PSleepConditionVariableCS_(&condition_variable_, + &(cs->crit), max_time_in_ms); + return ret_val != 0; +} + +void ConditionVariableNativeWin::Wake() { + PWakeConditionVariable_(&condition_variable_); +} + +void ConditionVariableNativeWin::WakeAll() { + PWakeAllConditionVariable_(&condition_variable_); +} + +} // namespace webrtc diff --git a/webrtc/system_wrappers/source/condition_variable_win.h b/webrtc/system_wrappers/source/condition_variable_native_win.h similarity index 57% rename from webrtc/system_wrappers/source/condition_variable_win.h rename to webrtc/system_wrappers/source/condition_variable_native_win.h index 6f90ead225..1fbce37387 100644 --- a/webrtc/system_wrappers/source/condition_variable_win.h +++ b/webrtc/system_wrappers/source/condition_variable_native_win.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source @@ -8,12 +8,12 @@ * be found in the AUTHORS file in the root of the source tree. */ -#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_WIN_H_ -#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_WIN_H_ +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_NATIVE_WIN_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_NATIVE_WIN_H_ #include -#include "condition_variable_wrapper.h" +#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h" namespace webrtc { @@ -31,10 +31,10 @@ typedef BOOL (WINAPI* PSleepConditionVariableCS)(PCONDITION_VARIABLE, typedef void (WINAPI* PWakeConditionVariable)(PCONDITION_VARIABLE); typedef void (WINAPI* PWakeAllConditionVariable)(PCONDITION_VARIABLE); -class ConditionVariableWindows : public ConditionVariableWrapper { +class ConditionVariableNativeWin : public ConditionVariableWrapper { public: - ConditionVariableWindows(); - ~ConditionVariableWindows(); + static ConditionVariableWrapper* Create(); + virtual ~ConditionVariableNativeWin(); void SleepCS(CriticalSectionWrapper& crit_sect); bool SleepCS(CriticalSectionWrapper& crit_sect, unsigned long max_time_inMS); @@ -42,24 +42,13 @@ class ConditionVariableWindows : public ConditionVariableWrapper { void WakeAll(); private: - enum EventWakeUpType { - WAKEALL_0 = 0, - WAKEALL_1 = 1, - WAKE = 2, - EVENT_COUNT = 3 - }; + ConditionVariableNativeWin(); - private: - // Native support for Windows Vista+ - static bool win_support_condition_variables_primitive_; - CONDITION_VARIABLE condition_variable_; + bool Init(); - unsigned int num_waiters_[2]; - EventWakeUpType eventID_; - CRITICAL_SECTION num_waiters_crit_sect_; - HANDLE events_[EVENT_COUNT]; + CONDITION_VARIABLE condition_variable_; }; -} // namespace webrtc +} // namespace webrtc -#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_WIN_H_ +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_NATIVE_WIN_H_ diff --git a/webrtc/system_wrappers/source/condition_variable_win.cc b/webrtc/system_wrappers/source/condition_variable_win.cc deleted file mode 100644 index 98a1e8865f..0000000000 --- a/webrtc/system_wrappers/source/condition_variable_win.cc +++ /dev/null @@ -1,198 +0,0 @@ -/* - * 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. - */ - -// TODO (hellner): probably nicer to split up native and generic -// implementation into two different files - -#include "condition_variable_win.h" -#include "critical_section_win.h" -#include "trace.h" - -namespace webrtc { - -bool ConditionVariableWindows::win_support_condition_variables_primitive_ = - false; -static HMODULE library = NULL; - -PInitializeConditionVariable PInitializeConditionVariable_; -PSleepConditionVariableCS PSleepConditionVariableCS_; -PWakeConditionVariable PWakeConditionVariable_; -PWakeAllConditionVariable PWakeAllConditionVariable_; - -typedef void (WINAPI *PInitializeConditionVariable)(PCONDITION_VARIABLE); -typedef BOOL (WINAPI *PSleepConditionVariableCS)(PCONDITION_VARIABLE, - PCRITICAL_SECTION, DWORD); -typedef void (WINAPI *PWakeConditionVariable)(PCONDITION_VARIABLE); -typedef void (WINAPI *PWakeAllConditionVariable)(PCONDITION_VARIABLE); - -ConditionVariableWindows::ConditionVariableWindows() - : eventID_(WAKEALL_0) { - if (!library) { - // Use native implementation if supported (i.e Vista+) - library = LoadLibrary(TEXT("Kernel32.dll")); - if (library) { - WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Loaded Kernel.dll"); - - PInitializeConditionVariable_ = - (PInitializeConditionVariable) GetProcAddress( - library, "InitializeConditionVariable"); - PSleepConditionVariableCS_ = (PSleepConditionVariableCS) GetProcAddress( - library, "SleepConditionVariableCS"); - PWakeConditionVariable_ = (PWakeConditionVariable) GetProcAddress( - library, "WakeConditionVariable"); - PWakeAllConditionVariable_ = (PWakeAllConditionVariable) GetProcAddress( - library, "WakeAllConditionVariable"); - - if (PInitializeConditionVariable_ && PSleepConditionVariableCS_ - && PWakeConditionVariable_ && PWakeAllConditionVariable_) { - WEBRTC_TRACE( - kTraceStateInfo, kTraceUtility, -1, - "Loaded native condition variables"); - win_support_condition_variables_primitive_ = true; - } - } - } - - if (win_support_condition_variables_primitive_) { - PInitializeConditionVariable_(&condition_variable_); - - events_[WAKEALL_0] = NULL; - events_[WAKEALL_1] = NULL; - events_[WAKE] = NULL; - - } else { - 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 - } -} - -ConditionVariableWindows::~ConditionVariableWindows() { - if (!win_support_condition_variables_primitive_) { - CloseHandle(events_[WAKE]); - CloseHandle(events_[WAKEALL_1]); - CloseHandle(events_[WAKEALL_0]); - - DeleteCriticalSection(&num_waiters_crit_sect_); - } -} - -void ConditionVariableWindows::SleepCS(CriticalSectionWrapper& crit_sect) { - SleepCS(crit_sect, INFINITE); -} - -bool ConditionVariableWindows::SleepCS(CriticalSectionWrapper& crit_sect, - unsigned long max_time_in_ms) { - CriticalSectionWindows* cs = - reinterpret_cast(&crit_sect); - - if (win_support_condition_variables_primitive_) { - BOOL ret_val = PSleepConditionVariableCS_( - &condition_variable_, &(cs->crit), max_time_in_ms); - return (ret_val == 0) ? false : true; - } else { - 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_); - - 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 ConditionVariableWindows::Wake() { - if (win_support_condition_variables_primitive_) { - PWakeConditionVariable_(&condition_variable_); - } else { - 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 ConditionVariableWindows::WakeAll() { - if (win_support_condition_variables_primitive_) { - PWakeAllConditionVariable_(&condition_variable_); - } else { - 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 diff --git a/webrtc/system_wrappers/source/critical_section_win.h b/webrtc/system_wrappers/source/critical_section_win.h index 01bb52c4a2..760cc10f1e 100644 --- a/webrtc/system_wrappers/source/critical_section_win.h +++ b/webrtc/system_wrappers/source/critical_section_win.h @@ -29,7 +29,8 @@ class CriticalSectionWindows : public CriticalSectionWrapper { private: CRITICAL_SECTION crit; - friend class ConditionVariableWindows; + friend class ConditionVariableEventWin; + friend class ConditionVariableNativeWin; }; } // namespace webrtc diff --git a/webrtc/system_wrappers/source/system_wrappers.gyp b/webrtc/system_wrappers/source/system_wrappers.gyp index fca9bf7e0c..36aa7d6ea9 100644 --- a/webrtc/system_wrappers/source/system_wrappers.gyp +++ b/webrtc/system_wrappers/source/system_wrappers.gyp @@ -61,8 +61,10 @@ 'condition_variable.cc', 'condition_variable_posix.cc', 'condition_variable_posix.h', - 'condition_variable_win.cc', - 'condition_variable_win.h', + 'condition_variable_event_win.cc', + 'condition_variable_event_win.h', + 'condition_variable_native_win.cc', + 'condition_variable_native_win.h', 'cpu.cc', 'cpu_no_op.cc', 'cpu_info.cc',