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 <condition_variable> 17 #include <memory> 18 #include <mutex> 19 20 #include "pw_chrono/system_clock.h" 21 #include "pw_function/function.h" 22 23 namespace pw::chrono::backend { 24 namespace internal { 25 26 using ExpiryFn = Function<void(SystemClock::time_point expired_deadline)>; 27 28 class NoDepsTimedThreadNotification { 29 public: 30 NoDepsTimedThreadNotification() = default; 31 bool try_acquire(); 32 bool try_acquire_until(SystemClock::time_point deadline); 33 void notify(); 34 35 private: 36 std::mutex lock_; 37 std::condition_variable cv_; 38 // Guarded by lock_. 39 bool is_set_ = false; 40 }; 41 42 class TimerState { 43 public: TimerState(ExpiryFn && cb)44 TimerState(ExpiryFn&& cb) : callback_(std::move(cb)) {} 45 46 NoDepsTimedThreadNotification timer_thread_wakeup_; 47 48 // The mutex is used both to ensure the public API is threadsafe and to 49 // ensure that only one expiry callback is executed at time. 50 // A recursive mutex is used as the timer callback must be able to invoke 51 // its own public API. 52 std::recursive_mutex lock_; 53 54 // All guarded by `lock_`; 55 const ExpiryFn callback_; 56 SystemClock::time_point expiry_deadline_; 57 bool enabled_ = false; 58 bool running_ = true; 59 }; 60 61 } // namespace internal 62 63 class NativeSystemTimer { 64 public: 65 NativeSystemTimer(internal::ExpiryFn&& callback); 66 void InvokeAt(SystemClock::time_point timestamp); 67 void Cancel(); 68 void Kill(); 69 70 private: 71 // Instead of using a more complex blocking timer cleanup, a shared_pointer is 72 // used so that the heap allocation is still valid for the detached threads 73 // even after the NativeSystemTimer has been destructed. Note this is shared 74 // with all detached threads. 75 std::shared_ptr<internal::TimerState> timer_state_; 76 }; 77 78 using NativeSystemTimerHandle = NativeSystemTimer&; 79 80 } // namespace pw::chrono::backend 81