1/*
2Source:
3http://www1.cse.wustl.edu/~schmidt/ACE-copying.html
4
5License:
6Copyright and Licensing Information for ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM),
7and CoSMIC(TM)
8
9ACE(TM), TAO(TM), CIAO(TM), DAnCE>(TM), and CoSMIC(TM) (henceforth referred to
10as "DOC software") are copyrighted by Douglas C. Schmidt and his research
11group at Washington University, University of California, Irvine, and
12Vanderbilt University, Copyright (c) 1993-2009, all rights reserved. Since DOC
13software is open-source, freely available software, you are free to use,
14modify, copy, and distribute--perpetually and irrevocably--the DOC software
15source code and object code produced from the source, as well as copy and
16distribute modified versions of this software. You must, however, include this
17copyright statement along with any code built using DOC software that you
18release. No copyright statement needs to be provided if you just ship binary
19executables of your software products.
20You can use DOC software in commercial and/or binary software releases and are
21under no obligation to redistribute any of your source code that is built
22using DOC software. Note, however, that you may not misappropriate the DOC
23software code, such as copyrighting it yourself or claiming authorship of the
24DOC software code, in a way that will prevent DOC software from being
25distributed freely using an open-source development model. You needn't inform
26anyone that you're using DOC software in your software, though we encourage
27you to let us know so we can promote your project in the DOC software success
28stories.
29
30The ACE, TAO, CIAO, DAnCE, and CoSMIC web sites are maintained by the DOC
31Group at the Institute for Software Integrated Systems (ISIS) and the Center
32for Distributed Object Computing of Washington University, St. Louis for the
33development of open-source software as part of the open-source software
34community. Submissions are provided by the submitter ``as is'' with no
35warranties whatsoever, including any warranty of merchantability,
36noninfringement of third party intellectual property, or fitness for any
37particular purpose. In no event shall the submitter be liable for any direct,
38indirect, special, exemplary, punitive, or consequential damages, including
39without limitation, lost profits, even if advised of the possibility of such
40damages. Likewise, DOC software is provided as is with no warranties of any
41kind, including the warranties of design, merchantability, and fitness for a
42particular purpose, noninfringement, or arising from a course of dealing,
43usage or trade practice. Washington University, UC Irvine, Vanderbilt
44University, their employees, and students shall have no liability with respect
45to the infringement of copyrights, trade secrets or any patents by DOC
46software or any part thereof. Moreover, in no event will Washington
47University, UC Irvine, or Vanderbilt University, their employees, or students
48be liable for any lost revenue or profits or other special, indirect and
49consequential damages.
50
51DOC software is provided with no support and without any obligation on the
52part of Washington University, UC Irvine, Vanderbilt University, their
53employees, or students to assist in its use, correction, modification, or
54enhancement. A number of companies around the world provide commercial support
55for DOC software, however. DOC software is Y2K-compliant, as long as the
56underlying OS platform is Y2K-compliant. Likewise, DOC software is compliant
57with the new US daylight savings rule passed by Congress as "The Energy Policy
58Act of 2005," which established new daylight savings times (DST) rules for the
59United States that expand DST as of March 2007. Since DOC software obtains
60time/date and calendaring information from operating systems users will not be
61affected by the new DST rules as long as they upgrade their operating systems
62accordingly.
63
64The names ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), CoSMIC(TM), Washington
65University, UC Irvine, and Vanderbilt University, may not be used to endorse
66or promote products or services derived from this source without express
67written permission from Washington University, UC Irvine, or Vanderbilt
68University. This license grants no permission to call products or services
69derived from this source ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), or CoSMIC(TM),
70nor does it grant permission for the name Washington University, UC Irvine, or
71Vanderbilt University to appear in their names.
72*/
73
74/*
75 *  This source code contain modifications to the original source code
76 *  which can be found here:
77 *  http://www.cs.wustl.edu/~schmidt/win32-cv-1.html (section 3.2).
78 *  Modifications:
79 *  1) Dynamic detection of native support for condition variables.
80 *  2) Use of WebRTC defined types and classes. Renaming of some functions.
81 *  3) Introduction of a second event for wake all functionality. This prevents
82 *     a thread from spinning on the same condition variable, preventing other
83 *     threads from waking up.
84 */
85
86#include "webrtc/system_wrappers/source/condition_variable_event_win.h"
87#include "webrtc/system_wrappers/source/critical_section_win.h"
88
89namespace webrtc {
90
91ConditionVariableEventWin::ConditionVariableEventWin() : eventID_(WAKEALL_0) {
92  memset(&num_waiters_[0], 0, sizeof(num_waiters_));
93
94  InitializeCriticalSection(&num_waiters_crit_sect_);
95
96  events_[WAKEALL_0] = CreateEvent(NULL,  // no security attributes
97                                   TRUE,  // manual-reset, sticky event
98                                   FALSE,  // initial state non-signaled
99                                   NULL);  // no name for event
100
101  events_[WAKEALL_1] = CreateEvent(NULL,  // no security attributes
102                                   TRUE,  // manual-reset, sticky event
103                                   FALSE,  // initial state non-signaled
104                                   NULL);  // no name for event
105
106  events_[WAKE] = CreateEvent(NULL,  // no security attributes
107                              FALSE,  // auto-reset, sticky event
108                              FALSE,  // initial state non-signaled
109                              NULL);  // no name for event
110}
111
112ConditionVariableEventWin::~ConditionVariableEventWin() {
113  CloseHandle(events_[WAKE]);
114  CloseHandle(events_[WAKEALL_1]);
115  CloseHandle(events_[WAKEALL_0]);
116
117  DeleteCriticalSection(&num_waiters_crit_sect_);
118}
119
120void ConditionVariableEventWin::SleepCS(CriticalSectionWrapper& crit_sect) {
121  SleepCS(crit_sect, INFINITE);
122}
123
124bool ConditionVariableEventWin::SleepCS(CriticalSectionWrapper& crit_sect,
125                                        unsigned long max_time_in_ms) {
126  EnterCriticalSection(&num_waiters_crit_sect_);
127
128  // Get the eventID for the event that will be triggered by next
129  // WakeAll() call and start waiting for it.
130  const EventWakeUpType eventID =
131      (WAKEALL_0 == eventID_) ? WAKEALL_1 : WAKEALL_0;
132
133  ++(num_waiters_[eventID]);
134  LeaveCriticalSection(&num_waiters_crit_sect_);
135
136  CriticalSectionWindows* cs =
137      static_cast<CriticalSectionWindows*>(&crit_sect);
138  LeaveCriticalSection(&cs->crit);
139  HANDLE events[2];
140  events[0] = events_[WAKE];
141  events[1] = events_[eventID];
142  const DWORD result = WaitForMultipleObjects(2,  // Wait on 2 events.
143                                              events,
144                                              FALSE,  // Wait for either.
145                                              max_time_in_ms);
146
147  const bool ret_val = (result != WAIT_TIMEOUT);
148
149  EnterCriticalSection(&num_waiters_crit_sect_);
150  --(num_waiters_[eventID]);
151
152  // Last waiter should only be true for WakeAll(). WakeAll() correspond
153  // to position 1 in events[] -> (result == WAIT_OBJECT_0 + 1)
154  const bool last_waiter = (result == WAIT_OBJECT_0 + 1) &&
155      (num_waiters_[eventID] == 0);
156  LeaveCriticalSection(&num_waiters_crit_sect_);
157
158  if (last_waiter) {
159    // Reset/unset the WakeAll() event since all threads have been
160    // released.
161    ResetEvent(events_[eventID]);
162  }
163
164  EnterCriticalSection(&cs->crit);
165  return ret_val;
166}
167
168void ConditionVariableEventWin::Wake() {
169  EnterCriticalSection(&num_waiters_crit_sect_);
170  const bool have_waiters = (num_waiters_[WAKEALL_0] > 0) ||
171      (num_waiters_[WAKEALL_1] > 0);
172  LeaveCriticalSection(&num_waiters_crit_sect_);
173
174  if (have_waiters) {
175    SetEvent(events_[WAKE]);
176  }
177}
178
179void ConditionVariableEventWin::WakeAll() {
180  EnterCriticalSection(&num_waiters_crit_sect_);
181
182  // Update current WakeAll() event
183  eventID_ = (WAKEALL_0 == eventID_) ? WAKEALL_1 : WAKEALL_0;
184
185  // Trigger current event
186  const EventWakeUpType eventID = eventID_;
187  const bool have_waiters = num_waiters_[eventID] > 0;
188  LeaveCriticalSection(&num_waiters_crit_sect_);
189
190  if (have_waiters) {
191    SetEvent(events_[eventID]);
192  }
193}
194
195}  // namespace webrtc
196