1 // Copyright 2024 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 <cstddef> 17 18 #include "pw_allocator/allocator.h" 19 #include "pw_sync/borrow.h" 20 21 namespace pw::allocator { 22 23 /// Wraps an `Allocator` with a lock to synchronize access. 24 /// 25 /// Depending on the `LockType`, this object may be thread- and/or interrupt- 26 /// safe. For example, `SynchronizedAllocator<pw::sync::Mutex>` is thread-safe, 27 /// while `SynchronizedAllocator<pw::sync::InterruptSpinLock>` is thread- and 28 /// interrupt-safe. 29 /// 30 /// @tparam LockType The type of the lock used to synchronize allocator access. 31 /// Must be default-constructible. 32 template <typename LockType> 33 class SynchronizedAllocator : public Allocator { 34 public: SynchronizedAllocator(Allocator & allocator)35 constexpr SynchronizedAllocator(Allocator& allocator) noexcept 36 : Allocator(allocator.capabilities()), borrowable_(allocator, lock_) {} 37 38 private: 39 using Pointer = sync::BorrowedPointer<Allocator, LockType>; 40 41 /// @copydoc Allocator::Allocate DoAllocate(Layout layout)42 void* DoAllocate(Layout layout) override { 43 Pointer allocator = borrowable_.acquire(); 44 return allocator->Allocate(layout); 45 } 46 47 /// @copydoc Allocator::Deallocate DoDeallocate(void * ptr)48 void DoDeallocate(void* ptr) override { 49 Pointer allocator = borrowable_.acquire(); 50 return allocator->Deallocate(ptr); 51 } 52 53 /// @copydoc Allocator::Deallocate DoDeallocate(void * ptr,Layout)54 void DoDeallocate(void* ptr, Layout) override { DoDeallocate(ptr); } 55 56 /// @copydoc Allocator::Resize DoResize(void * ptr,size_t new_size)57 bool DoResize(void* ptr, size_t new_size) override { 58 Pointer allocator = borrowable_.acquire(); 59 return allocator->Resize(ptr, new_size); 60 } 61 DoReallocate(void * ptr,Layout new_layout)62 void* DoReallocate(void* ptr, Layout new_layout) override { 63 Pointer allocator = borrowable_.acquire(); 64 return allocator->Reallocate(ptr, new_layout); 65 } 66 67 /// @copydoc Allocator::GetAllocated DoGetAllocated()68 size_t DoGetAllocated() const override { 69 Pointer allocator = borrowable_.acquire(); 70 return allocator->GetAllocated(); 71 } 72 73 /// @copydoc Deallocator::GetInfo DoGetInfo(InfoType info_type,const void * ptr)74 Result<Layout> DoGetInfo(InfoType info_type, const void* ptr) const override { 75 Pointer allocator = borrowable_.acquire(); 76 return GetInfo(*allocator, info_type, ptr); 77 } 78 79 LockType lock_; 80 sync::Borrowable<Allocator, LockType> borrowable_; 81 }; 82 83 /// Tag type used to indicate synchronization is NOT desired. 84 /// 85 /// This can be useful with allocator parameters for module configuration, e.g. 86 /// PW_MALLOC_LOCK_TYPE. 87 struct NoSync {}; 88 89 } // namespace pw::allocator 90