diff --git a/modules/audio_coding/test/iSACTest.cc b/modules/audio_coding/test/iSACTest.cc index 7120cac30c..e9fd867e03 100644 --- a/modules/audio_coding/test/iSACTest.cc +++ b/modules/audio_coding/test/iSACTest.cc @@ -26,7 +26,7 @@ #include "api/audio_codecs/builtin_audio_decoder_factory.h" #include "modules/audio_coding/codecs/audio_format_conversion.h" #include "modules/audio_coding/test/utility.h" -#include "system_wrappers/include/sleep.h" +#include "system_wrappers/include/event_wrapper.h" #include "test/testsupport/fileutils.h" namespace webrtc { @@ -251,19 +251,15 @@ void ISACTest::EncodeDecode(int testNr, _channel_B2A->ResetStats(); char currentTime[500]; - int64_t time_ms = rtc::TimeMillis(); + EventTimerWrapper* myEvent = EventTimerWrapper::Create(); + EXPECT_TRUE(myEvent->StartTimer(true, 10)); while (!(_inFileA.EndOfFile() || _inFileA.Rewinded())) { Run10ms(); _myTimer.Tick10ms(); _myTimer.CurrentTimeHMS(currentTime); if ((adaptiveMode) && (_testMode != 0)) { - time_ms += 10; - int64_t time_left_ms = time_ms - rtc::TimeMillis(); - if (time_left_ms > 0) { - SleepMs(time_left_ms); - } - + myEvent->Wait(5000); EXPECT_TRUE(_acmA->SendCodec()); EXPECT_TRUE(_acmB->SendCodec()); } diff --git a/system_wrappers/BUILD.gn b/system_wrappers/BUILD.gn index 9b470d161f..106c63b055 100644 --- a/system_wrappers/BUILD.gn +++ b/system_wrappers/BUILD.gn @@ -25,6 +25,8 @@ rtc_static_library("system_wrappers") { "source/cpu_features.cc", "source/cpu_info.cc", "source/event.cc", + "source/event_timer_win.cc", + "source/event_timer_win.h", "source/rtp_to_ntp_estimator.cc", "source/sleep.cc", ] @@ -44,6 +46,13 @@ rtc_static_library("system_wrappers") { "//third_party/abseil-cpp/absl/types:optional", ] + if (is_posix || is_fuchsia) { + sources += [ + "source/event_timer_posix.cc", + "source/event_timer_posix.h", + ] + } + if (is_android) { defines += [ "WEBRTC_THREAD_RR" ] @@ -200,6 +209,10 @@ if (rtc_include_tests) { "source/rtp_to_ntp_estimator_unittest.cc", ] + if (is_posix || is_fuchsia) { + sources += [ "source/event_timer_posix_unittest.cc" ] + } + deps = [ ":metrics_api", ":metrics_default", diff --git a/system_wrappers/include/event_wrapper.h b/system_wrappers/include/event_wrapper.h index 0531ddb563..0c29138203 100644 --- a/system_wrappers/include/event_wrapper.h +++ b/system_wrappers/include/event_wrapper.h @@ -20,6 +20,8 @@ enum EventTypeWrapper { #define WEBRTC_EVENT_INFINITE 0xffffffff +class EventTimerWrapper; + class EventWrapper { public: // Factory method. Constructor disabled. @@ -48,6 +50,20 @@ class EventWrapper { virtual EventTypeWrapper Wait(unsigned long max_time) = 0; }; +class EventTimerWrapper : public EventWrapper { + public: + static EventTimerWrapper* Create(); + + // Starts a timer that will call a non-sticky version of Set() either once + // or periodically. If the timer is periodic it ensures that there is no + // drift over time relative to the system clock. + // + // |time| is in milliseconds. + virtual bool StartTimer(bool periodic, unsigned long time) = 0; + + virtual bool StopTimer() = 0; +}; + } // namespace webrtc #endif // SYSTEM_WRAPPERS_INCLUDE_EVENT_WRAPPER_H_ diff --git a/system_wrappers/source/event.cc b/system_wrappers/source/event.cc index d1d2cdaff0..aac69f6e02 100644 --- a/system_wrappers/source/event.cc +++ b/system_wrappers/source/event.cc @@ -12,11 +12,14 @@ #if defined(_WIN32) #include +#include "system_wrappers/source/event_timer_win.h" #elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) #include #include +#include "system_wrappers/source/event_timer_posix.h" #else #include +#include "system_wrappers/source/event_timer_posix.h" #endif #include "rtc_base/event.h" diff --git a/system_wrappers/source/event_timer_posix.cc b/system_wrappers/source/event_timer_posix.cc new file mode 100644 index 0000000000..e79aa9900a --- /dev/null +++ b/system_wrappers/source/event_timer_posix.cc @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "system_wrappers/source/event_timer_posix.h" + +#if defined(WEBRTC_ANDROID) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "rtc_base/checks.h" + +#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) +// Chromium build is always defining this macro if __ANDROID_API__ < 20. +#undef HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC +#endif + +#if defined(WEBRTC_ANDROID) && defined(__ANDROID_API__) +#define HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC (__ANDROID_API__ < 21) +#else +#define HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC 0 +#endif + +namespace webrtc { + +// static +EventTimerWrapper* EventTimerWrapper::Create() { + return new EventTimerPosix(); +} + +const int64_t kNanosecondsPerMillisecond = 1000000; +const int64_t kNanosecondsPerSecond = 1000000000; + +EventTimerPosix::EventTimerPosix() + : event_set_(false), + timer_thread_(nullptr), + created_at_(), + periodic_(false), + time_ms_(0), + count_(0), + is_stopping_(false) { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mutex_, &attr); + pthread_condattr_t cond_attr; + pthread_condattr_init(&cond_attr); +// TODO(sprang): Remove HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC special case once +// all supported Android platforms support pthread_condattr_setclock. +// TODO(sprang): Add support for monotonic clock on Apple platforms. +#if !(defined(WEBRTC_MAC) || defined(WEBRTC_IOS)) && \ + !(defined(WEBRTC_ANDROID) && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) + pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC); +#endif + pthread_cond_init(&cond_, &cond_attr); + pthread_condattr_destroy(&cond_attr); +} + +EventTimerPosix::~EventTimerPosix() { + StopTimer(); + pthread_cond_destroy(&cond_); + pthread_mutex_destroy(&mutex_); +} + +// TODO(pbos): Make this void. +bool EventTimerPosix::Set() { + RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_)); + event_set_ = true; + pthread_cond_signal(&cond_); + pthread_mutex_unlock(&mutex_); + return true; +} + +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_ms) { + timespec end_at; +#ifndef WEBRTC_MAC + clock_gettime(CLOCK_MONOTONIC, &end_at); +#else + timeval value; + struct timezone time_zone; + time_zone.tz_minuteswest = 0; + time_zone.tz_dsttime = 0; + gettimeofday(&value, &time_zone); + TIMEVAL_TO_TIMESPEC(&value, &end_at); +#endif + end_at.tv_sec += timeout_ms / 1000; + end_at.tv_nsec += (timeout_ms % 1000) * kNanosecondsPerMillisecond; + + if (end_at.tv_nsec >= kNanosecondsPerSecond) { + end_at.tv_sec++; + end_at.tv_nsec -= kNanosecondsPerSecond; + } + while (ret_val == 0 && !event_set_) { +#if defined(WEBRTC_ANDROID) && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC + ret_val = pthread_cond_timedwait_monotonic_np(&cond_, &mutex_, &end_at); +#else + ret_val = pthread_cond_timedwait(&cond_, &mutex_, &end_at); +#endif // WEBRTC_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC + } + } else { + while (ret_val == 0 && !event_set_) + ret_val = pthread_cond_wait(&cond_, &mutex_); + } + } + + RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT); + + // Reset and signal if set, regardless of why the thread woke up. + if (event_set_) { + ret_val = 0; + event_set_ = false; + } + pthread_mutex_unlock(&mutex_); + + return ret_val == 0 ? kEventSignaled : kEventTimeout; +} + +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) && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC + ret_val = pthread_cond_timedwait_monotonic_np(&cond_, &mutex_, end_at); +#else + ret_val = pthread_cond_timedwait(&cond_, &mutex_, end_at); +#endif // WEBRTC_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC + } + + RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT); + + // Reset and signal if set, regardless of why the thread woke up. + if (event_set_) { + ret_val = 0; + event_set_ = false; + } + pthread_mutex_unlock(&mutex_); + + return ret_val == 0 ? kEventSignaled : kEventTimeout; +} + +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_) { + // Timer already started. + pthread_mutex_unlock(&mutex_); + return false; + } else { + // New one shot timer. + time_ms_ = time_ms; + created_at_.tv_sec = 0; + timer_event_->Set(); + pthread_mutex_unlock(&mutex_); + return true; + } + } + + // Start the timer thread. + timer_event_.reset(new EventTimerPosix()); + timer_thread_.reset(CreateThread()); + periodic_ = periodic; + time_ms_ = time_ms; + timer_thread_->Start(); + timer_thread_->SetPriority(rtc::kRealtimePriority); + pthread_mutex_unlock(&mutex_); + + return true; +} + +bool EventTimerPosix::Run(void* obj) { + return static_cast(obj)->Process(); +} + +bool EventTimerPosix::Process() { + pthread_mutex_lock(&mutex_); + if (is_stopping_) { + pthread_mutex_unlock(&mutex_); + return false; + } + if (created_at_.tv_sec == 0) { +#ifndef WEBRTC_MAC + RTC_CHECK_EQ(0, clock_gettime(CLOCK_MONOTONIC, &created_at_)); +#else + timeval value; + struct timezone time_zone; + time_zone.tz_minuteswest = 0; + time_zone.tz_dsttime = 0; + gettimeofday(&value, &time_zone); + TIMEVAL_TO_TIMESPEC(&value, &created_at_); +#endif + count_ = 0; + } + + timespec end_at; + 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(total_delta_ms, 60 * kNanosecondsPerSecond); + } + + 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 -= kNanosecondsPerSecond; + } + + pthread_mutex_unlock(&mutex_); + // 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_); + if (periodic_ || count_ == 1) + Set(); + pthread_mutex_unlock(&mutex_); + + return true; +} + +bool EventTimerPosix::StopTimer() { + 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(); + } + timer_event_.reset(); + + // Set time to zero to force new reference time for the timer. + memset(&created_at_, 0, sizeof(created_at_)); + count_ = 0; + return true; +} + +} // namespace webrtc diff --git a/system_wrappers/source/event_timer_posix.h b/system_wrappers/source/event_timer_posix.h new file mode 100644 index 0000000000..72d6753e53 --- /dev/null +++ b/system_wrappers/source/event_timer_posix.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_ +#define SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_ + +#include "system_wrappers/include/event_wrapper.h" + +#include + +#include +#include + +#include "rtc_base/platform_thread.h" + +namespace webrtc { + +enum State { kUp = 1, kDown = 2 }; + +class EventTimerPosix : public EventTimerWrapper { + public: + EventTimerPosix(); + ~EventTimerPosix() override; + + EventTypeWrapper Wait(unsigned long max_time) override; + bool Set() override; + + bool StartTimer(bool periodic, unsigned long time) override; + bool StopTimer() override; + + private: + friend class EventTimerPosixTest; + + static bool Run(void* obj); + bool Process(); + EventTypeWrapper Wait(timespec* end_at, bool reset_state); + + virtual rtc::PlatformThread* CreateThread(); + + pthread_cond_t cond_; + pthread_mutex_t mutex_; + bool event_set_; + + // TODO(pbos): Remove unique_ptr and use PlatformThread directly. + std::unique_ptr timer_thread_; + std::unique_ptr timer_event_; + timespec created_at_; + + bool periodic_; + unsigned long time_ms_; + unsigned long count_; + bool is_stopping_; +}; + +} // namespace webrtc + +#endif // SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_ diff --git a/system_wrappers/source/event_timer_posix_unittest.cc b/system_wrappers/source/event_timer_posix_unittest.cc new file mode 100644 index 0000000000..88fd90aef8 --- /dev/null +++ b/system_wrappers/source/event_timer_posix_unittest.cc @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "system_wrappers/source/event_timer_posix.h" + +#include "rtc_base/criticalsection.h" +#include "rtc_base/event.h" +#include "test/gtest.h" + +namespace webrtc { + +enum class ThreadState { + kNotStarted, + kWaiting, + kRequestProcessCall, + kCallingProcess, + kProcessDone, + kContinue, + kExiting, + kDead +}; + +class EventTimerPosixTest : public testing::Test, public EventTimerPosix { + public: + EventTimerPosixTest() + : thread_state_(ThreadState::kNotStarted), + process_event_(false, true), + main_event_(false, true), + process_thread_id_(0), + process_thread_(nullptr) {} + ~EventTimerPosixTest() override {} + + rtc::PlatformThread* CreateThread() override { + EXPECT_TRUE(process_thread_ == nullptr); + process_thread_ = + new rtc::PlatformThread(Run, this, "EventTimerPosixTestThread"); + return process_thread_; + } + + static bool Run(void* obj) { + return static_cast(obj)->Process(); + } + + bool Process() { + bool res = ProcessInternal(); + if (!res) { + rtc::CritScope cs(&lock_); + thread_state_ = ThreadState::kDead; + main_event_.Set(); + } + return res; + } + + bool ProcessInternal() { + { + rtc::CritScope cs(&lock_); + if (thread_state_ == ThreadState::kNotStarted) { + if (!ChangeThreadState(ThreadState::kNotStarted, + ThreadState::kContinue)) { + ADD_FAILURE() << "Unable to start process thread"; + return false; + } + process_thread_id_ = rtc::CurrentThreadId(); + } + } + + if (!ChangeThreadState(ThreadState::kContinue, ThreadState::kWaiting)) + return false; + + if (!AwaitThreadState(ThreadState::kRequestProcessCall, + rtc::Event::kForever)) + return false; + + if (!ChangeThreadState(ThreadState::kRequestProcessCall, + ThreadState::kCallingProcess)) + return false; + + EventTimerPosix::Process(); + + if (!ChangeThreadState(ThreadState::kCallingProcess, + ThreadState::kProcessDone)) + return false; + + if (!AwaitThreadState(ThreadState::kContinue, rtc::Event::kForever)) + return false; + + return true; + } + + bool IsProcessThread() { + rtc::CritScope cs(&lock_); + return process_thread_id_ == rtc::CurrentThreadId(); + } + + bool ChangeThreadState(ThreadState prev_state, ThreadState new_state) { + rtc::CritScope cs(&lock_); + if (thread_state_ != prev_state) + return false; + thread_state_ = new_state; + if (IsProcessThread()) { + main_event_.Set(); + } else { + process_event_.Set(); + } + return true; + } + + bool AwaitThreadState(ThreadState state, int timeout) { + rtc::Event* event = IsProcessThread() ? &process_event_ : &main_event_; + do { + rtc::CritScope cs(&lock_); + if (state != ThreadState::kDead && thread_state_ == ThreadState::kExiting) + return false; + if (thread_state_ == state) + return true; + } while (event->Wait(timeout)); + return false; + } + + bool CallProcess(int timeout_ms) { + return AwaitThreadState(ThreadState::kWaiting, timeout_ms) && + ChangeThreadState(ThreadState::kWaiting, + ThreadState::kRequestProcessCall); + } + + bool AwaitProcessDone(int timeout_ms) { + return AwaitThreadState(ThreadState::kProcessDone, timeout_ms) && + ChangeThreadState(ThreadState::kProcessDone, ThreadState::kContinue); + } + + void TearDown() override { + if (process_thread_) { + { + rtc::CritScope cs(&lock_); + if (thread_state_ != ThreadState::kDead) { + thread_state_ = ThreadState::kExiting; + process_event_.Set(); + } + } + ASSERT_TRUE(AwaitThreadState(ThreadState::kDead, 5000)); + } + } + + ThreadState thread_state_; + rtc::CriticalSection lock_; + rtc::Event process_event_; + rtc::Event main_event_; + rtc::PlatformThreadId process_thread_id_; + rtc::PlatformThread* process_thread_; +}; + +TEST_F(EventTimerPosixTest, WaiterBlocksUntilTimeout) { + const int kTimerIntervalMs = 100; + const int kTimeoutMs = 5000; + ASSERT_TRUE(StartTimer(false, kTimerIntervalMs)); + ASSERT_TRUE(CallProcess(kTimeoutMs)); + EventTypeWrapper res = Wait(kTimeoutMs); + EXPECT_EQ(kEventSignaled, res); + ASSERT_TRUE(AwaitProcessDone(kTimeoutMs)); +} + +TEST_F(EventTimerPosixTest, WaiterWakesImmediatelyAfterTimeout) { + const int kTimerIntervalMs = 100; + const int kTimeoutMs = 5000; + ASSERT_TRUE(StartTimer(false, kTimerIntervalMs)); + ASSERT_TRUE(CallProcess(kTimeoutMs)); + ASSERT_TRUE(AwaitProcessDone(kTimeoutMs)); + EventTypeWrapper res = Wait(0); + EXPECT_EQ(kEventSignaled, res); +} + +TEST_F(EventTimerPosixTest, WaiterBlocksUntilTimeoutProcessInactiveOnStart) { + const int kTimerIntervalMs = 100; + const int kTimeoutMs = 5000; + // First call to StartTimer initializes thread. + ASSERT_TRUE(StartTimer(false, kTimerIntervalMs)); + + // Process thread currently _not_ blocking on Process() call. + ASSERT_TRUE(AwaitThreadState(ThreadState::kWaiting, kTimeoutMs)); + + // Start new one-off timer, then call Process(). + ASSERT_TRUE(StartTimer(false, kTimerIntervalMs)); + ASSERT_TRUE(CallProcess(kTimeoutMs)); + + EventTypeWrapper res = Wait(kTimeoutMs); + EXPECT_EQ(kEventSignaled, res); + + ASSERT_TRUE(AwaitProcessDone(kTimeoutMs)); +} + +} // namespace webrtc diff --git a/system_wrappers/source/event_timer_win.cc b/system_wrappers/source/event_timer_win.cc new file mode 100644 index 0000000000..c2ad9f372a --- /dev/null +++ b/system_wrappers/source/event_timer_win.cc @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "system_wrappers/source/event_timer_win.h" + +#include "mmsystem.h" + +namespace webrtc { + +// static +EventTimerWrapper* EventTimerWrapper::Create() { + return new EventTimerWin(); +} + +EventTimerWin::EventTimerWin() + : event_(::CreateEvent(NULL, // security attributes + FALSE, // manual reset + FALSE, // initial state + NULL)), // name of event + timerID_(NULL) {} + +EventTimerWin::~EventTimerWin() { + StopTimer(); + CloseHandle(event_); +} + +bool EventTimerWin::Set() { + // Note: setting an event that is already set has no effect. + return SetEvent(event_) == 1; +} + +EventTypeWrapper EventTimerWin::Wait(unsigned long max_time) { + unsigned long res = WaitForSingleObject(event_, max_time); + switch (res) { + case WAIT_OBJECT_0: + return kEventSignaled; + case WAIT_TIMEOUT: + return kEventTimeout; + default: + return kEventError; + } +} + +bool EventTimerWin::StartTimer(bool periodic, unsigned long time) { + if (timerID_ != NULL) { + timeKillEvent(timerID_); + timerID_ = NULL; + } + + if (periodic) { + timerID_ = timeSetEvent(time, 0, (LPTIMECALLBACK)HANDLE(event_), 0, + TIME_PERIODIC | TIME_CALLBACK_EVENT_PULSE); + } else { + timerID_ = timeSetEvent(time, 0, (LPTIMECALLBACK)HANDLE(event_), 0, + TIME_ONESHOT | TIME_CALLBACK_EVENT_SET); + } + + return timerID_ != NULL; +} + +bool EventTimerWin::StopTimer() { + if (timerID_ != NULL) { + timeKillEvent(timerID_); + timerID_ = NULL; + } + + return true; +} + +} // namespace webrtc diff --git a/system_wrappers/source/event_timer_win.h b/system_wrappers/source/event_timer_win.h new file mode 100644 index 0000000000..c99f8c66d6 --- /dev/null +++ b/system_wrappers/source/event_timer_win.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_ +#define SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_ + +#include + +#include + +#include "system_wrappers/include/event_wrapper.h" + +namespace webrtc { + +class EventTimerWin : public EventTimerWrapper { + public: + EventTimerWin(); + ~EventTimerWin() override; + + EventTypeWrapper Wait(unsigned long max_time) override; + bool Set() override; + + bool StartTimer(bool periodic, unsigned long time) override; + bool StopTimer() override; + + private: + HANDLE event_; + uint32_t timerID_; +}; + +} // namespace webrtc + +#endif // SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_