1 /*
2 * libjingle
3 * Copyright 2004--2008, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "talk/base/event.h"
29
30 #if defined(WIN32)
31 #include <windows.h>
32 #elif defined(POSIX)
33 #include <pthread.h>
34 #include <sys/time.h>
35 #include <time.h>
36 #else
37 #error "Must define either WIN32 or POSIX."
38 #endif
39
40 namespace talk_base {
41
42 #if defined(WIN32)
43
Event(bool manual_reset,bool initially_signaled)44 Event::Event(bool manual_reset, bool initially_signaled)
45 : is_manual_reset_(manual_reset),
46 is_initially_signaled_(initially_signaled),
47 event_handle_(NULL) {
48 }
49
EnsureInitialized()50 bool Event::EnsureInitialized() {
51 if (event_handle_ == NULL) {
52 event_handle_ = ::CreateEvent(NULL, // Security attributes.
53 is_manual_reset_,
54 is_initially_signaled_,
55 NULL); // Name.
56 }
57
58 return (event_handle_ != NULL);
59 }
60
~Event()61 Event::~Event() {
62 if (event_handle_ != NULL) {
63 CloseHandle(event_handle_);
64 event_handle_ = NULL;
65 }
66 }
67
Set()68 bool Event::Set() {
69 if (!EnsureInitialized())
70 return false;
71
72 SetEvent(event_handle_);
73 return true;
74 }
75
Reset()76 bool Event::Reset() {
77 if (!EnsureInitialized())
78 return false;
79
80 ResetEvent(event_handle_);
81 return true;
82 }
83
Wait(int cms)84 bool Event::Wait(int cms) {
85 DWORD ms = (cms == kForever)? INFINITE : cms;
86
87 if (!EnsureInitialized())
88 return false;
89 else
90 return (WaitForSingleObject(event_handle_, ms) == WAIT_OBJECT_0);
91 }
92
93 #elif defined(POSIX)
94
95 Event::Event(bool manual_reset, bool initially_signaled)
96 : is_manual_reset_(manual_reset),
97 event_status_(initially_signaled),
98 event_mutex_initialized_(false),
99 event_cond_initialized_(false) {
100 }
101
102 bool Event::EnsureInitialized() {
103 if (!event_mutex_initialized_) {
104 if (pthread_mutex_init(&event_mutex_, NULL) == 0)
105 event_mutex_initialized_ = true;
106 }
107
108 if (!event_cond_initialized_) {
109 if (pthread_cond_init(&event_cond_, NULL) == 0)
110 event_cond_initialized_ = true;
111 }
112
113 return (event_mutex_initialized_ && event_cond_initialized_);
114 }
115
116 Event::~Event() {
117 if (event_mutex_initialized_) {
118 pthread_mutex_destroy(&event_mutex_);
119 event_mutex_initialized_ = false;
120 }
121
122 if (event_cond_initialized_) {
123 pthread_cond_destroy(&event_cond_);
124 event_cond_initialized_ = false;
125 }
126 }
127
128 bool Event::Set() {
129 if (!EnsureInitialized())
130 return false;
131
132 pthread_mutex_lock(&event_mutex_);
133 event_status_ = true;
134 pthread_cond_broadcast(&event_cond_);
135 pthread_mutex_unlock(&event_mutex_);
136 return true;
137 }
138
139 bool Event::Reset() {
140 if (!EnsureInitialized())
141 return false;
142
143 pthread_mutex_lock(&event_mutex_);
144 event_status_ = false;
145 pthread_mutex_unlock(&event_mutex_);
146 return true;
147 }
148
149 bool Event::Wait(int cms) {
150 if (!EnsureInitialized())
151 return false;
152
153 pthread_mutex_lock(&event_mutex_);
154 int error = 0;
155
156 if (cms != kForever) {
157 // Converting from seconds and microseconds (1e-6) plus
158 // milliseconds (1e-3) to seconds and nanoseconds (1e-9).
159
160 struct timeval tv;
161 gettimeofday(&tv, NULL);
162
163 struct timespec ts;
164 ts.tv_sec = tv.tv_sec + (cms / 1000);
165 ts.tv_nsec = tv.tv_usec * 1000 + (cms % 1000) * 1000000;
166
167 // Handle overflow.
168 if (ts.tv_nsec >= 1000000000) {
169 ts.tv_sec++;
170 ts.tv_nsec -= 1000000000;
171 }
172
173 while (!event_status_ && error == 0)
174 error = pthread_cond_timedwait(&event_cond_, &event_mutex_, &ts);
175 } else {
176 while (!event_status_ && error == 0)
177 error = pthread_cond_wait(&event_cond_, &event_mutex_);
178 }
179
180 // NOTE(liulk): Exactly one thread will auto-reset this event. All
181 // the other threads will think it's unsignaled. This seems to be
182 // consistent with auto-reset events in WIN32.
183 if (error == 0 && !is_manual_reset_)
184 event_status_ = false;
185
186 pthread_mutex_unlock(&event_mutex_);
187
188 return (error == 0);
189 }
190
191 #endif
192
193 } // namespace talk_base
194