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