• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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