tor-browser

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

notification.h (5423B)


      1 // Copyright 2017 The Abseil Authors.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 //
     15 // -----------------------------------------------------------------------------
     16 // notification.h
     17 // -----------------------------------------------------------------------------
     18 //
     19 // This header file defines a `Notification` abstraction, which allows threads
     20 // to receive notification of a single occurrence of a single event.
     21 //
     22 // The `Notification` object maintains a private boolean "notified" state that
     23 // transitions to `true` at most once. The `Notification` class provides the
     24 // following primary member functions:
     25 //   * `HasBeenNotified()` to query its state
     26 //   * `WaitForNotification*()` to have threads wait until the "notified" state
     27 //      is `true`.
     28 //   * `Notify()` to set the notification's "notified" state to `true` and
     29 //     notify all waiting threads that the event has occurred.
     30 //     This method may only be called once.
     31 //
     32 // Note that while `Notify()` may only be called once, it is perfectly valid to
     33 // call any of the `WaitForNotification*()` methods multiple times, from
     34 // multiple threads -- even after the notification's "notified" state has been
     35 // set -- in which case those methods will immediately return.
     36 //
     37 // Note that the lifetime of a `Notification` requires careful consideration;
     38 // it might not be safe to destroy a notification after calling `Notify()` since
     39 // it is still legal for other threads to call `WaitForNotification*()` methods
     40 // on the notification. However, observers responding to a "notified" state of
     41 // `true` can safely delete the notification without interfering with the call
     42 // to `Notify()` in the other thread.
     43 //
     44 // Memory ordering: For any threads X and Y, if X calls `Notify()`, then any
     45 // action taken by X before it calls `Notify()` is visible to thread Y after:
     46 //  * Y returns from `WaitForNotification()`, or
     47 //  * Y receives a `true` return value from either `HasBeenNotified()` or
     48 //    `WaitForNotificationWithTimeout()`.
     49 
     50 #ifndef ABSL_SYNCHRONIZATION_NOTIFICATION_H_
     51 #define ABSL_SYNCHRONIZATION_NOTIFICATION_H_
     52 
     53 #include <atomic>
     54 
     55 #include "absl/base/attributes.h"
     56 #include "absl/base/internal/tracing.h"
     57 #include "absl/synchronization/mutex.h"
     58 #include "absl/time/time.h"
     59 
     60 namespace absl {
     61 ABSL_NAMESPACE_BEGIN
     62 
     63 // -----------------------------------------------------------------------------
     64 // Notification
     65 // -----------------------------------------------------------------------------
     66 class Notification {
     67 public:
     68  // Initializes the "notified" state to unnotified.
     69  Notification() : notified_yet_(false) {}
     70  explicit Notification(bool prenotify) : notified_yet_(prenotify) {}
     71  Notification(const Notification&) = delete;
     72  Notification& operator=(const Notification&) = delete;
     73  ~Notification();
     74 
     75  // Notification::HasBeenNotified()
     76  //
     77  // Returns the value of the notification's internal "notified" state.
     78  [[nodiscard]] bool HasBeenNotified() const {
     79    if (HasBeenNotifiedInternal(&this->notified_yet_)) {
     80      base_internal::TraceObserved(this, TraceObjectKind());
     81      return true;
     82    }
     83    return false;
     84  }
     85 
     86  // Notification::WaitForNotification()
     87  //
     88  // Blocks the calling thread until the notification's "notified" state is
     89  // `true`. Note that if `Notify()` has been previously called on this
     90  // notification, this function will immediately return.
     91  void WaitForNotification() const;
     92 
     93  // Notification::WaitForNotificationWithTimeout()
     94  //
     95  // Blocks until either the notification's "notified" state is `true` (which
     96  // may occur immediately) or the timeout has elapsed, returning the value of
     97  // its "notified" state in either case.
     98  bool WaitForNotificationWithTimeout(absl::Duration timeout) const;
     99 
    100  // Notification::WaitForNotificationWithDeadline()
    101  //
    102  // Blocks until either the notification's "notified" state is `true` (which
    103  // may occur immediately) or the deadline has expired, returning the value of
    104  // its "notified" state in either case.
    105  bool WaitForNotificationWithDeadline(absl::Time deadline) const;
    106 
    107  // Notification::Notify()
    108  //
    109  // Sets the "notified" state of this notification to `true` and wakes waiting
    110  // threads. Note: do not call `Notify()` multiple times on the same
    111  // `Notification`; calling `Notify()` more than once on the same notification
    112  // results in undefined behavior.
    113  void Notify();
    114 
    115 private:
    116  // Convenience helper to reduce verbosity at call sites.
    117  static inline constexpr base_internal::ObjectKind TraceObjectKind() {
    118    return base_internal::ObjectKind::kNotification;
    119  }
    120 
    121  static inline bool HasBeenNotifiedInternal(
    122      const std::atomic<bool>* notified_yet) {
    123    return notified_yet->load(std::memory_order_acquire);
    124  }
    125 
    126  mutable Mutex mutex_;
    127  std::atomic<bool> notified_yet_;  // written under mutex_
    128 };
    129 
    130 ABSL_NAMESPACE_END
    131 }  // namespace absl
    132 
    133 #endif  // ABSL_SYNCHRONIZATION_NOTIFICATION_H_