diff --git a/webrtc/base/platform_thread.cc b/webrtc/base/platform_thread.cc index 0b025f2af0..d1bd509bf1 100644 --- a/webrtc/base/platform_thread.cc +++ b/webrtc/base/platform_thread.cc @@ -10,6 +10,7 @@ #include "webrtc/base/platform_thread.h" +#include "webrtc/base/atomicops.h" #include "webrtc/base/checks.h" #if defined(WEBRTC_LINUX) @@ -96,15 +97,7 @@ PlatformThread::PlatformThread(ThreadRunFunction func, const char* thread_name) : run_function_(func), obj_(obj), - name_(thread_name ? thread_name : "webrtc"), -#if defined(WEBRTC_WIN) - stop_(false), - thread_(NULL), - thread_id_(0) { -#else - stop_event_(false, false), - thread_(0) { -#endif // defined(WEBRTC_WIN) + name_(thread_name ? thread_name : "webrtc") { RTC_DCHECK(func); RTC_DCHECK(name_.length() < 64); } @@ -187,15 +180,26 @@ void PlatformThread::Stop() { thread_ = nullptr; thread_id_ = 0; #else - stop_event_.Set(); + RTC_CHECK_EQ(1, AtomicOps::Increment(&stop_flag_)); RTC_CHECK_EQ(0, pthread_join(thread_, nullptr)); + AtomicOps::ReleaseStore(&stop_flag_, 0); thread_ = 0; #endif // defined(WEBRTC_WIN) } +// TODO(tommi): Deprecate the loop behavior in PlatformThread. +// * Introduce a new callback type that returns void. +// * Remove potential for a busy loop in PlatformThread. +// * Delegate the responsibility for how to stop the thread, to the +// implementation that actually uses the thread. +// All implementations will need to be aware of how the thread should be stopped +// and encouraging a busy polling loop, can be costly in terms of power and cpu. void PlatformThread::Run() { if (!name_.empty()) rtc::SetCurrentThreadName(name_.c_str()); +#if !defined(WEBRTC_MAC) && !defined(WEBRTC_WIN) + const struct timespec ts_null = {0}; +#endif do { // The interface contract of Start/Stop is that for a successful call to // Start, there should be at least one call to the run function. So we @@ -207,7 +211,12 @@ void PlatformThread::Run() { SleepEx(0, true); } while (!stop_); #else - } while (!stop_event_.Wait(0)); +#if defined(WEBRTC_MAC) + sched_yield(); +#else + nanosleep(&ts_null, nullptr); +#endif + } while (!AtomicOps::AcquireLoad(&stop_flag_)); #endif // defined(WEBRTC_WIN) } diff --git a/webrtc/base/platform_thread.h b/webrtc/base/platform_thread.h index d74aec2811..667407fabc 100644 --- a/webrtc/base/platform_thread.h +++ b/webrtc/base/platform_thread.h @@ -94,15 +94,16 @@ class PlatformThread { #if defined(WEBRTC_WIN) static DWORD WINAPI StartThread(void* param); - bool stop_; - HANDLE thread_; - DWORD thread_id_; + bool stop_ = false; + HANDLE thread_ = nullptr; + DWORD thread_id_ = 0; #else static void* StartThread(void* param); - rtc::Event stop_event_; - - pthread_t thread_; + // An atomic flag that we use to stop the thread. Only modified on the + // controlling thread and checked on the worker thread. + volatile int stop_flag_ = 0; + pthread_t thread_ = 0; #endif // defined(WEBRTC_WIN) RTC_DISALLOW_COPY_AND_ASSIGN(PlatformThread); }; diff --git a/webrtc/modules/utility/source/process_thread_impl_unittest.cc b/webrtc/modules/utility/source/process_thread_impl_unittest.cc index 8f25b112a9..fae4c07884 100644 --- a/webrtc/modules/utility/source/process_thread_impl_unittest.cc +++ b/webrtc/modules/utility/source/process_thread_impl_unittest.cc @@ -85,7 +85,9 @@ TEST(ProcessThreadImpl, ProcessCall) { std::unique_ptr event(EventWrapper::Create()); MockModule module; - EXPECT_CALL(module, TimeUntilNextProcess()).WillRepeatedly(Return(0)); + EXPECT_CALL(module, TimeUntilNextProcess()) + .WillOnce(Return(0)) + .WillRepeatedly(Return(1)); EXPECT_CALL(module, Process()) .WillOnce(DoAll(SetEvent(event.get()), Return())) .WillRepeatedly(Return()); @@ -105,7 +107,9 @@ TEST(ProcessThreadImpl, ProcessCall2) { std::unique_ptr event(EventWrapper::Create()); MockModule module; - EXPECT_CALL(module, TimeUntilNextProcess()).WillRepeatedly(Return(0)); + EXPECT_CALL(module, TimeUntilNextProcess()) + .WillOnce(Return(0)) + .WillRepeatedly(Return(1)); EXPECT_CALL(module, Process()) .WillOnce(DoAll(SetEvent(event.get()), Return())) .WillRepeatedly(Return()); @@ -128,7 +132,9 @@ TEST(ProcessThreadImpl, Deregister) { int process_count = 0; MockModule module; - EXPECT_CALL(module, TimeUntilNextProcess()).WillRepeatedly(Return(0)); + EXPECT_CALL(module, TimeUntilNextProcess()) + .WillOnce(Return(0)) + .WillRepeatedly(Return(1)); EXPECT_CALL(module, Process()) .WillOnce(DoAll(SetEvent(event.get()), Increment(&process_count),