tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

waitable_event.h (10698B)


      1 // Copyright 2012 The Chromium Authors
      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 
      8 #include <stddef.h>
      9 
     10 #include "base/base_export.h"
     11 #include "base/compiler_specific.h"
     12 #include "build/build_config.h"
     13 
     14 #if BUILDFLAG(IS_WIN)
     15 #include "base/win/scoped_handle.h"
     16 #elif BUILDFLAG(IS_APPLE)
     17 #include <mach/mach.h>
     18 
     19 #include <list>
     20 #include <memory>
     21 
     22 #include "base/apple/scoped_mach_port.h"
     23 #include "base/functional/callback_forward.h"
     24 #include "base/memory/ref_counted.h"
     25 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
     26 #include <list>
     27 #include <utility>
     28 
     29 #include "base/memory/ref_counted.h"
     30 #include "base/synchronization/lock.h"
     31 #endif
     32 
     33 namespace base {
     34 
     35 class TimeDelta;
     36 
     37 // A WaitableEvent can be a useful thread synchronization tool when you want to
     38 // allow one thread to wait for another thread to finish some work. For
     39 // non-Windows systems, this can only be used from within a single address
     40 // space.
     41 //
     42 // Use a WaitableEvent when you would otherwise use a Lock+ConditionVariable to
     43 // protect a simple boolean value.  However, if you find yourself using a
     44 // WaitableEvent in conjunction with a Lock to wait for a more complex state
     45 // change (e.g., for an item to be added to a queue), then you should probably
     46 // be using a ConditionVariable instead of a WaitableEvent.
     47 //
     48 // NOTE: On Windows, this class provides a subset of the functionality afforded
     49 // by a Windows event object.  This is intentional.  If you are writing Windows
     50 // specific code and you need other features of a Windows event, then you might
     51 // be better off just using an Windows event directly.
     52 class BASE_EXPORT WaitableEvent {
     53 public:
     54  // Indicates whether a WaitableEvent should automatically reset the event
     55  // state after a single waiting thread has been released or remain signaled
     56  // until Reset() is manually invoked.
     57  enum class ResetPolicy { MANUAL, AUTOMATIC };
     58 
     59  // Indicates whether a new WaitableEvent should start in a signaled state or
     60  // not.
     61  enum class InitialState { SIGNALED, NOT_SIGNALED };
     62 
     63  // Constructs a WaitableEvent with policy and initial state as detailed in
     64  // the above enums.
     65  WaitableEvent(ResetPolicy reset_policy = ResetPolicy::MANUAL,
     66                InitialState initial_state = InitialState::NOT_SIGNALED);
     67 
     68 #if BUILDFLAG(IS_WIN)
     69  // Create a WaitableEvent from an Event HANDLE which has already been
     70  // created. This objects takes ownership of the HANDLE and will close it when
     71  // deleted.
     72  explicit WaitableEvent(win::ScopedHandle event_handle);
     73 #endif
     74 
     75  WaitableEvent(const WaitableEvent&) = delete;
     76  WaitableEvent& operator=(const WaitableEvent&) = delete;
     77 
     78  ~WaitableEvent();
     79 
     80  // Put the event in the un-signaled state.
     81  void Reset();
     82 
     83  // Put the event in the signaled state.  Causing any thread blocked on Wait
     84  // to be woken up.
     85  void Signal();
     86 
     87  // Returns true if the event is in the signaled state, else false.  If this
     88  // is not a manual reset event, then this test will cause a reset.
     89  bool IsSignaled();
     90 
     91  // Wait indefinitely for the event to be signaled. Wait's return "happens
     92  // after" |Signal| has completed. This means that it's safe for a
     93  // WaitableEvent to synchronise its own destruction, like this:
     94  //
     95  //   WaitableEvent *e = new WaitableEvent;
     96  //   SendToOtherThread(e);
     97  //   e->Wait();
     98  //   delete e;
     99  NOT_TAIL_CALLED void Wait();
    100 
    101  // Wait up until wait_delta has passed for the event to be signaled
    102  // (real-time; ignores time overrides).  Returns true if the event was
    103  // signaled. Handles spurious wakeups and guarantees that |wait_delta| will
    104  // have elapsed if this returns false.
    105  //
    106  // TimedWait can synchronise its own destruction like |Wait|.
    107  NOT_TAIL_CALLED bool TimedWait(TimeDelta wait_delta);
    108 
    109 #if BUILDFLAG(IS_WIN)
    110  HANDLE handle() const { return handle_.get(); }
    111 #endif
    112 
    113  // Declares that this WaitableEvent will only ever be used by a thread that is
    114  // idle at the bottom of its stack and waiting for work (in particular, it is
    115  // not synchronously waiting on this event before resuming ongoing work). This
    116  // is useful to avoid telling base-internals that this thread is "blocked"
    117  // when it's merely idle and ready to do work. As such, this is only expected
    118  // to be used by thread and thread pool impls. In such cases wakeup.flow
    119  // events aren't emitted on |Signal|/|Wait|, because threading implementations
    120  // are responsible for emitting the cause of their wakeup from idle.
    121  void declare_only_used_while_idle() { only_used_while_idle_ = true; }
    122 
    123  // Wait, synchronously, on multiple events.
    124  //   waitables: an array of WaitableEvent pointers
    125  //   count: the number of elements in @waitables
    126  //
    127  // returns: the index of a WaitableEvent which has been signaled.
    128  //
    129  // You MUST NOT delete any of the WaitableEvent objects while this wait is
    130  // happening, however WaitMany's return "happens after" the |Signal| call
    131  // that caused it has completed, like |Wait|.
    132  //
    133  // If more than one WaitableEvent is signaled to unblock WaitMany, the lowest
    134  // index among them is returned.
    135  NOT_TAIL_CALLED static size_t WaitMany(WaitableEvent** waitables,
    136                                         size_t count);
    137 
    138  // For asynchronous waiting, see WaitableEventWatcher
    139 
    140  // This is a private helper class. It's here because it's used by friends of
    141  // this class (such as WaitableEventWatcher) to be able to enqueue elements
    142  // of the wait-list
    143  class Waiter {
    144   public:
    145    // Signal the waiter to wake up.
    146    //
    147    // Consider the case of a Waiter which is in multiple WaitableEvent's
    148    // wait-lists. Each WaitableEvent is automatic-reset and two of them are
    149    // signaled at the same time. Now, each will wake only the first waiter in
    150    // the wake-list before resetting. However, if those two waiters happen to
    151    // be the same object (as can happen if another thread didn't have a chance
    152    // to dequeue the waiter from the other wait-list in time), two auto-resets
    153    // will have happened, but only one waiter has been signaled!
    154    //
    155    // Because of this, a Waiter may "reject" a wake by returning false. In
    156    // this case, the auto-reset WaitableEvent shouldn't act as if anything has
    157    // been notified.
    158    virtual bool Fire(WaitableEvent* signaling_event) = 0;
    159 
    160    // Waiters may implement this in order to provide an extra condition for
    161    // two Waiters to be considered equal. In WaitableEvent::Dequeue, if the
    162    // pointers match then this function is called as a final check. See the
    163    // comments in ~Handle for why.
    164    virtual bool Compare(void* tag) = 0;
    165 
    166   protected:
    167    virtual ~Waiter() = default;
    168  };
    169 
    170 private:
    171  friend class WaitableEventWatcher;
    172 
    173  // The platform specific portions of Signal and TimedWait (which do the actual
    174  // signaling and waiting).
    175  void SignalImpl();
    176  bool TimedWaitImpl(TimeDelta wait_delta);
    177 
    178 #if BUILDFLAG(IS_WIN)
    179  win::ScopedHandle handle_;
    180 #elif BUILDFLAG(IS_APPLE)
    181  // Peeks the message queue named by |port| and returns true if a message
    182  // is present and false if not. If |dequeue| is true, the messsage will be
    183  // drained from the queue. If |dequeue| is false, the queue will only be
    184  // peeked. |port| must be a receive right.
    185  static bool PeekPort(mach_port_t port, bool dequeue);
    186 
    187  // The Mach receive right is waited on by both WaitableEvent and
    188  // WaitableEventWatcher. It is valid to signal and then delete an event, and
    189  // a watcher should still be notified. If the right were to be destroyed
    190  // immediately, the watcher would not receive the signal. Because Mach
    191  // receive rights cannot have a user refcount greater than one, the right
    192  // must be reference-counted manually.
    193  class ReceiveRight : public RefCountedThreadSafe<ReceiveRight> {
    194   public:
    195    explicit ReceiveRight(mach_port_t name);
    196 
    197    ReceiveRight(const ReceiveRight&) = delete;
    198    ReceiveRight& operator=(const ReceiveRight&) = delete;
    199 
    200    mach_port_t Name() const { return right_.get(); }
    201 
    202   private:
    203    friend class RefCountedThreadSafe<ReceiveRight>;
    204    ~ReceiveRight();
    205 
    206    apple::ScopedMachReceiveRight right_;
    207  };
    208 
    209  const ResetPolicy policy_;
    210 
    211  // The receive right for the event.
    212  scoped_refptr<ReceiveRight> receive_right_;
    213 
    214  // The send right used to signal the event. This can be disposed of with
    215  // the event, unlike the receive right, since a deleted event cannot be
    216  // signaled.
    217  apple::ScopedMachSendRight send_right_;
    218 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
    219  // On Windows, you must not close a HANDLE which is currently being waited on.
    220  // The MSDN documentation says that the resulting behaviour is 'undefined'.
    221  // To solve that issue each WaitableEventWatcher duplicates the given event
    222  // handle.
    223 
    224  // However, if we were to include the following members
    225  // directly then, on POSIX, one couldn't use WaitableEventWatcher to watch an
    226  // event which gets deleted. This mismatch has bitten us several times now,
    227  // so we have a kernel of the WaitableEvent, which is reference counted.
    228  // WaitableEventWatchers may then take a reference and thus match the Windows
    229  // behaviour.
    230  struct WaitableEventKernel :
    231      public RefCountedThreadSafe<WaitableEventKernel> {
    232   public:
    233    WaitableEventKernel(ResetPolicy reset_policy, InitialState initial_state);
    234 
    235    bool Dequeue(Waiter* waiter, void* tag);
    236 
    237    base::Lock lock_;
    238    const bool manual_reset_;
    239    bool signaled_;
    240    std::list<Waiter*> waiters_;
    241 
    242   private:
    243    friend class RefCountedThreadSafe<WaitableEventKernel>;
    244    ~WaitableEventKernel();
    245  };
    246 
    247  typedef std::pair<WaitableEvent*, size_t> WaiterAndIndex;
    248 
    249  // When dealing with arrays of WaitableEvent*, we want to sort by the address
    250  // of the WaitableEvent in order to have a globally consistent locking order.
    251  // In that case we keep them, in sorted order, in an array of pairs where the
    252  // second element is the index of the WaitableEvent in the original,
    253  // unsorted, array.
    254  static size_t EnqueueMany(WaiterAndIndex* waitables,
    255                            size_t count, Waiter* waiter);
    256 
    257  bool SignalAll();
    258  bool SignalOne();
    259  void Enqueue(Waiter* waiter);
    260 
    261  scoped_refptr<WaitableEventKernel> kernel_;
    262 #endif
    263 
    264  // Whether a thread invoking Wait() on this WaitableEvent should be considered
    265  // blocked as opposed to idle (and potentially replaced if part of a pool),
    266  // and whether WaitableEvent should emit a wakeup.flow event on Signal =>
    267  // TimedWait.
    268  bool only_used_while_idle_ = false;
    269 };
    270 
    271 }  // namespace base
    272 
    273 #endif  // BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_