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
19namespace 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.
28class 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.
80class 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