blob: 990ff725fb8d9d1aebf79ab1153dab111c11847f [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
Peter Boström64c03662015-04-08 11:24:19 +020011#include "webrtc/system_wrappers/source/event_timer_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
Peter Boström64c03662015-04-08 11:24:19 +020025// static
26EventTimerWrapper* EventTimerWrapper::Create() {
27 return new EventTimerPosix();
28}
29
niklase@google.com470e71d2011-07-07 08:21:25 +000030const long int E6 = 1000000;
31const long int E9 = 1000 * E6;
32
Peter Boström64c03662015-04-08 11:24:19 +020033EventTimerPosix::EventTimerPosix()
pbos@webrtc.orga8463712015-03-17 13:11:15 +000034 : event_set_(false),
35 timer_thread_(nullptr),
pbos@webrtc.orga8463712015-03-17 13:11:15 +000036 created_at_(),
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000037 periodic_(false),
38 time_(0),
pbos@webrtc.orga8463712015-03-17 13:11:15 +000039 count_(0) {
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +000040 pthread_mutexattr_t attr;
41 pthread_mutexattr_init(&attr);
42 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pbos@webrtc.orga8463712015-03-17 13:11:15 +000043 pthread_mutex_init(&mutex_, &attr);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000044 pthread_condattr_t cond_attr;
pbos@webrtc.orga8463712015-03-17 13:11:15 +000045 pthread_condattr_init(&cond_attr);
sprange791ffd2016-01-26 01:53:20 -080046// TODO(sprang): Remove HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC special case once
47// all supported Android platforms support pthread_condattr_setclock.
48// TODO(sprang): Add support for monotonic clock on Apple platforms.
49#if !(defined(WEBRTC_MAC) || defined(WEBRTC_IOS)) && \
50 !(defined(WEBRTC_ANDROID) && \
51 defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
pbos@webrtc.orga8463712015-03-17 13:11:15 +000052 pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
sprange791ffd2016-01-26 01:53:20 -080053#endif
pbos@webrtc.orga8463712015-03-17 13:11:15 +000054 pthread_cond_init(&cond_, &cond_attr);
55 pthread_condattr_destroy(&cond_attr);
niklase@google.com470e71d2011-07-07 08:21:25 +000056}
57
Peter Boström64c03662015-04-08 11:24:19 +020058EventTimerPosix::~EventTimerPosix() {
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000059 StopTimer();
60 pthread_cond_destroy(&cond_);
61 pthread_mutex_destroy(&mutex_);
niklase@google.com470e71d2011-07-07 08:21:25 +000062}
63
pbos@webrtc.orga8463712015-03-17 13:11:15 +000064// TODO(pbos): Make this void.
Peter Boström64c03662015-04-08 11:24:19 +020065bool EventTimerPosix::Set() {
henrikg91d6ede2015-09-17 00:24:34 -070066 RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
pbos@webrtc.orga8463712015-03-17 13:11:15 +000067 event_set_ = true;
68 pthread_cond_signal(&cond_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000069 pthread_mutex_unlock(&mutex_);
70 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +000071}
72
Peter Boström64c03662015-04-08 11:24:19 +020073EventTypeWrapper EventTimerPosix::Wait(unsigned long timeout) {
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000074 int ret_val = 0;
henrikg91d6ede2015-09-17 00:24:34 -070075 RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000076
pbos@webrtc.orga8463712015-03-17 13:11:15 +000077 if (!event_set_) {
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000078 if (WEBRTC_EVENT_INFINITE != timeout) {
79 timespec end_at;
niklase@google.com470e71d2011-07-07 08:21:25 +000080#ifndef WEBRTC_MAC
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000081 clock_gettime(CLOCK_MONOTONIC, &end_at);
niklase@google.com470e71d2011-07-07 08:21:25 +000082#else
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000083 timeval value;
84 struct timezone time_zone;
85 time_zone.tz_minuteswest = 0;
86 time_zone.tz_dsttime = 0;
87 gettimeofday(&value, &time_zone);
88 TIMEVAL_TO_TIMESPEC(&value, &end_at);
niklase@google.com470e71d2011-07-07 08:21:25 +000089#endif
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +000090 end_at.tv_sec += timeout / 1000;
91 end_at.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6;
92
93 if (end_at.tv_nsec >= E9) {
94 end_at.tv_sec++;
95 end_at.tv_nsec -= E9;
96 }
sprange791ffd2016-01-26 01:53:20 -080097 while (ret_val == 0 && !event_set_) {
98#if defined(WEBRTC_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
99 ret_val = pthread_cond_timedwait_monotonic_np(&cond_, &mutex_, &end_at);
100#else
pbos@webrtc.orga8463712015-03-17 13:11:15 +0000101 ret_val = pthread_cond_timedwait(&cond_, &mutex_, &end_at);
sprange791ffd2016-01-26 01:53:20 -0800102#endif // WEBRTC_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
103 }
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000104 } else {
pbos@webrtc.orga8463712015-03-17 13:11:15 +0000105 while (ret_val == 0 && !event_set_)
106 ret_val = pthread_cond_wait(&cond_, &mutex_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000107 }
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000108 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000109
henrikg91d6ede2015-09-17 00:24:34 -0700110 RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT);
tommi@webrtc.orgf7e6cfd2015-02-09 18:25:38 +0000111
pbos@webrtc.orga8463712015-03-17 13:11:15 +0000112 // Reset and signal if set, regardless of why the thread woke up.
113 if (event_set_) {
114 ret_val = 0;
115 event_set_ = false;
116 }
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000117 pthread_mutex_unlock(&mutex_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000118
pbos@webrtc.orga8463712015-03-17 13:11:15 +0000119 return ret_val == 0 ? kEventSignaled : kEventTimeout;
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000120}
121
Peter Boström64c03662015-04-08 11:24:19 +0200122EventTypeWrapper EventTimerPosix::Wait(timespec* end_at) {
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000123 int ret_val = 0;
henrikg91d6ede2015-09-17 00:24:34 -0700124 RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000125
sprange791ffd2016-01-26 01:53:20 -0800126 while (ret_val == 0 && !event_set_) {
127#if defined(WEBRTC_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
128 ret_val = pthread_cond_timedwait_monotonic_np(&cond_, &mutex_, end_at);
129#else
pbos@webrtc.orga8463712015-03-17 13:11:15 +0000130 ret_val = pthread_cond_timedwait(&cond_, &mutex_, end_at);
sprange791ffd2016-01-26 01:53:20 -0800131#endif // WEBRTC_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
132 }
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000133
henrikg91d6ede2015-09-17 00:24:34 -0700134 RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT);
pbos@webrtc.orga8463712015-03-17 13:11:15 +0000135
136 // Reset and signal if set, regardless of why the thread woke up.
137 if (event_set_) {
138 ret_val = 0;
139 event_set_ = false;
140 }
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000141 pthread_mutex_unlock(&mutex_);
142
pbos@webrtc.orga8463712015-03-17 13:11:15 +0000143 return ret_val == 0 ? kEventSignaled : kEventTimeout;
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000144}
145
Peter Boström64c03662015-04-08 11:24:19 +0200146bool EventTimerPosix::StartTimer(bool periodic, unsigned long time) {
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000147 pthread_mutex_lock(&mutex_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000148 if (timer_thread_) {
149 if (periodic_) {
150 // Timer already started.
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000151 pthread_mutex_unlock(&mutex_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000152 return false;
153 } else {
154 // New one shot timer
155 time_ = time;
156 created_at_.tv_sec = 0;
157 timer_event_->Set();
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000158 pthread_mutex_unlock(&mutex_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000159 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000160 }
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000161 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000162
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000163 // Start the timer thread
Peter Boström64c03662015-04-08 11:24:19 +0200164 timer_event_.reset(new EventTimerPosix());
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000165 const char* thread_name = "WebRtc_event_timer_thread";
Peter Boström8c38e8b2015-11-26 17:45:47 +0100166 timer_thread_.reset(new rtc::PlatformThread(Run, this, thread_name));
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000167 periodic_ = periodic;
168 time_ = time;
Peter Boström8c38e8b2015-11-26 17:45:47 +0100169 timer_thread_->Start();
170 timer_thread_->SetPriority(rtc::kRealtimePriority);
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000171 pthread_mutex_unlock(&mutex_);
172
Peter Boström8c38e8b2015-11-26 17:45:47 +0100173 return true;
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000174}
175
Peter Boström64c03662015-04-08 11:24:19 +0200176bool EventTimerPosix::Run(void* obj) {
177 return static_cast<EventTimerPosix*>(obj)->Process();
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000178}
179
Peter Boström64c03662015-04-08 11:24:19 +0200180bool EventTimerPosix::Process() {
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000181 pthread_mutex_lock(&mutex_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000182 if (created_at_.tv_sec == 0) {
183#ifndef WEBRTC_MAC
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000184 clock_gettime(CLOCK_MONOTONIC, &created_at_);
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000185#else
186 timeval value;
187 struct timezone time_zone;
188 time_zone.tz_minuteswest = 0;
189 time_zone.tz_dsttime = 0;
190 gettimeofday(&value, &time_zone);
191 TIMEVAL_TO_TIMESPEC(&value, &created_at_);
192#endif
193 count_ = 0;
194 }
195
196 timespec end_at;
197 unsigned long long time = time_ * ++count_;
198 end_at.tv_sec = created_at_.tv_sec + time / 1000;
199 end_at.tv_nsec = created_at_.tv_nsec + (time - (time / 1000) * 1000) * E6;
200
201 if (end_at.tv_nsec >= E9) {
202 end_at.tv_sec++;
203 end_at.tv_nsec -= E9;
204 }
205
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000206 pthread_mutex_unlock(&mutex_);
pbos@webrtc.orga8463712015-03-17 13:11:15 +0000207 if (timer_event_->Wait(&end_at) == kEventSignaled)
208 return true;
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000209
210 pthread_mutex_lock(&mutex_);
211 if (periodic_ || count_ == 1)
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000212 Set();
pbos@webrtc.orge6dc38e2013-08-20 09:49:19 +0000213 pthread_mutex_unlock(&mutex_);
214
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000215 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000216}
217
Peter Boström64c03662015-04-08 11:24:19 +0200218bool EventTimerPosix::StopTimer() {
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000219 if (timer_event_) {
220 timer_event_->Set();
221 }
222 if (timer_thread_) {
Peter Boström8c38e8b2015-11-26 17:45:47 +0100223 timer_thread_->Stop();
tommi@webrtc.org361981f2015-03-19 14:44:18 +0000224 timer_thread_.reset();
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000225 }
Peter Boström64c03662015-04-08 11:24:19 +0200226 timer_event_.reset();
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000227
228 // Set time to zero to force new reference time for the timer.
229 memset(&created_at_, 0, sizeof(created_at_));
230 count_ = 0;
231 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000232}
phoglund@webrtc.org5bbe0692012-12-10 10:44:37 +0000233
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000234} // namespace webrtc