ipc/chromium/src/base/waitable_event.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial