1 /* 2 * Copyright 2004 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 11 #ifndef RTC_BASE_EVENT_H_ 12 #define RTC_BASE_EVENT_H_ 13 14 #include "api/units/time_delta.h" 15 16 #if defined(WEBRTC_WIN) 17 #include <windows.h> 18 #elif defined(WEBRTC_POSIX) 19 #include <pthread.h> 20 #else 21 #error "Must define either WEBRTC_WIN or WEBRTC_POSIX." 22 #endif 23 24 #include "rtc_base/synchronization/yield_policy.h" 25 26 namespace rtc { 27 28 // RTC_DISALLOW_WAIT() utility 29 // 30 // Sets a stack-scoped flag that disallows use of `rtc::Event::Wait` by means 31 // of raising a DCHECK when a call to `rtc::Event::Wait()` is made.. 32 // This is useful to guard synchronization-free scopes against regressions. 33 // 34 // Example of what this would catch (`ScopeToProtect` calls `Foo`): 35 // 36 // void Foo(TaskQueue* tq) { 37 // Event event; 38 // tq->PostTask([&event]() { 39 // event.Set(); 40 // }); 41 // event.Wait(Event::kForever); // <- Will trigger a DCHECK. 42 // } 43 // 44 // void ScopeToProtect() { 45 // TaskQueue* tq = GetSomeTaskQueue(); 46 // RTC_DISALLOW_WAIT(); // Policy takes effect. 47 // Foo(tq); 48 // } 49 // 50 #if RTC_DCHECK_IS_ON 51 #define RTC_DISALLOW_WAIT() ScopedDisallowWait disallow_wait_##__LINE__ 52 #else 53 #define RTC_DISALLOW_WAIT() 54 #endif 55 56 class Event { 57 public: 58 // TODO(bugs.webrtc.org/14366): Consider removing this redundant alias. 59 static constexpr webrtc::TimeDelta kForever = 60 webrtc::TimeDelta::PlusInfinity(); 61 62 Event(); 63 Event(bool manual_reset, bool initially_signaled); 64 Event(const Event&) = delete; 65 Event& operator=(const Event&) = delete; 66 ~Event(); 67 68 void Set(); 69 void Reset(); 70 71 // Waits for the event to become signaled, but logs a warning if it takes more 72 // than `warn_after`, and gives up completely if it takes more than 73 // `give_up_after`. (If `warn_after >= give_up_after`, no warning will be 74 // logged.) Either or both may be `kForever`, which means wait indefinitely. 75 // 76 // Care is taken so that the underlying OS wait call isn't requested to sleep 77 // shorter than `give_up_after`. 78 // 79 // Returns true if the event was signaled, false if there was a timeout or 80 // some other error. 81 bool Wait(webrtc::TimeDelta give_up_after, webrtc::TimeDelta warn_after); 82 83 // Waits with the given timeout and a reasonable default warning timeout. Wait(webrtc::TimeDelta give_up_after)84 bool Wait(webrtc::TimeDelta give_up_after) { 85 return Wait(give_up_after, give_up_after.IsPlusInfinity() 86 ? webrtc::TimeDelta::Seconds(3) 87 : kForever); 88 } 89 90 private: 91 #if defined(WEBRTC_WIN) 92 HANDLE event_handle_; 93 #elif defined(WEBRTC_POSIX) 94 pthread_mutex_t event_mutex_; 95 pthread_cond_t event_cond_; 96 const bool is_manual_reset_; 97 bool event_status_; 98 #endif 99 }; 100 101 // These classes are provided for compatibility with Chromium. 102 // The rtc::Event implementation is overriden inside of Chromium for the 103 // purposes of detecting when threads are blocked that shouldn't be as well as 104 // to use the more accurate event implementation that's there than is provided 105 // by default on some platforms (e.g. Windows). 106 // When building with standalone WebRTC, this class is a noop. 107 // For further information, please see the 108 // ScopedAllowBaseSyncPrimitives(ForTesting) classes in Chromium. 109 class ScopedAllowBaseSyncPrimitives { 110 public: ScopedAllowBaseSyncPrimitives()111 ScopedAllowBaseSyncPrimitives() {} ~ScopedAllowBaseSyncPrimitives()112 ~ScopedAllowBaseSyncPrimitives() {} 113 }; 114 115 class ScopedAllowBaseSyncPrimitivesForTesting { 116 public: ScopedAllowBaseSyncPrimitivesForTesting()117 ScopedAllowBaseSyncPrimitivesForTesting() {} ~ScopedAllowBaseSyncPrimitivesForTesting()118 ~ScopedAllowBaseSyncPrimitivesForTesting() {} 119 }; 120 121 #if RTC_DCHECK_IS_ON 122 class ScopedDisallowWait { 123 public: 124 ScopedDisallowWait() = default; 125 126 private: 127 class DisallowYieldHandler : public YieldInterface { 128 public: YieldExecution()129 void YieldExecution() override { RTC_DCHECK_NOTREACHED(); } 130 } handler_; 131 rtc::ScopedYieldPolicy policy{&handler_}; 132 }; 133 #endif 134 135 } // namespace rtc 136 137 #endif // RTC_BASE_EVENT_H_ 138