Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1229)

Unified Diff: webrtc/system_wrappers/source/event_timer_posix.cc

Issue 1812533002: Fix race condition in EventTimerPosix (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Test case was still racy Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/system_wrappers/source/event_timer_posix.cc
diff --git a/webrtc/system_wrappers/source/event_timer_posix.cc b/webrtc/system_wrappers/source/event_timer_posix.cc
index 990ff725fb8d9d1aebf79ab1153dab111c11847f..b46b83857fcf63db9a22cac2e100b483ebd3710e 100644
--- a/webrtc/system_wrappers/source/event_timer_posix.cc
+++ b/webrtc/system_wrappers/source/event_timer_posix.cc
@@ -27,16 +27,17 @@ EventTimerWrapper* EventTimerWrapper::Create() {
return new EventTimerPosix();
}
-const long int E6 = 1000000;
-const long int E9 = 1000 * E6;
+const int64_t kNanosecondsPerMillisecond = 1000000;
+const int64_t kNanosecondsPerSecond = 1000000000;
EventTimerPosix::EventTimerPosix()
: event_set_(false),
timer_thread_(nullptr),
created_at_(),
periodic_(false),
- time_(0),
- count_(0) {
+ time_ms_(0),
+ count_(0),
+ is_stopping_(false) {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
@@ -70,12 +71,12 @@ bool EventTimerPosix::Set() {
return true;
}
-EventTypeWrapper EventTimerPosix::Wait(unsigned long timeout) {
+EventTypeWrapper EventTimerPosix::Wait(unsigned long timeout_ms) {
int ret_val = 0;
RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
if (!event_set_) {
- if (WEBRTC_EVENT_INFINITE != timeout) {
+ if (WEBRTC_EVENT_INFINITE != timeout_ms) {
timespec end_at;
#ifndef WEBRTC_MAC
clock_gettime(CLOCK_MONOTONIC, &end_at);
@@ -87,12 +88,12 @@ EventTypeWrapper EventTimerPosix::Wait(unsigned long timeout) {
gettimeofday(&value, &time_zone);
TIMEVAL_TO_TIMESPEC(&value, &end_at);
#endif
- end_at.tv_sec += timeout / 1000;
- end_at.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6;
+ end_at.tv_sec += timeout_ms / 1000;
+ end_at.tv_nsec += (timeout_ms % 1000) * kNanosecondsPerMillisecond;
- if (end_at.tv_nsec >= E9) {
+ if (end_at.tv_nsec >= kNanosecondsPerSecond) {
end_at.tv_sec++;
- end_at.tv_nsec -= E9;
+ end_at.tv_nsec -= kNanosecondsPerSecond;
}
while (ret_val == 0 && !event_set_) {
#if defined(WEBRTC_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
@@ -119,9 +120,13 @@ EventTypeWrapper EventTimerPosix::Wait(unsigned long timeout) {
return ret_val == 0 ? kEventSignaled : kEventTimeout;
}
-EventTypeWrapper EventTimerPosix::Wait(timespec* end_at) {
+EventTypeWrapper EventTimerPosix::Wait(timespec* end_at, bool reset_event) {
int ret_val = 0;
RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
+ if (reset_event) {
+ // Only wake for new events or timeouts.
+ event_set_ = false;
+ }
while (ret_val == 0 && !event_set_) {
#if defined(WEBRTC_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
@@ -143,7 +148,12 @@ EventTypeWrapper EventTimerPosix::Wait(timespec* end_at) {
return ret_val == 0 ? kEventSignaled : kEventTimeout;
}
-bool EventTimerPosix::StartTimer(bool periodic, unsigned long time) {
+rtc::PlatformThread* EventTimerPosix::CreateThread() {
+ const char* kThreadName = "WebRtc_event_timer_thread";
+ return new rtc::PlatformThread(Run, this, kThreadName);
+}
+
+bool EventTimerPosix::StartTimer(bool periodic, unsigned long time_ms) {
pthread_mutex_lock(&mutex_);
if (timer_thread_) {
if (periodic_) {
@@ -151,8 +161,8 @@ bool EventTimerPosix::StartTimer(bool periodic, unsigned long time) {
pthread_mutex_unlock(&mutex_);
return false;
} else {
- // New one shot timer
- time_ = time;
+ // New one shot timer.
+ time_ms_ = time_ms;
created_at_.tv_sec = 0;
timer_event_->Set();
pthread_mutex_unlock(&mutex_);
@@ -160,12 +170,11 @@ bool EventTimerPosix::StartTimer(bool periodic, unsigned long time) {
}
}
- // Start the timer thread
+ // Start the timer thread.
timer_event_.reset(new EventTimerPosix());
- const char* thread_name = "WebRtc_event_timer_thread";
- timer_thread_.reset(new rtc::PlatformThread(Run, this, thread_name));
+ timer_thread_.reset(CreateThread());
periodic_ = periodic;
- time_ = time;
+ time_ms_ = time_ms;
timer_thread_->Start();
timer_thread_->SetPriority(rtc::kRealtimePriority);
pthread_mutex_unlock(&mutex_);
@@ -179,9 +188,13 @@ bool EventTimerPosix::Run(void* obj) {
bool EventTimerPosix::Process() {
pthread_mutex_lock(&mutex_);
+ if (is_stopping_) {
+ pthread_mutex_unlock(&mutex_);
mflodman 2016/03/22 07:47:02 Ouch, I should have spotted this too...
+ return false;
+ }
if (created_at_.tv_sec == 0) {
#ifndef WEBRTC_MAC
- clock_gettime(CLOCK_MONOTONIC, &created_at_);
+ RTC_CHECK_EQ(0, clock_gettime(CLOCK_MONOTONIC, &created_at_));
#else
timeval value;
struct timezone time_zone;
@@ -194,17 +207,27 @@ bool EventTimerPosix::Process() {
}
timespec end_at;
- unsigned long long time = time_ * ++count_;
- end_at.tv_sec = created_at_.tv_sec + time / 1000;
- end_at.tv_nsec = created_at_.tv_nsec + (time - (time / 1000) * 1000) * E6;
+ unsigned long long total_delta_ms = time_ms_ * ++count_;
+ if (!periodic_ && count_ >= 1) {
+ // No need to wake up often if we're not going to signal waiting threads.
+ total_delta_ms =
+ std::min<uint64_t>(total_delta_ms, 60 * kNanosecondsPerSecond);
+ }
- if (end_at.tv_nsec >= E9) {
+ end_at.tv_sec = created_at_.tv_sec + total_delta_ms / 1000;
+ end_at.tv_nsec = created_at_.tv_nsec +
+ (total_delta_ms % 1000) * kNanosecondsPerMillisecond;
+
+ if (end_at.tv_nsec >= kNanosecondsPerSecond) {
end_at.tv_sec++;
- end_at.tv_nsec -= E9;
+ end_at.tv_nsec -= kNanosecondsPerSecond;
}
pthread_mutex_unlock(&mutex_);
- if (timer_event_->Wait(&end_at) == kEventSignaled)
+ // Reset event on first call so that we don't immediately return here if this
+ // thread was not blocked on timer_event_->Wait when the StartTimer() call
+ // was made.
+ if (timer_event_->Wait(&end_at, count_ == 1) == kEventSignaled)
return true;
pthread_mutex_lock(&mutex_);
@@ -216,9 +239,13 @@ bool EventTimerPosix::Process() {
}
bool EventTimerPosix::StopTimer() {
- if (timer_event_) {
+ pthread_mutex_lock(&mutex_);
+ is_stopping_ = true;
+ pthread_mutex_unlock(&mutex_);
+
+ if (timer_event_)
timer_event_->Set();
- }
+
if (timer_thread_) {
timer_thread_->Stop();
timer_thread_.reset();
« no previous file with comments | « webrtc/system_wrappers/source/event_timer_posix.h ('k') | webrtc/system_wrappers/source/event_timer_posix_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698