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#include "absl/synchronization/notification.h"
16
17#include <atomic>
18
19#include "absl/base/attributes.h"
20#include "absl/base/internal/raw_logging.h"
21#include "absl/synchronization/mutex.h"
22#include "absl/time/time.h"
23
24namespace absl {
25
26void Notification::Notify() {
27 MutexLock l(&this->mutex_);
28
29#ifndef NDEBUG
30 if (ABSL_PREDICT_FALSE(notified_yet_.load(std::memory_order_relaxed))) {
31 ABSL_RAW_LOG(
32 FATAL,
33 "Notify() method called more than once for Notification object %p",
34 static_cast<void *>(this));
35 }
36#endif
37
38 notified_yet_.store(true, std::memory_order_release);
39}
40
41Notification::~Notification() {
42 // Make sure that the thread running Notify() exits before the object is
43 // destructed.
44 MutexLock l(&this->mutex_);
45}
46
47static inline bool HasBeenNotifiedInternal(
48 const std::atomic<bool> *notified_yet) {
49 return notified_yet->load(std::memory_order_acquire);
50}
51
52bool Notification::HasBeenNotified() const {
53 return HasBeenNotifiedInternal(&this->notified_yet_);
54}
55
56void Notification::WaitForNotification() const {
57 if (!HasBeenNotifiedInternal(&this->notified_yet_)) {
58 this->mutex_.LockWhen(Condition(&HasBeenNotifiedInternal,
59 &this->notified_yet_));
60 this->mutex_.Unlock();
61 }
62}
63
64bool Notification::WaitForNotificationWithTimeout(
65 absl::Duration timeout) const {
66 bool notified = HasBeenNotifiedInternal(&this->notified_yet_);
67 if (!notified) {
68 notified = this->mutex_.LockWhenWithTimeout(
69 Condition(&HasBeenNotifiedInternal, &this->notified_yet_), timeout);
70 this->mutex_.Unlock();
71 }
72 return notified;
73}
74
75bool Notification::WaitForNotificationWithDeadline(absl::Time deadline) const {
76 bool notified = HasBeenNotifiedInternal(&this->notified_yet_);
77 if (!notified) {
78 notified = this->mutex_.LockWhenWithDeadline(
79 Condition(&HasBeenNotifiedInternal, &this->notified_yet_), deadline);
80 this->mutex_.Unlock();
81 }
82 return notified;
83}
84
85} // namespace absl
86