1 // Copyright 2023 gRPC 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 // http://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 #ifndef GRPC_SRC_CORE_LIB_PROMISE_PROMISE_MUTEX_H 16 #define GRPC_SRC_CORE_LIB_PROMISE_PROMISE_MUTEX_H 17 18 #include <grpc/support/port_platform.h> 19 20 #include <utility> 21 22 #include "absl/log/check.h" 23 #include "src/core/lib/promise/activity.h" 24 #include "src/core/lib/promise/poll.h" 25 26 namespace grpc_core { 27 28 // A mutex that can be used to synchronize access to a value within one 29 // activity. 30 template <typename T> 31 class PromiseMutex { 32 public: 33 class Lock { 34 public: Lock()35 Lock() {} ~Lock()36 ~Lock() { 37 if (mutex_ != nullptr) { 38 CHECK(mutex_->locked_); 39 mutex_->locked_ = false; 40 mutex_->waiter_.Wake(); 41 } 42 } 43 Lock(Lock && other)44 Lock(Lock&& other) noexcept 45 : mutex_(std::exchange(other.mutex_, nullptr)) {} 46 Lock& operator=(Lock&& other) noexcept { 47 std::swap(mutex_, other.mutex_); 48 return *this; 49 } 50 51 Lock(const Lock&) = delete; 52 Lock& operator=(const Lock&) noexcept = delete; 53 54 T* operator->() { 55 DCHECK_NE(mutex_, nullptr); 56 return &mutex_->value_; 57 } 58 T& operator*() { 59 DCHECK_NE(mutex_, nullptr); 60 return mutex_->value_; 61 } 62 63 private: 64 friend class PromiseMutex; Lock(PromiseMutex * mutex)65 explicit Lock(PromiseMutex* mutex) : mutex_(mutex) { 66 DCHECK(!mutex_->locked_); 67 mutex_->locked_ = true; 68 } 69 PromiseMutex* mutex_ = nullptr; 70 }; 71 72 PromiseMutex() = default; PromiseMutex(T value)73 explicit PromiseMutex(T value) : value_(std::move(value)) {} ~PromiseMutex()74 ~PromiseMutex() { DCHECK(!locked_); } 75 Acquire()76 auto Acquire() { 77 return [this]() -> Poll<Lock> { 78 if (locked_) return waiter_.pending(); 79 return Lock(this); 80 }; 81 } 82 83 private: 84 bool locked_ = false; 85 IntraActivityWaiter waiter_; 86 GPR_NO_UNIQUE_ADDRESS T value_; 87 }; 88 89 } // namespace grpc_core 90 91 #endif // GRPC_SRC_CORE_LIB_PROMISE_PROMISE_MUTEX_H 92