blob: 5a2be36de05b3c4ee477b6c3040a0b3548bd4990 [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
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000011#include "webrtc/system_wrappers/source/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 {
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000022
niklase@google.com470e71d2011-07-07 08:21:25 +000023const long int E6 = 1000000;
24const long int E9 = 1000 * E6;
25
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000026EventWrapper* EventPosix::Create() {
27 EventPosix* ptr = new EventPosix;
28 if (!ptr) {
29 return NULL;
30 }
niklase@google.com470e71d2011-07-07 08:21:25 +000031
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000032 const int error = ptr->Construct();
33 if (error) {
34 delete ptr;
35 return NULL;
36 }
37 return ptr;
niklase@google.com470e71d2011-07-07 08:21:25 +000038}
39
ajm@google.comb5c49ff2011-08-01 17:04:04 +000040EventPosix::EventPosix()
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000041 : timer_thread_(0),
42 timer_event_(0),
43 periodic_(false),
44 time_(0),
45 count_(0),
46 state_(kDown) {
niklase@google.com470e71d2011-07-07 08:21:25 +000047}
48
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000049int EventPosix::Construct() {
50 // Set start time to zero
51 memset(&created_at_, 0, sizeof(created_at_));
niklase@google.com470e71d2011-07-07 08:21:25 +000052
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +000053 pthread_mutexattr_t attr;
54 pthread_mutexattr_init(&attr);
55 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
56 int result = pthread_mutex_init(&mutex_, &attr);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000057 if (result != 0) {
58 return -1;
59 }
niklase@google.com470e71d2011-07-07 08:21:25 +000060#ifdef WEBRTC_CLOCK_TYPE_REALTIME
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000061 result = pthread_cond_init(&cond_, 0);
62 if (result != 0) {
63 return -1;
64 }
niklase@google.com470e71d2011-07-07 08:21:25 +000065#else
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000066 pthread_condattr_t cond_attr;
67 result = pthread_condattr_init(&cond_attr);
68 if (result != 0) {
69 return -1;
70 }
71 result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
72 if (result != 0) {
73 return -1;
74 }
75 result = pthread_cond_init(&cond_, &cond_attr);
76 if (result != 0) {
77 return -1;
78 }
79 result = pthread_condattr_destroy(&cond_attr);
80 if (result != 0) {
81 return -1;
82 }
niklase@google.com470e71d2011-07-07 08:21:25 +000083#endif
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000084 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000085}
86
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000087EventPosix::~EventPosix() {
88 StopTimer();
89 pthread_cond_destroy(&cond_);
90 pthread_mutex_destroy(&mutex_);
niklase@google.com470e71d2011-07-07 08:21:25 +000091}
92
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000093bool EventPosix::Reset() {
94 if (0 != pthread_mutex_lock(&mutex_)) {
niklase@google.com470e71d2011-07-07 08:21:25 +000095 return false;
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000096 }
97 state_ = kDown;
98 pthread_mutex_unlock(&mutex_);
99 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000100}
101
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000102bool EventPosix::Set() {
103 if (0 != pthread_mutex_lock(&mutex_)) {
104 return false;
105 }
106 state_ = kUp;
107 // Release all waiting threads
108 pthread_cond_broadcast(&cond_);
109 pthread_mutex_unlock(&mutex_);
110 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000111}
112
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000113EventTypeWrapper EventPosix::Wait(unsigned long timeout) {
114 int ret_val = 0;
115 if (0 != pthread_mutex_lock(&mutex_)) {
116 return kEventError;
117 }
118
119 if (kDown == state_) {
120 if (WEBRTC_EVENT_INFINITE != timeout) {
121 timespec end_at;
niklase@google.com470e71d2011-07-07 08:21:25 +0000122#ifndef WEBRTC_MAC
123#ifdef WEBRTC_CLOCK_TYPE_REALTIME
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000124 clock_gettime(CLOCK_REALTIME, &end_at);
niklase@google.com470e71d2011-07-07 08:21:25 +0000125#else
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000126 clock_gettime(CLOCK_MONOTONIC, &end_at);
niklase@google.com470e71d2011-07-07 08:21:25 +0000127#endif
128#else
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000129 timeval value;
130 struct timezone time_zone;
131 time_zone.tz_minuteswest = 0;
132 time_zone.tz_dsttime = 0;
133 gettimeofday(&value, &time_zone);
134 TIMEVAL_TO_TIMESPEC(&value, &end_at);
niklase@google.com470e71d2011-07-07 08:21:25 +0000135#endif
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000136 end_at.tv_sec += timeout / 1000;
137 end_at.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6;
138
139 if (end_at.tv_nsec >= E9) {
140 end_at.tv_sec++;
141 end_at.tv_nsec -= E9;
142 }
143 ret_val = pthread_cond_timedwait(&cond_, &mutex_, &end_at);
144 } else {
145 ret_val = pthread_cond_wait(&cond_, &mutex_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000146 }
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000147 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000148
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000149 state_ = kDown;
150 pthread_mutex_unlock(&mutex_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000151
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000152 switch (ret_val) {
153 case 0:
154 return kEventSignaled;
155 case ETIMEDOUT:
156 return kEventTimeout;
157 default:
158 return kEventError;
159 }
160}
161
162EventTypeWrapper EventPosix::Wait(timespec& wake_at) {
163 int ret_val = 0;
164 if (0 != pthread_mutex_lock(&mutex_)) {
165 return kEventError;
166 }
167
168 if (kUp != state_) {
169 ret_val = pthread_cond_timedwait(&cond_, &mutex_, &wake_at);
170 }
171 state_ = kDown;
172
173 pthread_mutex_unlock(&mutex_);
174
175 switch (ret_val) {
176 case 0:
177 return kEventSignaled;
178 case ETIMEDOUT:
179 return kEventTimeout;
180 default:
181 return kEventError;
182 }
183}
184
185bool EventPosix::StartTimer(bool periodic, unsigned long time) {
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000186 pthread_mutex_lock(&mutex_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000187 if (timer_thread_) {
188 if (periodic_) {
189 // Timer already started.
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000190 pthread_mutex_unlock(&mutex_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000191 return false;
192 } else {
193 // New one shot timer
194 time_ = time;
195 created_at_.tv_sec = 0;
196 timer_event_->Set();
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000197 pthread_mutex_unlock(&mutex_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000198 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000199 }
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000200 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000201
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000202 // Start the timer thread
203 timer_event_ = static_cast<EventPosix*>(EventWrapper::Create());
204 const char* thread_name = "WebRtc_event_timer_thread";
205 timer_thread_ = ThreadWrapper::CreateThread(Run, this, kRealtimePriority,
206 thread_name);
207 periodic_ = periodic;
208 time_ = time;
209 unsigned int id = 0;
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000210 bool started = timer_thread_->Start(id);
211 pthread_mutex_unlock(&mutex_);
212
213 return started;
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000214}
215
216bool EventPosix::Run(ThreadObj obj) {
217 return static_cast<EventPosix*>(obj)->Process();
218}
219
220bool EventPosix::Process() {
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000221 pthread_mutex_lock(&mutex_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000222 if (created_at_.tv_sec == 0) {
223#ifndef WEBRTC_MAC
224#ifdef WEBRTC_CLOCK_TYPE_REALTIME
225 clock_gettime(CLOCK_REALTIME, &created_at_);
226#else
227 clock_gettime(CLOCK_MONOTONIC, &created_at_);
228#endif
229#else
230 timeval value;
231 struct timezone time_zone;
232 time_zone.tz_minuteswest = 0;
233 time_zone.tz_dsttime = 0;
234 gettimeofday(&value, &time_zone);
235 TIMEVAL_TO_TIMESPEC(&value, &created_at_);
236#endif
237 count_ = 0;
238 }
239
240 timespec end_at;
241 unsigned long long time = time_ * ++count_;
242 end_at.tv_sec = created_at_.tv_sec + time / 1000;
243 end_at.tv_nsec = created_at_.tv_nsec + (time - (time / 1000) * 1000) * E6;
244
245 if (end_at.tv_nsec >= E9) {
246 end_at.tv_sec++;
247 end_at.tv_nsec -= E9;
248 }
249
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000250 pthread_mutex_unlock(&mutex_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000251 switch (timer_event_->Wait(end_at)) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000252 case kEventSignaled:
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000253 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000254 case kEventError:
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000255 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 case kEventTimeout:
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000257 break;
258 }
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000259
260 pthread_mutex_lock(&mutex_);
261 if (periodic_ || count_ == 1)
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000262 Set();
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000263 pthread_mutex_unlock(&mutex_);
264
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000265 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000266}
267
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000268bool EventPosix::StopTimer() {
269 if (timer_thread_) {
270 timer_thread_->SetNotAlive();
271 }
272 if (timer_event_) {
273 timer_event_->Set();
274 }
275 if (timer_thread_) {
276 if (!timer_thread_->Stop()) {
277 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000278 }
279
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000280 delete timer_thread_;
281 timer_thread_ = 0;
282 }
283 if (timer_event_) {
284 delete timer_event_;
285 timer_event_ = 0;
286 }
287
288 // Set time to zero to force new reference time for the timer.
289 memset(&created_at_, 0, sizeof(created_at_));
290 count_ = 0;
291 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000292}
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000293
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000294} // namespace webrtc