blob: b77b9023c29125c0f0776fc67b0cb8b53cb90bdb [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
ajm@google.comb5c49ff2011-08-01 17:04:04 +000011#include "event_posix.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
13#include <errno.h>
14#include <pthread.h>
15#include <signal.h>
16#include <stdio.h>
17#include <string.h>
18#include <sys/time.h>
19#include <unistd.h>
20
21namespace webrtc {
22const long int E6 = 1000000;
23const long int E9 = 1000 * E6;
24
ajm@google.comb5c49ff2011-08-01 17:04:04 +000025EventWrapper* EventPosix::Create()
niklase@google.com470e71d2011-07-07 08:21:25 +000026{
ajm@google.comb5c49ff2011-08-01 17:04:04 +000027 EventPosix* ptr = new EventPosix;
niklase@google.com470e71d2011-07-07 08:21:25 +000028 if (!ptr)
29 {
30 return NULL;
31 }
32
33 const int error = ptr->Construct();
34 if (error)
35 {
36 delete ptr;
37 return NULL;
38 }
39 return ptr;
40}
41
42
ajm@google.comb5c49ff2011-08-01 17:04:04 +000043EventPosix::EventPosix()
niklase@google.com470e71d2011-07-07 08:21:25 +000044 : _timerThread(0),
45 _timerEvent(0),
46 _periodic(false),
47 _time(0),
48 _count(0),
49 _state(kDown)
50{
51}
52
ajm@google.comb5c49ff2011-08-01 17:04:04 +000053int EventPosix::Construct()
niklase@google.com470e71d2011-07-07 08:21:25 +000054{
55 // Set start time to zero
56 memset(&_tCreate, 0, sizeof(_tCreate));
57
58 int result = pthread_mutex_init(&mutex, 0);
59 if (result != 0)
60 {
61 return -1;
62 }
63#ifdef WEBRTC_CLOCK_TYPE_REALTIME
64 result = pthread_cond_init(&cond, 0);
65 if (result != 0)
66 {
67 return -1;
68 }
69#else
70 pthread_condattr_t condAttr;
71 result = pthread_condattr_init(&condAttr);
72 if (result != 0)
73 {
74 return -1;
75 }
76 result = pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC);
77 if (result != 0)
78 {
79 return -1;
80 }
81 result = pthread_cond_init(&cond, &condAttr);
82 if (result != 0)
83 {
84 return -1;
85 }
86 result = pthread_condattr_destroy(&condAttr);
87 if (result != 0)
88 {
89 return -1;
90 }
91#endif
92 return 0;
93}
94
ajm@google.comb5c49ff2011-08-01 17:04:04 +000095EventPosix::~EventPosix()
niklase@google.com470e71d2011-07-07 08:21:25 +000096{
97 StopTimer();
98 pthread_cond_destroy(&cond);
99 pthread_mutex_destroy(&mutex);
100}
101
ajm@google.comb5c49ff2011-08-01 17:04:04 +0000102bool EventPosix::Reset()
niklase@google.com470e71d2011-07-07 08:21:25 +0000103{
104 if (0 != pthread_mutex_lock(&mutex))
105 {
106 return false;
107 }
108 _state = kDown;
109 pthread_mutex_unlock(&mutex);
110 return true;
111}
112
ajm@google.comb5c49ff2011-08-01 17:04:04 +0000113bool EventPosix::Set()
niklase@google.com470e71d2011-07-07 08:21:25 +0000114{
115 if (0 != pthread_mutex_lock(&mutex))
116 {
117 return false;
118 }
119 _state = kUp;
120 // Release all waiting threads
121 pthread_cond_broadcast(&cond);
122 pthread_mutex_unlock(&mutex);
123 return true;
124}
125
ajm@google.comb5c49ff2011-08-01 17:04:04 +0000126EventTypeWrapper EventPosix::Wait(unsigned long timeout)
niklase@google.com470e71d2011-07-07 08:21:25 +0000127{
128 int retVal = 0;
129 if (0 != pthread_mutex_lock(&mutex))
130 {
131 return kEventError;
132 }
133
134 if (kDown == _state)
135 {
136 if (WEBRTC_EVENT_INFINITE != timeout)
137 {
138 timespec tEnd;
139#ifndef WEBRTC_MAC
140#ifdef WEBRTC_CLOCK_TYPE_REALTIME
141 clock_gettime(CLOCK_REALTIME, &tEnd);
142#else
143 clock_gettime(CLOCK_MONOTONIC, &tEnd);
144#endif
145#else
146 timeval tVal;
147 struct timezone tZone;
148 tZone.tz_minuteswest = 0;
149 tZone.tz_dsttime = 0;
150 gettimeofday(&tVal,&tZone);
151 TIMEVAL_TO_TIMESPEC(&tVal,&tEnd);
152#endif
153 tEnd.tv_sec += timeout / 1000;
154 tEnd.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6;
155
156 if (tEnd.tv_nsec >= E9)
157 {
158 tEnd.tv_sec++;
159 tEnd.tv_nsec -= E9;
160 }
161 retVal = pthread_cond_timedwait(&cond, &mutex, &tEnd);
162 } else {
163 retVal = pthread_cond_wait(&cond, &mutex);
164 }
165 }
166
167 _state = kDown;
168 pthread_mutex_unlock(&mutex);
169
170 switch(retVal)
171 {
172 case 0:
173 return kEventSignaled;
174 case ETIMEDOUT:
175 return kEventTimeout;
176 default:
177 return kEventError;
178 }
179}
180
ajm@google.comb5c49ff2011-08-01 17:04:04 +0000181EventTypeWrapper EventPosix::Wait(timespec& tPulse)
niklase@google.com470e71d2011-07-07 08:21:25 +0000182{
183 int retVal = 0;
184 if (0 != pthread_mutex_lock(&mutex))
185 {
186 return kEventError;
187 }
188
189 if (kUp != _state)
190 {
191 retVal = pthread_cond_timedwait(&cond, &mutex, &tPulse);
192 }
193 _state = kDown;
194
195 pthread_mutex_unlock(&mutex);
196
197 switch(retVal)
198 {
199 case 0:
200 return kEventSignaled;
201 case ETIMEDOUT:
202 return kEventTimeout;
203 default:
204 return kEventError;
205 }
206}
207
ajm@google.comb5c49ff2011-08-01 17:04:04 +0000208bool EventPosix::StartTimer(bool periodic, unsigned long time)
niklase@google.com470e71d2011-07-07 08:21:25 +0000209{
210 if (_timerThread)
211 {
212 if(_periodic)
213 {
214 // Timer already started.
215 return false;
216 } else {
217 // New one shot timer
218 _time = time;
219 _tCreate.tv_sec = 0;
220 _timerEvent->Set();
221 return true;
222 }
223 }
224
225 // Start the timer thread
ajm@google.comb5c49ff2011-08-01 17:04:04 +0000226 _timerEvent = static_cast<EventPosix*>(EventWrapper::Create());
niklase@google.com470e71d2011-07-07 08:21:25 +0000227 const char* threadName = "WebRtc_event_timer_thread";
228 _timerThread = ThreadWrapper::CreateThread(Run, this, kRealtimePriority,
229 threadName);
230 _periodic = periodic;
231 _time = time;
232 unsigned int id = 0;
233 if (_timerThread->Start(id))
234 {
235 return true;
236 }
237 return false;
238}
239
ajm@google.comb5c49ff2011-08-01 17:04:04 +0000240bool EventPosix::Run(ThreadObj obj)
niklase@google.com470e71d2011-07-07 08:21:25 +0000241{
ajm@google.comb5c49ff2011-08-01 17:04:04 +0000242 return static_cast<EventPosix*>(obj)->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +0000243}
244
ajm@google.comb5c49ff2011-08-01 17:04:04 +0000245bool EventPosix::Process()
niklase@google.com470e71d2011-07-07 08:21:25 +0000246{
247 if (_tCreate.tv_sec == 0)
248 {
249#ifndef WEBRTC_MAC
250#ifdef WEBRTC_CLOCK_TYPE_REALTIME
251 clock_gettime(CLOCK_REALTIME, &_tCreate);
252#else
253 clock_gettime(CLOCK_MONOTONIC, &_tCreate);
254#endif
255#else
256 timeval tVal;
257 struct timezone tZone;
258 tZone.tz_minuteswest = 0;
259 tZone.tz_dsttime = 0;
260 gettimeofday(&tVal,&tZone);
261 TIMEVAL_TO_TIMESPEC(&tVal,&_tCreate);
262#endif
263 _count=0;
264 }
265
266 timespec tEnd;
267 unsigned long long time = _time * ++_count;
268 tEnd.tv_sec = _tCreate.tv_sec + time/1000;
269 tEnd.tv_nsec = _tCreate.tv_nsec + (time - (time/1000)*1000)*E6;
270
271 if ( tEnd.tv_nsec >= E9 )
272 {
273 tEnd.tv_sec++;
274 tEnd.tv_nsec -= E9;
275 }
276
277 switch(_timerEvent->Wait(tEnd))
278 {
279 case kEventSignaled:
280 return true;
281 case kEventError:
282 return false;
283 case kEventTimeout:
284 break;
285 }
286 if(_periodic || _count==1)
287 {
288 Set();
289 }
290 return true;
291}
292
ajm@google.comb5c49ff2011-08-01 17:04:04 +0000293bool EventPosix::StopTimer()
niklase@google.com470e71d2011-07-07 08:21:25 +0000294{
295 if(_timerThread)
296 {
297 _timerThread->SetNotAlive();
298 }
299 if (_timerEvent)
300 {
301 _timerEvent->Set();
302 }
303 if (_timerThread)
304 {
305 if(!_timerThread->Stop())
306 {
307 return false;
308 }
309
310 delete _timerThread;
311 _timerThread = 0;
312 }
313 if (_timerEvent)
314 {
315 delete _timerEvent;
316 _timerEvent = 0;
317 }
318
319 // Set time to zero to force new reference time for the timer.
320 memset(&_tCreate, 0, sizeof(_tCreate));
321 _count=0;
322 return true;
323}
324} // namespace webrtc