1 // Copyright 2021 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // 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, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include "pw_polyfill/language_feature_macros.h" 17 #include "pw_sync/lock_annotations.h" 18 19 namespace pw::sync { 20 21 /// The `VirtualBasicLockable` is a virtual lock abstraction for locks which 22 /// meet the C++ named BasicLockable requirements of lock() and unlock(). 23 /// 24 /// This virtual indirection is useful in case you need configurable lock 25 /// selection in a portable module where the final type is not defined upstream 26 /// and ergo module configuration cannot be used or in case the lock type is not 27 /// fixed at compile time, for example to support run time and crash time use of 28 /// an object without incurring the code size hit for templating the object. 29 class PW_LOCKABLE("pw::sync::VirtualBasicLockable") VirtualBasicLockable { 30 public: lock()31 void lock() PW_EXCLUSIVE_LOCK_FUNCTION() { 32 DoLockOperation(Operation::kLock); 33 } 34 unlock()35 void unlock() PW_UNLOCK_FUNCTION() { DoLockOperation(Operation::kUnlock); } 36 37 protected: 38 ~VirtualBasicLockable() = default; 39 40 enum class Operation { 41 kLock, 42 kUnlock, 43 }; 44 45 private: 46 /// Uses a single virtual method with an enum to minimize the vtable cost per 47 /// implementation of `VirtualBasicLockable`. 48 virtual void DoLockOperation(Operation operation) = 0; 49 }; 50 51 /// The `NoOpLock` is a type of `VirtualBasicLockable` that does nothing, i.e. 52 /// lock operations are no-ops. 53 class PW_LOCKABLE("pw::sync::NoOpLock") NoOpLock final 54 : public VirtualBasicLockable { 55 public: NoOpLock()56 constexpr NoOpLock() {} 57 NoOpLock(const NoOpLock&) = delete; 58 NoOpLock(NoOpLock&&) = delete; 59 NoOpLock& operator=(const NoOpLock&) = delete; 60 NoOpLock& operator=(NoOpLock&&) = delete; 61 62 /// Gives access to a global NoOpLock instance. It is not necessary to have 63 /// multiple NoOpLock instances since they have no state and do nothing. Instance()64 static NoOpLock& Instance() { 65 PW_CONSTINIT static NoOpLock lock; 66 return lock; 67 } 68 69 private: DoLockOperation(Operation)70 void DoLockOperation(Operation) override {} 71 }; 72 73 } // namespace pw::sync 74