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 | |
24 | namespace absl { |
25 | |
26 | void 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 | |
41 | Notification::~Notification() { |
42 | // Make sure that the thread running Notify() exits before the object is |
43 | // destructed. |
44 | MutexLock l(&this->mutex_); |
45 | } |
46 | |
47 | static inline bool HasBeenNotifiedInternal( |
48 | const std::atomic<bool> *notified_yet) { |
49 | return notified_yet->load(std::memory_order_acquire); |
50 | } |
51 | |
52 | bool Notification::HasBeenNotified() const { |
53 | return HasBeenNotifiedInternal(&this->notified_yet_); |
54 | } |
55 | |
56 | void 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 | |
64 | bool 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 | |
75 | bool 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 | |