| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/system_wrappers/source/event_timer_posix.h" | 11 #include "webrtc/system_wrappers/source/event_timer_posix.h" |
| 12 | 12 |
| 13 #include <errno.h> | 13 #include <errno.h> |
| 14 #include <pthread.h> | 14 #include <pthread.h> |
| 15 #include <signal.h> | 15 #include <signal.h> |
| 16 #include <stdio.h> | 16 #include <stdio.h> |
| 17 #include <string.h> | 17 #include <string.h> |
| 18 #include <sys/time.h> | 18 #include <sys/time.h> |
| 19 #include <unistd.h> | 19 #include <unistd.h> |
| 20 | 20 |
| 21 #include "webrtc/base/checks.h" | 21 #include "webrtc/base/checks.h" |
| 22 | 22 |
| 23 namespace webrtc { | 23 namespace webrtc { |
| 24 | 24 |
| 25 // static | 25 // static |
| 26 EventTimerWrapper* EventTimerWrapper::Create() { | 26 EventTimerWrapper* EventTimerWrapper::Create() { |
| 27 return new EventTimerPosix(); | 27 return new EventTimerPosix(); |
| 28 } | 28 } |
| 29 | 29 |
| 30 const long int E6 = 1000000; | 30 const int64_t kNanosecondsPerMillisecond = 1000000; |
| 31 const long int E9 = 1000 * E6; | 31 const int64_t kNanosecondsPerSecond = 1000000000; |
| 32 | 32 |
| 33 EventTimerPosix::EventTimerPosix() | 33 EventTimerPosix::EventTimerPosix() |
| 34 : event_set_(false), | 34 : event_set_(false), |
| 35 timer_thread_(nullptr), | 35 timer_thread_(nullptr), |
| 36 created_at_(), | 36 created_at_(), |
| 37 periodic_(false), | 37 periodic_(false), |
| 38 time_(0), | 38 time_ms_(0), |
| 39 count_(0) { | 39 count_(0), |
| 40 is_stopping_(false) { |
| 40 pthread_mutexattr_t attr; | 41 pthread_mutexattr_t attr; |
| 41 pthread_mutexattr_init(&attr); | 42 pthread_mutexattr_init(&attr); |
| 42 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); | 43 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); |
| 43 pthread_mutex_init(&mutex_, &attr); | 44 pthread_mutex_init(&mutex_, &attr); |
| 44 pthread_condattr_t cond_attr; | 45 pthread_condattr_t cond_attr; |
| 45 pthread_condattr_init(&cond_attr); | 46 pthread_condattr_init(&cond_attr); |
| 46 // TODO(sprang): Remove HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC special case once | 47 // TODO(sprang): Remove HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC special case once |
| 47 // all supported Android platforms support pthread_condattr_setclock. | 48 // all supported Android platforms support pthread_condattr_setclock. |
| 48 // TODO(sprang): Add support for monotonic clock on Apple platforms. | 49 // TODO(sprang): Add support for monotonic clock on Apple platforms. |
| 49 #if !(defined(WEBRTC_MAC) || defined(WEBRTC_IOS)) && \ | 50 #if !(defined(WEBRTC_MAC) || defined(WEBRTC_IOS)) && \ |
| (...skipping 13 matching lines...) Expand all Loading... |
| 63 | 64 |
| 64 // TODO(pbos): Make this void. | 65 // TODO(pbos): Make this void. |
| 65 bool EventTimerPosix::Set() { | 66 bool EventTimerPosix::Set() { |
| 66 RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_)); | 67 RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_)); |
| 67 event_set_ = true; | 68 event_set_ = true; |
| 68 pthread_cond_signal(&cond_); | 69 pthread_cond_signal(&cond_); |
| 69 pthread_mutex_unlock(&mutex_); | 70 pthread_mutex_unlock(&mutex_); |
| 70 return true; | 71 return true; |
| 71 } | 72 } |
| 72 | 73 |
| 73 EventTypeWrapper EventTimerPosix::Wait(unsigned long timeout) { | 74 EventTypeWrapper EventTimerPosix::Wait(unsigned long timeout_ms) { |
| 74 int ret_val = 0; | 75 int ret_val = 0; |
| 75 RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_)); | 76 RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_)); |
| 76 | 77 |
| 77 if (!event_set_) { | 78 if (!event_set_) { |
| 78 if (WEBRTC_EVENT_INFINITE != timeout) { | 79 if (WEBRTC_EVENT_INFINITE != timeout_ms) { |
| 79 timespec end_at; | 80 timespec end_at; |
| 80 #ifndef WEBRTC_MAC | 81 #ifndef WEBRTC_MAC |
| 81 clock_gettime(CLOCK_MONOTONIC, &end_at); | 82 clock_gettime(CLOCK_MONOTONIC, &end_at); |
| 82 #else | 83 #else |
| 83 timeval value; | 84 timeval value; |
| 84 struct timezone time_zone; | 85 struct timezone time_zone; |
| 85 time_zone.tz_minuteswest = 0; | 86 time_zone.tz_minuteswest = 0; |
| 86 time_zone.tz_dsttime = 0; | 87 time_zone.tz_dsttime = 0; |
| 87 gettimeofday(&value, &time_zone); | 88 gettimeofday(&value, &time_zone); |
| 88 TIMEVAL_TO_TIMESPEC(&value, &end_at); | 89 TIMEVAL_TO_TIMESPEC(&value, &end_at); |
| 89 #endif | 90 #endif |
| 90 end_at.tv_sec += timeout / 1000; | 91 end_at.tv_sec += timeout_ms / 1000; |
| 91 end_at.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6; | 92 end_at.tv_nsec += (timeout_ms % 1000) * kNanosecondsPerMillisecond; |
| 92 | 93 |
| 93 if (end_at.tv_nsec >= E9) { | 94 if (end_at.tv_nsec >= kNanosecondsPerSecond) { |
| 94 end_at.tv_sec++; | 95 end_at.tv_sec++; |
| 95 end_at.tv_nsec -= E9; | 96 end_at.tv_nsec -= kNanosecondsPerSecond; |
| 96 } | 97 } |
| 97 while (ret_val == 0 && !event_set_) { | 98 while (ret_val == 0 && !event_set_) { |
| 98 #if defined(WEBRTC_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) | 99 #if defined(WEBRTC_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) |
| 99 ret_val = pthread_cond_timedwait_monotonic_np(&cond_, &mutex_, &end_at); | 100 ret_val = pthread_cond_timedwait_monotonic_np(&cond_, &mutex_, &end_at); |
| 100 #else | 101 #else |
| 101 ret_val = pthread_cond_timedwait(&cond_, &mutex_, &end_at); | 102 ret_val = pthread_cond_timedwait(&cond_, &mutex_, &end_at); |
| 102 #endif // WEBRTC_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC | 103 #endif // WEBRTC_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC |
| 103 } | 104 } |
| 104 } else { | 105 } else { |
| 105 while (ret_val == 0 && !event_set_) | 106 while (ret_val == 0 && !event_set_) |
| 106 ret_val = pthread_cond_wait(&cond_, &mutex_); | 107 ret_val = pthread_cond_wait(&cond_, &mutex_); |
| 107 } | 108 } |
| 108 } | 109 } |
| 109 | 110 |
| 110 RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT); | 111 RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT); |
| 111 | 112 |
| 112 // Reset and signal if set, regardless of why the thread woke up. | 113 // Reset and signal if set, regardless of why the thread woke up. |
| 113 if (event_set_) { | 114 if (event_set_) { |
| 114 ret_val = 0; | 115 ret_val = 0; |
| 115 event_set_ = false; | 116 event_set_ = false; |
| 116 } | 117 } |
| 117 pthread_mutex_unlock(&mutex_); | 118 pthread_mutex_unlock(&mutex_); |
| 118 | 119 |
| 119 return ret_val == 0 ? kEventSignaled : kEventTimeout; | 120 return ret_val == 0 ? kEventSignaled : kEventTimeout; |
| 120 } | 121 } |
| 121 | 122 |
| 122 EventTypeWrapper EventTimerPosix::Wait(timespec* end_at) { | 123 EventTypeWrapper EventTimerPosix::Wait(timespec* end_at, bool reset_event) { |
| 123 int ret_val = 0; | 124 int ret_val = 0; |
| 124 RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_)); | 125 RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_)); |
| 126 if (reset_event) { |
| 127 // Only wake for new events or timeouts. |
| 128 event_set_ = false; |
| 129 } |
| 125 | 130 |
| 126 while (ret_val == 0 && !event_set_) { | 131 while (ret_val == 0 && !event_set_) { |
| 127 #if defined(WEBRTC_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) | 132 #if defined(WEBRTC_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) |
| 128 ret_val = pthread_cond_timedwait_monotonic_np(&cond_, &mutex_, end_at); | 133 ret_val = pthread_cond_timedwait_monotonic_np(&cond_, &mutex_, end_at); |
| 129 #else | 134 #else |
| 130 ret_val = pthread_cond_timedwait(&cond_, &mutex_, end_at); | 135 ret_val = pthread_cond_timedwait(&cond_, &mutex_, end_at); |
| 131 #endif // WEBRTC_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC | 136 #endif // WEBRTC_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC |
| 132 } | 137 } |
| 133 | 138 |
| 134 RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT); | 139 RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT); |
| 135 | 140 |
| 136 // Reset and signal if set, regardless of why the thread woke up. | 141 // Reset and signal if set, regardless of why the thread woke up. |
| 137 if (event_set_) { | 142 if (event_set_) { |
| 138 ret_val = 0; | 143 ret_val = 0; |
| 139 event_set_ = false; | 144 event_set_ = false; |
| 140 } | 145 } |
| 141 pthread_mutex_unlock(&mutex_); | 146 pthread_mutex_unlock(&mutex_); |
| 142 | 147 |
| 143 return ret_val == 0 ? kEventSignaled : kEventTimeout; | 148 return ret_val == 0 ? kEventSignaled : kEventTimeout; |
| 144 } | 149 } |
| 145 | 150 |
| 146 bool EventTimerPosix::StartTimer(bool periodic, unsigned long time) { | 151 rtc::PlatformThread* EventTimerPosix::CreateThread() { |
| 152 const char* kThreadName = "WebRtc_event_timer_thread"; |
| 153 return new rtc::PlatformThread(Run, this, kThreadName); |
| 154 } |
| 155 |
| 156 bool EventTimerPosix::StartTimer(bool periodic, unsigned long time_ms) { |
| 147 pthread_mutex_lock(&mutex_); | 157 pthread_mutex_lock(&mutex_); |
| 148 if (timer_thread_) { | 158 if (timer_thread_) { |
| 149 if (periodic_) { | 159 if (periodic_) { |
| 150 // Timer already started. | 160 // Timer already started. |
| 151 pthread_mutex_unlock(&mutex_); | 161 pthread_mutex_unlock(&mutex_); |
| 152 return false; | 162 return false; |
| 153 } else { | 163 } else { |
| 154 // New one shot timer | 164 // New one shot timer. |
| 155 time_ = time; | 165 time_ms_ = time_ms; |
| 156 created_at_.tv_sec = 0; | 166 created_at_.tv_sec = 0; |
| 157 timer_event_->Set(); | 167 timer_event_->Set(); |
| 158 pthread_mutex_unlock(&mutex_); | 168 pthread_mutex_unlock(&mutex_); |
| 159 return true; | 169 return true; |
| 160 } | 170 } |
| 161 } | 171 } |
| 162 | 172 |
| 163 // Start the timer thread | 173 // Start the timer thread. |
| 164 timer_event_.reset(new EventTimerPosix()); | 174 timer_event_.reset(new EventTimerPosix()); |
| 165 const char* thread_name = "WebRtc_event_timer_thread"; | 175 timer_thread_.reset(CreateThread()); |
| 166 timer_thread_.reset(new rtc::PlatformThread(Run, this, thread_name)); | |
| 167 periodic_ = periodic; | 176 periodic_ = periodic; |
| 168 time_ = time; | 177 time_ms_ = time_ms; |
| 169 timer_thread_->Start(); | 178 timer_thread_->Start(); |
| 170 timer_thread_->SetPriority(rtc::kRealtimePriority); | 179 timer_thread_->SetPriority(rtc::kRealtimePriority); |
| 171 pthread_mutex_unlock(&mutex_); | 180 pthread_mutex_unlock(&mutex_); |
| 172 | 181 |
| 173 return true; | 182 return true; |
| 174 } | 183 } |
| 175 | 184 |
| 176 bool EventTimerPosix::Run(void* obj) { | 185 bool EventTimerPosix::Run(void* obj) { |
| 177 return static_cast<EventTimerPosix*>(obj)->Process(); | 186 return static_cast<EventTimerPosix*>(obj)->Process(); |
| 178 } | 187 } |
| 179 | 188 |
| 180 bool EventTimerPosix::Process() { | 189 bool EventTimerPosix::Process() { |
| 181 pthread_mutex_lock(&mutex_); | 190 pthread_mutex_lock(&mutex_); |
| 191 if (is_stopping_) |
| 192 return false; |
| 182 if (created_at_.tv_sec == 0) { | 193 if (created_at_.tv_sec == 0) { |
| 183 #ifndef WEBRTC_MAC | 194 #ifndef WEBRTC_MAC |
| 184 clock_gettime(CLOCK_MONOTONIC, &created_at_); | 195 RTC_CHECK_EQ(0, clock_gettime(CLOCK_MONOTONIC, &created_at_)); |
| 185 #else | 196 #else |
| 186 timeval value; | 197 timeval value; |
| 187 struct timezone time_zone; | 198 struct timezone time_zone; |
| 188 time_zone.tz_minuteswest = 0; | 199 time_zone.tz_minuteswest = 0; |
| 189 time_zone.tz_dsttime = 0; | 200 time_zone.tz_dsttime = 0; |
| 190 gettimeofday(&value, &time_zone); | 201 gettimeofday(&value, &time_zone); |
| 191 TIMEVAL_TO_TIMESPEC(&value, &created_at_); | 202 TIMEVAL_TO_TIMESPEC(&value, &created_at_); |
| 192 #endif | 203 #endif |
| 193 count_ = 0; | 204 count_ = 0; |
| 194 } | 205 } |
| 195 | 206 |
| 196 timespec end_at; | 207 timespec end_at; |
| 197 unsigned long long time = time_ * ++count_; | 208 unsigned long long total_delta_ms = time_ms_ * ++count_; |
| 198 end_at.tv_sec = created_at_.tv_sec + time / 1000; | 209 if (!periodic_ && count_ >= 1) { |
| 199 end_at.tv_nsec = created_at_.tv_nsec + (time - (time / 1000) * 1000) * E6; | 210 // No need to wake up often if we're not going to signal waiting threads. |
| 211 total_delta_ms = |
| 212 std::min<uint64_t>(total_delta_ms, 60 * kNanosecondsPerSecond); |
| 213 } |
| 200 | 214 |
| 201 if (end_at.tv_nsec >= E9) { | 215 end_at.tv_sec = created_at_.tv_sec + total_delta_ms / 1000; |
| 216 end_at.tv_nsec = created_at_.tv_nsec + |
| 217 (total_delta_ms % 1000) * kNanosecondsPerMillisecond; |
| 218 |
| 219 if (end_at.tv_nsec >= kNanosecondsPerSecond) { |
| 202 end_at.tv_sec++; | 220 end_at.tv_sec++; |
| 203 end_at.tv_nsec -= E9; | 221 end_at.tv_nsec -= kNanosecondsPerSecond; |
| 204 } | 222 } |
| 205 | 223 |
| 206 pthread_mutex_unlock(&mutex_); | 224 pthread_mutex_unlock(&mutex_); |
| 207 if (timer_event_->Wait(&end_at) == kEventSignaled) | 225 // Reset event on first call so that we don't immediately return here if this |
| 208 return true; | 226 // thread was not blocked on timer_event_->Wait when the StartTimer() call |
| 227 // was made. |
| 228 if (timer_event_->Wait(&end_at, count_ == 1) == kEventSignaled) |
| 229 return !is_stopping_; |
| 209 | 230 |
| 210 pthread_mutex_lock(&mutex_); | 231 pthread_mutex_lock(&mutex_); |
| 211 if (periodic_ || count_ == 1) | 232 if (periodic_ || count_ == 1) |
| 212 Set(); | 233 Set(); |
| 213 pthread_mutex_unlock(&mutex_); | 234 pthread_mutex_unlock(&mutex_); |
| 214 | 235 |
| 215 return true; | 236 return true; |
| 216 } | 237 } |
| 217 | 238 |
| 218 bool EventTimerPosix::StopTimer() { | 239 bool EventTimerPosix::StopTimer() { |
| 219 if (timer_event_) { | 240 pthread_mutex_lock(&mutex_); |
| 241 is_stopping_ = true; |
| 242 pthread_mutex_unlock(&mutex_); |
| 243 |
| 244 if (timer_event_) |
| 220 timer_event_->Set(); | 245 timer_event_->Set(); |
| 221 } | 246 |
| 222 if (timer_thread_) { | 247 if (timer_thread_) { |
| 223 timer_thread_->Stop(); | 248 timer_thread_->Stop(); |
| 224 timer_thread_.reset(); | 249 timer_thread_.reset(); |
| 225 } | 250 } |
| 226 timer_event_.reset(); | 251 timer_event_.reset(); |
| 227 | 252 |
| 228 // Set time to zero to force new reference time for the timer. | 253 // Set time to zero to force new reference time for the timer. |
| 229 memset(&created_at_, 0, sizeof(created_at_)); | 254 memset(&created_at_, 0, sizeof(created_at_)); |
| 230 count_ = 0; | 255 count_ = 0; |
| 231 return true; | 256 return true; |
| 232 } | 257 } |
| 233 | 258 |
| 234 } // namespace webrtc | 259 } // namespace webrtc |
| OLD | NEW |