Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
4 : // Use of this source code is governed by a BSD-style license that can be
5 : // found in the LICENSE file.
6 :
7 : #ifndef BASE_WAITABLE_EVENT_H_
8 : #define BASE_WAITABLE_EVENT_H_
9 :
10 : #include "base/basictypes.h"
11 :
12 : #if defined(OS_WIN)
13 : #include <windows.h>
14 : #endif
15 :
16 : #if defined(OS_POSIX)
17 : #include <list>
18 : #include <utility>
19 : #include "base/condition_variable.h"
20 : #include "base/lock.h"
21 : #include "nsISupportsImpl.h"
22 : #include "nsAutoPtr.h"
23 : #endif
24 :
25 : #include "base/message_loop.h"
26 :
27 : namespace base {
28 :
29 : // This replaces INFINITE from Win32
30 : static const int kNoTimeout = -1;
31 :
32 : class TimeDelta;
33 :
34 : // A WaitableEvent can be a useful thread synchronization tool when you want to
35 : // allow one thread to wait for another thread to finish some work. For
36 : // non-Windows systems, this can only be used from within a single address
37 : // space.
38 : //
39 : // Use a WaitableEvent when you would otherwise use a Lock+ConditionVariable to
40 : // protect a simple boolean value. However, if you find yourself using a
41 : // WaitableEvent in conjunction with a Lock to wait for a more complex state
42 : // change (e.g., for an item to be added to a queue), then you should probably
43 : // be using a ConditionVariable instead of a WaitableEvent.
44 : //
45 : // NOTE: On Windows, this class provides a subset of the functionality afforded
46 : // by a Windows event object. This is intentional. If you are writing Windows
47 : // specific code and you need other features of a Windows event, then you might
48 : // be better off just using an Windows event directly.
49 : class WaitableEvent {
50 : public:
51 : // If manual_reset is true, then to set the event state to non-signaled, a
52 : // consumer must call the Reset method. If this parameter is false, then the
53 : // system automatically resets the event state to non-signaled after a single
54 : // waiting thread has been released.
55 : WaitableEvent(bool manual_reset, bool initially_signaled);
56 :
57 : ~WaitableEvent();
58 :
59 : // Put the event in the un-signaled state.
60 : void Reset();
61 :
62 : // Put the event in the signaled state. Causing any thread blocked on Wait
63 : // to be woken up.
64 : void Signal();
65 :
66 : // Returns true if the event is in the signaled state, else false. If this
67 : // is not a manual reset event, then this test will cause a reset.
68 : bool IsSignaled();
69 :
70 : // Wait indefinitely for the event to be signaled. Returns true if the event
71 : // was signaled, else false is returned to indicate that waiting failed.
72 : bool Wait();
73 :
74 : // Wait up until max_time has passed for the event to be signaled. Returns
75 : // true if the event was signaled. If this method returns false, then it
76 : // does not necessarily mean that max_time was exceeded.
77 : bool TimedWait(const TimeDelta& max_time);
78 :
79 : #if defined(OS_WIN)
80 : HANDLE handle() const { return handle_; }
81 : #endif
82 :
83 : // Wait, synchronously, on multiple events.
84 : // waitables: an array of WaitableEvent pointers
85 : // count: the number of elements in @waitables
86 : //
87 : // returns: the index of a WaitableEvent which has been signaled.
88 : //
89 : // You MUST NOT delete any of the WaitableEvent objects while this wait is
90 : // happening.
91 : static size_t WaitMany(WaitableEvent** waitables, size_t count);
92 :
93 : // For asynchronous waiting, see WaitableEventWatcher
94 :
95 : // This is a private helper class. It's here because it's used by friends of
96 : // this class (such as WaitableEventWatcher) to be able to enqueue elements
97 : // of the wait-list
98 777 : class Waiter {
99 : public:
100 : // Signal the waiter to wake up.
101 : //
102 : // Consider the case of a Waiter which is in multiple WaitableEvent's
103 : // wait-lists. Each WaitableEvent is automatic-reset and two of them are
104 : // signaled at the same time. Now, each will wake only the first waiter in
105 : // the wake-list before resetting. However, if those two waiters happen to
106 : // be the same object (as can happen if another thread didn't have a chance
107 : // to dequeue the waiter from the other wait-list in time), two auto-resets
108 : // will have happened, but only one waiter has been signaled!
109 : //
110 : // Because of this, a Waiter may "reject" a wake by returning false. In
111 : // this case, the auto-reset WaitableEvent shouldn't act as if anything has
112 : // been notified.
113 : virtual bool Fire(WaitableEvent* signaling_event) = 0;
114 :
115 : // Waiters may implement this in order to provide an extra condition for
116 : // two Waiters to be considered equal. In WaitableEvent::Dequeue, if the
117 : // pointers match then this function is called as a final check. See the
118 : // comments in ~Handle for why.
119 : virtual bool Compare(void* tag) = 0;
120 : };
121 :
122 : private:
123 : friend class WaitableEventWatcher;
124 :
125 : #if defined(OS_WIN)
126 : HANDLE handle_;
127 : #else
128 : // On Windows, one can close a HANDLE which is currently being waited on. The
129 : // MSDN documentation says that the resulting behaviour is 'undefined', but
130 : // it doesn't crash. However, if we were to include the following members
131 : // directly then, on POSIX, one couldn't use WaitableEventWatcher to watch an
132 : // event which gets deleted. This mismatch has bitten us several times now,
133 : // so we have a kernel of the WaitableEvent, which is reference counted.
134 : // WaitableEventWatchers may then take a reference and thus match the Windows
135 : // behaviour.
136 : struct WaitableEventKernel final {
137 : public:
138 90 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WaitableEventKernel)
139 72 : WaitableEventKernel(bool manual_reset, bool initially_signaled)
140 72 : : manual_reset_(manual_reset),
141 72 : signaled_(initially_signaled) {
142 72 : }
143 :
144 : bool Dequeue(Waiter* waiter, void* tag);
145 :
146 : Lock lock_;
147 : const bool manual_reset_;
148 : bool signaled_;
149 : std::list<Waiter*> waiters_;
150 : protected:
151 9 : ~WaitableEventKernel() {}
152 : };
153 :
154 : RefPtr<WaitableEventKernel> kernel_;
155 :
156 : bool SignalAll();
157 : bool SignalOne();
158 : void Enqueue(Waiter* waiter);
159 :
160 : // When dealing with arrays of WaitableEvent*, we want to sort by the address
161 : // of the WaitableEvent in order to have a globally consistent locking order.
162 : // In that case we keep them, in sorted order, in an array of pairs where the
163 : // second element is the index of the WaitableEvent in the original,
164 : // unsorted, array.
165 : typedef std::pair<WaitableEvent*, size_t> WaiterAndIndex;
166 : static size_t EnqueueMany(WaiterAndIndex* waitables,
167 : size_t count, Waiter* waiter);
168 : #endif
169 :
170 : DISALLOW_COPY_AND_ASSIGN(WaitableEvent);
171 : };
172 :
173 : } // namespace base
174 :
175 : #endif // BASE_WAITABLE_EVENT_H_
|