• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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