1 // Copyright 2020 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 <algorithm> 17 18 #include "pw_assert/assert.h" 19 #include "pw_chrono/system_clock.h" 20 #include "pw_interrupt/context.h" 21 #include "pw_sync/counting_semaphore.h" 22 #include "tx_api.h" 23 24 namespace pw::sync { 25 namespace backend { 26 27 inline constexpr char kCountingSemaphoreName[] = "pw::CountingSemaphore"; 28 29 } // namespace backend 30 CountingSemaphore()31inline CountingSemaphore::CountingSemaphore() : native_type_() { 32 PW_ASSERT( 33 tx_semaphore_create(&native_type_, 34 const_cast<char*>(backend::kCountingSemaphoreName), 35 0) == TX_SUCCESS); 36 } 37 ~CountingSemaphore()38inline CountingSemaphore::~CountingSemaphore() { 39 PW_ASSERT(tx_semaphore_delete(&native_type_) == TX_SUCCESS); 40 } 41 release(ptrdiff_t update)42inline void CountingSemaphore::release(ptrdiff_t update) { 43 for (; update > 0; --update) { 44 PW_ASSERT(tx_semaphore_put(&native_type_) == TX_SUCCESS); 45 } 46 } 47 acquire()48inline void CountingSemaphore::acquire() { 49 // Enforce the pw::sync::CountingSemaphore IRQ contract. 50 PW_DASSERT(!interrupt::InInterruptContext()); 51 PW_ASSERT(tx_semaphore_get(&native_type_, TX_WAIT_FOREVER) == TX_SUCCESS); 52 } 53 try_acquire()54inline bool CountingSemaphore::try_acquire() noexcept { 55 const UINT result = tx_semaphore_get(&native_type_, TX_NO_WAIT); 56 if (result == TX_NO_INSTANCE) { 57 return false; 58 } 59 PW_ASSERT(result == TX_SUCCESS); 60 return true; 61 } 62 try_acquire_until(chrono::SystemClock::time_point deadline)63inline bool CountingSemaphore::try_acquire_until( 64 chrono::SystemClock::time_point deadline) { 65 // Note that if this deadline is in the future, it will get rounded up by 66 // one whole tick due to how try_acquire_for is implemented. 67 return try_acquire_for(deadline - chrono::SystemClock::now()); 68 } 69 70 inline CountingSemaphore::native_handle_type native_handle()71CountingSemaphore::native_handle() { 72 return native_type_; 73 } 74 75 } // namespace pw::sync 76