1 // Copyright 2013 The Flutter Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Provides classes with functionality analogous to (but much more limited than) 6 // Chromium's |base::WaitableEvent|, which in turn provides functionality 7 // analogous to Windows's Event. (Unlike these two, we have separate types for 8 // the manual- and auto-reset versions.) 9 10 #ifndef FLUTTER_FML_SYNCHRONIZATION_WAITABLE_EVENT_H_ 11 #define FLUTTER_FML_SYNCHRONIZATION_WAITABLE_EVENT_H_ 12 13 #include <condition_variable> 14 #include <mutex> 15 16 #include "flutter/fml/macros.h" 17 #include "flutter/fml/synchronization/thread_annotations.h" 18 #include "flutter/fml/time/time_delta.h" 19 20 namespace fml { 21 22 // AutoResetWaitableEvent ------------------------------------------------------ 23 24 // An event that can be signaled and waited on. This version automatically 25 // returns to the unsignaled state after unblocking one waiter. (This is similar 26 // to Windows's auto-reset Event, which is also imitated by Chromium's 27 // auto-reset |base::WaitableEvent|. However, there are some limitations -- see 28 // |Signal()|.) This class is thread-safe. 29 class AutoResetWaitableEvent final { 30 public: AutoResetWaitableEvent()31 AutoResetWaitableEvent() {} ~AutoResetWaitableEvent()32 ~AutoResetWaitableEvent() {} 33 34 // Put the event in the signaled state. Exactly one |Wait()| will be unblocked 35 // and the event will be returned to the unsignaled state. 36 // 37 // Notes (these are arguably bugs, but not worth working around): 38 // * That |Wait()| may be one that occurs on the calling thread, *after* the 39 // call to |Signal()|. 40 // * A |Signal()|, followed by a |Reset()|, may cause *no* waiting thread to 41 // be unblocked. 42 // * We rely on pthreads's queueing for picking which waiting thread to 43 // unblock, rather than enforcing FIFO ordering. 44 void Signal(); 45 46 // Put the event into the unsignaled state. Generally, this is not recommended 47 // on an auto-reset event (see notes above). 48 void Reset(); 49 50 // Blocks the calling thread until the event is signaled. Upon unblocking, the 51 // event is returned to the unsignaled state, so that (unless |Reset()| is 52 // called) each |Signal()| unblocks exactly one |Wait()|. 53 void Wait(); 54 55 // Like |Wait()|, but with a timeout. Also unblocks if |timeout_microseconds| 56 // without being signaled in which case it returns true (otherwise, it returns 57 // false). 58 bool WaitWithTimeout(TimeDelta timeout); 59 60 // Returns whether this event is in a signaled state or not. For use in tests 61 // only (in general, this is racy). Note: Unlike 62 // |base::WaitableEvent::IsSignaled()|, this doesn't reset the signaled state. 63 bool IsSignaledForTest(); 64 65 private: 66 std::condition_variable cv_; 67 std::mutex mutex_; 68 69 // True if this event is in the signaled state. 70 bool signaled_ = false; 71 72 FML_DISALLOW_COPY_AND_ASSIGN(AutoResetWaitableEvent); 73 }; 74 75 // ManualResetWaitableEvent ---------------------------------------------------- 76 77 // An event that can be signaled and waited on. This version remains signaled 78 // until explicitly reset. (This is similar to Windows's manual-reset Event, 79 // which is also imitated by Chromium's manual-reset |base::WaitableEvent|.) 80 // This class is thread-safe. 81 class ManualResetWaitableEvent final { 82 public: ManualResetWaitableEvent()83 ManualResetWaitableEvent() {} ~ManualResetWaitableEvent()84 ~ManualResetWaitableEvent() {} 85 86 // Put the event into the unsignaled state. 87 void Reset(); 88 89 // Put the event in the signaled state. If this is a manual-reset event, it 90 // wakes all waiting threads (blocked on |Wait()| or |WaitWithTimeout()|). 91 // Otherwise, it wakes a single waiting thread (and returns to the unsignaled 92 // state), if any; if there are none, it remains signaled. 93 void Signal(); 94 95 // Blocks the calling thread until the event is signaled. 96 void Wait(); 97 98 // Like |Wait()|, but with a timeout. Also unblocks if |timeout_microseconds| 99 // without being signaled in which case it returns true (otherwise, it returns 100 // false). 101 bool WaitWithTimeout(TimeDelta timeout); 102 103 // Returns whether this event is in a signaled state or not. For use in tests 104 // only (in general, this is racy). 105 bool IsSignaledForTest(); 106 107 private: 108 std::condition_variable cv_; 109 std::mutex mutex_; 110 111 // True if this event is in the signaled state. 112 bool signaled_ = false; 113 114 // While |std::condition_variable::notify_all()| (|pthread_cond_broadcast()|) 115 // will wake all waiting threads, one has to deal with spurious wake-ups. 116 // Checking |signaled_| isn't sufficient, since another thread may have been 117 // awoken and (manually) reset |signaled_|. This is a counter that is 118 // incremented in |Signal()| before calling 119 // |std::condition_variable::notify_all()|. A waiting thread knows it was 120 // awoken if |signal_id_| is different from when it started waiting. 121 unsigned signal_id_ = 0u; 122 123 FML_DISALLOW_COPY_AND_ASSIGN(ManualResetWaitableEvent); 124 }; 125 126 } // namespace fml 127 128 #endif // FLUTTER_FML_SYNCHRONIZATION_WAITABLE_EVENT_H_ 129