blob: c32918924465b9e577836f4368df323fc4421cdc [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
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000053 int result = pthread_mutex_init(&mutex_, 0);
54 if (result != 0) {
55 return -1;
56 }
niklase@google.com470e71d2011-07-07 08:21:25 +000057#ifdef WEBRTC_CLOCK_TYPE_REALTIME
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000058 result = pthread_cond_init(&cond_, 0);
59 if (result != 0) {
60 return -1;
61 }
niklase@google.com470e71d2011-07-07 08:21:25 +000062#else
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000063 pthread_condattr_t cond_attr;
64 result = pthread_condattr_init(&cond_attr);
65 if (result != 0) {
66 return -1;
67 }
68 result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
69 if (result != 0) {
70 return -1;
71 }
72 result = pthread_cond_init(&cond_, &cond_attr);
73 if (result != 0) {
74 return -1;
75 }
76 result = pthread_condattr_destroy(&cond_attr);
77 if (result != 0) {
78 return -1;
79 }
niklase@google.com470e71d2011-07-07 08:21:25 +000080#endif
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000081 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000082}
83
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000084EventPosix::~EventPosix() {
85 StopTimer();
86 pthread_cond_destroy(&cond_);
87 pthread_mutex_destroy(&mutex_);
niklase@google.com470e71d2011-07-07 08:21:25 +000088}
89
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000090bool EventPosix::Reset() {
91 if (0 != pthread_mutex_lock(&mutex_)) {
niklase@google.com470e71d2011-07-07 08:21:25 +000092 return false;
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000093 }
94 state_ = kDown;
95 pthread_mutex_unlock(&mutex_);
96 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +000097}
98
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000099bool EventPosix::Set() {
100 if (0 != pthread_mutex_lock(&mutex_)) {
101 return false;
102 }
103 state_ = kUp;
104 // Release all waiting threads
105 pthread_cond_broadcast(&cond_);
106 pthread_mutex_unlock(&mutex_);
107 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000108}
109
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000110EventTypeWrapper EventPosix::Wait(unsigned long timeout) {
111 int ret_val = 0;
112 if (0 != pthread_mutex_lock(&mutex_)) {
113 return kEventError;
114 }
115
116 if (kDown == state_) {
117 if (WEBRTC_EVENT_INFINITE != timeout) {
118 timespec end_at;
niklase@google.com470e71d2011-07-07 08:21:25 +0000119#ifndef WEBRTC_MAC
120#ifdef WEBRTC_CLOCK_TYPE_REALTIME
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000121 clock_gettime(CLOCK_REALTIME, &end_at);
niklase@google.com470e71d2011-07-07 08:21:25 +0000122#else
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000123 clock_gettime(CLOCK_MONOTONIC, &end_at);
niklase@google.com470e71d2011-07-07 08:21:25 +0000124#endif
125#else
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000126 timeval value;
127 struct timezone time_zone;
128 time_zone.tz_minuteswest = 0;
129 time_zone.tz_dsttime = 0;
130 gettimeofday(&value, &time_zone);
131 TIMEVAL_TO_TIMESPEC(&value, &end_at);
niklase@google.com470e71d2011-07-07 08:21:25 +0000132#endif
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000133 end_at.tv_sec += timeout / 1000;
134 end_at.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6;
135
136 if (end_at.tv_nsec >= E9) {
137 end_at.tv_sec++;
138 end_at.tv_nsec -= E9;
139 }
140 ret_val = pthread_cond_timedwait(&cond_, &mutex_, &end_at);
141 } else {
142 ret_val = pthread_cond_wait(&cond_, &mutex_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000143 }
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000144 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000145
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000146 state_ = kDown;
147 pthread_mutex_unlock(&mutex_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000148
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000149 switch (ret_val) {
150 case 0:
151 return kEventSignaled;
152 case ETIMEDOUT:
153 return kEventTimeout;
154 default:
155 return kEventError;
156 }
157}
158
159EventTypeWrapper EventPosix::Wait(timespec& wake_at) {
160 int ret_val = 0;
161 if (0 != pthread_mutex_lock(&mutex_)) {
162 return kEventError;
163 }
164
165 if (kUp != state_) {
166 ret_val = pthread_cond_timedwait(&cond_, &mutex_, &wake_at);
167 }
168 state_ = kDown;
169
170 pthread_mutex_unlock(&mutex_);
171
172 switch (ret_val) {
173 case 0:
174 return kEventSignaled;
175 case ETIMEDOUT:
176 return kEventTimeout;
177 default:
178 return kEventError;
179 }
180}
181
182bool EventPosix::StartTimer(bool periodic, unsigned long time) {
183 if (timer_thread_) {
184 if (periodic_) {
185 // Timer already started.
186 return false;
187 } else {
188 // New one shot timer
189 time_ = time;
190 created_at_.tv_sec = 0;
191 timer_event_->Set();
192 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000193 }
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000194 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000195
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000196 // Start the timer thread
197 timer_event_ = static_cast<EventPosix*>(EventWrapper::Create());
198 const char* thread_name = "WebRtc_event_timer_thread";
199 timer_thread_ = ThreadWrapper::CreateThread(Run, this, kRealtimePriority,
200 thread_name);
201 periodic_ = periodic;
202 time_ = time;
203 unsigned int id = 0;
204 if (timer_thread_->Start(id)) {
205 return true;
206 }
207 return false;
208}
209
210bool EventPosix::Run(ThreadObj obj) {
211 return static_cast<EventPosix*>(obj)->Process();
212}
213
214bool EventPosix::Process() {
215 if (created_at_.tv_sec == 0) {
216#ifndef WEBRTC_MAC
217#ifdef WEBRTC_CLOCK_TYPE_REALTIME
218 clock_gettime(CLOCK_REALTIME, &created_at_);
219#else
220 clock_gettime(CLOCK_MONOTONIC, &created_at_);
221#endif
222#else
223 timeval value;
224 struct timezone time_zone;
225 time_zone.tz_minuteswest = 0;
226 time_zone.tz_dsttime = 0;
227 gettimeofday(&value, &time_zone);
228 TIMEVAL_TO_TIMESPEC(&value, &created_at_);
229#endif
230 count_ = 0;
231 }
232
233 timespec end_at;
234 unsigned long long time = time_ * ++count_;
235 end_at.tv_sec = created_at_.tv_sec + time / 1000;
236 end_at.tv_nsec = created_at_.tv_nsec + (time - (time / 1000) * 1000) * E6;
237
238 if (end_at.tv_nsec >= E9) {
239 end_at.tv_sec++;
240 end_at.tv_nsec -= E9;
241 }
242
243 switch (timer_event_->Wait(end_at)) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000244 case kEventSignaled:
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000245 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000246 case kEventError:
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000247 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000248 case kEventTimeout:
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000249 break;
250 }
251 if (periodic_ || count_ == 1) {
252 Set();
253 }
254 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000255}
256
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000257bool EventPosix::StopTimer() {
258 if (timer_thread_) {
259 timer_thread_->SetNotAlive();
260 }
261 if (timer_event_) {
262 timer_event_->Set();
263 }
264 if (timer_thread_) {
265 if (!timer_thread_->Stop()) {
266 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000267 }
268
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000269 delete timer_thread_;
270 timer_thread_ = 0;
271 }
272 if (timer_event_) {
273 delete timer_event_;
274 timer_event_ = 0;
275 }
276
277 // Set time to zero to force new reference time for the timer.
278 memset(&created_at_, 0, sizeof(created_at_));
279 count_ = 0;
280 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000281}
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000282
niklase@google.com470e71d2011-07-07 08:21:25 +0000283} // namespace webrtc