blob: 2a53afac3654619bebb4c7539bb5e1b62311265b [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
tommi@webrtc.orgf7e6cfd2015-02-09 18:25:38 +000021#include "webrtc/base/checks.h"
22
niklase@google.com470e71d2011-07-07 08:21:25 +000023namespace webrtc {
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000024
niklase@google.com470e71d2011-07-07 08:21:25 +000025const long int E6 = 1000000;
26const long int E9 = 1000 * E6;
27
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000028EventWrapper* EventPosix::Create() {
29 EventPosix* ptr = new EventPosix;
30 if (!ptr) {
31 return NULL;
32 }
niklase@google.com470e71d2011-07-07 08:21:25 +000033
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000034 const int error = ptr->Construct();
35 if (error) {
36 delete ptr;
37 return NULL;
38 }
39 return ptr;
niklase@google.com470e71d2011-07-07 08:21:25 +000040}
41
ajm@google.comb5c49ff2011-08-01 17:04:04 +000042EventPosix::EventPosix()
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000043 : timer_thread_(0),
44 timer_event_(0),
45 periodic_(false),
46 time_(0),
47 count_(0),
48 state_(kDown) {
niklase@google.com470e71d2011-07-07 08:21:25 +000049}
50
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000051int EventPosix::Construct() {
52 // Set start time to zero
53 memset(&created_at_, 0, sizeof(created_at_));
niklase@google.com470e71d2011-07-07 08:21:25 +000054
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +000055 pthread_mutexattr_t attr;
56 pthread_mutexattr_init(&attr);
57 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
58 int result = pthread_mutex_init(&mutex_, &attr);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000059 if (result != 0) {
60 return -1;
61 }
niklase@google.com470e71d2011-07-07 08:21:25 +000062#ifdef WEBRTC_CLOCK_TYPE_REALTIME
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000063 result = pthread_cond_init(&cond_, 0);
64 if (result != 0) {
65 return -1;
66 }
niklase@google.com470e71d2011-07-07 08:21:25 +000067#else
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000068 pthread_condattr_t cond_attr;
69 result = pthread_condattr_init(&cond_attr);
70 if (result != 0) {
71 return -1;
72 }
73 result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
74 if (result != 0) {
75 return -1;
76 }
77 result = pthread_cond_init(&cond_, &cond_attr);
78 if (result != 0) {
79 return -1;
80 }
81 result = pthread_condattr_destroy(&cond_attr);
82 if (result != 0) {
83 return -1;
84 }
niklase@google.com470e71d2011-07-07 08:21:25 +000085#endif
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000086 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000087}
88
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000089EventPosix::~EventPosix() {
90 StopTimer();
91 pthread_cond_destroy(&cond_);
92 pthread_mutex_destroy(&mutex_);
niklase@google.com470e71d2011-07-07 08:21:25 +000093}
94
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000095bool EventPosix::Reset() {
96 if (0 != pthread_mutex_lock(&mutex_)) {
niklase@google.com470e71d2011-07-07 08:21:25 +000097 return false;
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000098 }
99 state_ = kDown;
100 pthread_mutex_unlock(&mutex_);
101 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000102}
103
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000104bool EventPosix::Set() {
105 if (0 != pthread_mutex_lock(&mutex_)) {
106 return false;
107 }
108 state_ = kUp;
109 // Release all waiting threads
110 pthread_cond_broadcast(&cond_);
111 pthread_mutex_unlock(&mutex_);
112 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000113}
114
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000115EventTypeWrapper EventPosix::Wait(unsigned long timeout) {
116 int ret_val = 0;
117 if (0 != pthread_mutex_lock(&mutex_)) {
118 return kEventError;
119 }
120
121 if (kDown == state_) {
122 if (WEBRTC_EVENT_INFINITE != timeout) {
123 timespec end_at;
niklase@google.com470e71d2011-07-07 08:21:25 +0000124#ifndef WEBRTC_MAC
125#ifdef WEBRTC_CLOCK_TYPE_REALTIME
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000126 clock_gettime(CLOCK_REALTIME, &end_at);
niklase@google.com470e71d2011-07-07 08:21:25 +0000127#else
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000128 clock_gettime(CLOCK_MONOTONIC, &end_at);
niklase@google.com470e71d2011-07-07 08:21:25 +0000129#endif
130#else
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000131 timeval value;
132 struct timezone time_zone;
133 time_zone.tz_minuteswest = 0;
134 time_zone.tz_dsttime = 0;
135 gettimeofday(&value, &time_zone);
136 TIMEVAL_TO_TIMESPEC(&value, &end_at);
niklase@google.com470e71d2011-07-07 08:21:25 +0000137#endif
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000138 end_at.tv_sec += timeout / 1000;
139 end_at.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6;
140
141 if (end_at.tv_nsec >= E9) {
142 end_at.tv_sec++;
143 end_at.tv_nsec -= E9;
144 }
145 ret_val = pthread_cond_timedwait(&cond_, &mutex_, &end_at);
146 } else {
147 ret_val = pthread_cond_wait(&cond_, &mutex_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000148 }
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000149 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000150
tommi@webrtc.org30015e32015-02-10 09:33:28 +0000151 // Be careful to only change the state if we're about to report that the
152 // event was signaled.
153 if (ret_val == 0) {
154 DCHECK(state_ == kUp);
155 state_ = kDown;
156 }
tommi@webrtc.orgf7e6cfd2015-02-09 18:25:38 +0000157
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000158 pthread_mutex_unlock(&mutex_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000159
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000160 switch (ret_val) {
161 case 0:
162 return kEventSignaled;
163 case ETIMEDOUT:
164 return kEventTimeout;
165 default:
166 return kEventError;
167 }
168}
169
170EventTypeWrapper EventPosix::Wait(timespec& wake_at) {
171 int ret_val = 0;
172 if (0 != pthread_mutex_lock(&mutex_)) {
173 return kEventError;
174 }
175
176 if (kUp != state_) {
177 ret_val = pthread_cond_timedwait(&cond_, &mutex_, &wake_at);
178 }
179 state_ = kDown;
180
181 pthread_mutex_unlock(&mutex_);
182
183 switch (ret_val) {
184 case 0:
185 return kEventSignaled;
186 case ETIMEDOUT:
187 return kEventTimeout;
188 default:
189 return kEventError;
190 }
191}
192
193bool EventPosix::StartTimer(bool periodic, unsigned long time) {
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000194 pthread_mutex_lock(&mutex_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000195 if (timer_thread_) {
196 if (periodic_) {
197 // Timer already started.
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000198 pthread_mutex_unlock(&mutex_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000199 return false;
200 } else {
201 // New one shot timer
202 time_ = time;
203 created_at_.tv_sec = 0;
204 timer_event_->Set();
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000205 pthread_mutex_unlock(&mutex_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000206 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000207 }
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000208 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000209
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000210 // Start the timer thread
211 timer_event_ = static_cast<EventPosix*>(EventWrapper::Create());
212 const char* thread_name = "WebRtc_event_timer_thread";
213 timer_thread_ = ThreadWrapper::CreateThread(Run, this, kRealtimePriority,
214 thread_name);
215 periodic_ = periodic;
216 time_ = time;
217 unsigned int id = 0;
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000218 bool started = timer_thread_->Start(id);
219 pthread_mutex_unlock(&mutex_);
220
221 return started;
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000222}
223
224bool EventPosix::Run(ThreadObj obj) {
225 return static_cast<EventPosix*>(obj)->Process();
226}
227
228bool EventPosix::Process() {
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000229 pthread_mutex_lock(&mutex_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000230 if (created_at_.tv_sec == 0) {
231#ifndef WEBRTC_MAC
232#ifdef WEBRTC_CLOCK_TYPE_REALTIME
233 clock_gettime(CLOCK_REALTIME, &created_at_);
234#else
235 clock_gettime(CLOCK_MONOTONIC, &created_at_);
236#endif
237#else
238 timeval value;
239 struct timezone time_zone;
240 time_zone.tz_minuteswest = 0;
241 time_zone.tz_dsttime = 0;
242 gettimeofday(&value, &time_zone);
243 TIMEVAL_TO_TIMESPEC(&value, &created_at_);
244#endif
245 count_ = 0;
246 }
247
248 timespec end_at;
249 unsigned long long time = time_ * ++count_;
250 end_at.tv_sec = created_at_.tv_sec + time / 1000;
251 end_at.tv_nsec = created_at_.tv_nsec + (time - (time / 1000) * 1000) * E6;
252
253 if (end_at.tv_nsec >= E9) {
254 end_at.tv_sec++;
255 end_at.tv_nsec -= E9;
256 }
257
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000258 pthread_mutex_unlock(&mutex_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000259 switch (timer_event_->Wait(end_at)) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000260 case kEventSignaled:
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000261 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000262 case kEventError:
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000263 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000264 case kEventTimeout:
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000265 break;
266 }
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000267
268 pthread_mutex_lock(&mutex_);
269 if (periodic_ || count_ == 1)
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000270 Set();
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000271 pthread_mutex_unlock(&mutex_);
272
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000273 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000274}
275
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000276bool EventPosix::StopTimer() {
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000277 if (timer_event_) {
278 timer_event_->Set();
279 }
280 if (timer_thread_) {
281 if (!timer_thread_->Stop()) {
282 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000283 }
284
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000285 delete timer_thread_;
286 timer_thread_ = 0;
287 }
288 if (timer_event_) {
289 delete timer_event_;
290 timer_event_ = 0;
291 }
292
293 // Set time to zero to force new reference time for the timer.
294 memset(&created_at_, 0, sizeof(created_at_));
295 count_ = 0;
296 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000297}
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000298
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000299} // namespace webrtc