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