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