00001 // Copyright 2017 The Abseil Authors. 00002 // 00003 // Licensed under the Apache License, Version 2.0 (the "License"); 00004 // you may not use this file except in compliance with the License. 00005 // You may obtain a copy of the License at 00006 // 00007 // https://www.apache.org/licenses/LICENSE-2.0 00008 // 00009 // Unless required by applicable law or agreed to in writing, software 00010 // distributed under the License is distributed on an "AS IS" BASIS, 00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 // See the License for the specific language governing permissions and 00013 // limitations under the License. 00014 00015 #include "absl/synchronization/notification.h" 00016 00017 #include <atomic> 00018 00019 #include "absl/base/attributes.h" 00020 #include "absl/base/internal/raw_logging.h" 00021 #include "absl/synchronization/mutex.h" 00022 #include "absl/time/time.h" 00023 00024 namespace absl { 00025 00026 void Notification::Notify() { 00027 MutexLock l(&this->mutex_); 00028 00029 #ifndef NDEBUG 00030 if (ABSL_PREDICT_FALSE(notified_yet_.load(std::memory_order_relaxed))) { 00031 ABSL_RAW_LOG( 00032 FATAL, 00033 "Notify() method called more than once for Notification object %p", 00034 static_cast<void *>(this)); 00035 } 00036 #endif 00037 00038 notified_yet_.store(true, std::memory_order_release); 00039 } 00040 00041 Notification::~Notification() { 00042 // Make sure that the thread running Notify() exits before the object is 00043 // destructed. 00044 MutexLock l(&this->mutex_); 00045 } 00046 00047 static inline bool HasBeenNotifiedInternal( 00048 const std::atomic<bool> *notified_yet) { 00049 return notified_yet->load(std::memory_order_acquire); 00050 } 00051 00052 bool Notification::HasBeenNotified() const { 00053 return HasBeenNotifiedInternal(&this->notified_yet_); 00054 } 00055 00056 void Notification::WaitForNotification() const { 00057 if (!HasBeenNotifiedInternal(&this->notified_yet_)) { 00058 this->mutex_.LockWhen(Condition(&HasBeenNotifiedInternal, 00059 &this->notified_yet_)); 00060 this->mutex_.Unlock(); 00061 } 00062 } 00063 00064 bool Notification::WaitForNotificationWithTimeout( 00065 absl::Duration timeout) const { 00066 bool notified = HasBeenNotifiedInternal(&this->notified_yet_); 00067 if (!notified) { 00068 notified = this->mutex_.LockWhenWithTimeout( 00069 Condition(&HasBeenNotifiedInternal, &this->notified_yet_), timeout); 00070 this->mutex_.Unlock(); 00071 } 00072 return notified; 00073 } 00074 00075 bool Notification::WaitForNotificationWithDeadline(absl::Time deadline) const { 00076 bool notified = HasBeenNotifiedInternal(&this->notified_yet_); 00077 if (!notified) { 00078 notified = this->mutex_.LockWhenWithDeadline( 00079 Condition(&HasBeenNotifiedInternal, &this->notified_yet_), deadline); 00080 this->mutex_.Unlock(); 00081 } 00082 return notified; 00083 } 00084 00085 } // namespace absl