| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #pragma once |
| |
| #include <fbl/ref_ptr.h> |
| #include <zircon/compiler.h> |
| #include <zircon/errors.h> |
| #include <zircon/time.h> |
| #include <zircon/types.h> |
| |
| #include <dispatcher-pool/dispatcher-event-source.h> |
| |
| namespace dispatcher { |
| |
| // class Timer |
| // |
| // Timer is one of the EventSources in the dispatcher framework used to manage |
| // a zircon timer object. |
| // |
| // :: Handler :: |
| // |
| // Timer defines a single handler (ProcessHandler) which runs when the timer |
| // fires. Returning an error from the process handler will cause the timer to |
| // automatically become deactivated. |
| // |
| // :: Activation :: |
| // |
| // Activation simply requires a user to provide a valid ExecutionDomain and a |
| // valid ProcessHandler. The timer kernel object itself will be allocated |
| // internally. |
| // |
| // :: Arming/Canceling :: |
| // |
| // Arming the timer to fire at a specific point in time and canceling the timer |
| // are operations protected by an internal lock, they may be called from any |
| // thread. Attempting to Arm a deactivated timer will result in an error. The |
| // time at which a timer fires is always an absolute time given on the |
| // ZX_CLOCK_MONOTONIC timeline. |
| // |
| // After firing, a timer is always disarmed. It may be armed, canceled and |
| // re-armed again any number of times from the dispatch operation within the |
| // context of the ExecutionDomain the timer was bound to. |
| // |
| class Timer : public EventSource { |
| public: |
| static constexpr size_t MAX_HANDLER_CAPTURE_SIZE = sizeof(void*) * 2; |
| using ProcessHandler = |
| fbl::InlineFunction<zx_status_t(Timer*), MAX_HANDLER_CAPTURE_SIZE>; |
| |
| static fbl::RefPtr<Timer> Create(zx_duration_t early_slop_nsec = 0); |
| |
| // Activate a timer object, creating the kernel timer and binding the Timer |
| // object to an execution domain and a processing handler. |
| // |
| // The operation will fail if the Timer has already been bound, or either |
| // the domain reference or processing handler is invalid. |
| // |
| // |slack_type| specifies the type of slack that may be applied to the |
| // deadline. |
| // |
| // TODO(ZX-3311): Remove the default for slack_type and pass the correct |
| // value based on the needs of the callers. |
| zx_status_t Activate(fbl::RefPtr<ExecutionDomain> domain, |
| ProcessHandler process_handler, |
| uint32_t slack_type = ZX_TIMER_SLACK_LATE); |
| virtual void Deactivate() __TA_EXCLUDES(obj_lock_) override; |
| |
| // Arm a timer object to fire at the |deadline| adjusted by the |
| // |slack_amount| and the |slack_type| used to Activate. |
| // |
| // TODO(ZX-3311): Remove the default for slack_amount and pass the correct |
| // value based on the needs of the callers. |
| zx_status_t Arm(zx_time_t deadline, zx_duration_t slack_amount = 0); |
| void Cancel(); |
| |
| protected: |
| void Dispatch(ExecutionDomain* domain) __TA_EXCLUDES(obj_lock_) override; |
| |
| private: |
| friend class fbl::RefPtr<Timer>; |
| |
| Timer(zx_duration_t early_slop_nsec) |
| : EventSource(ZX_TIMER_SIGNALED), |
| early_slop_nsec_(early_slop_nsec) { } |
| |
| void DisarmLocked() __TA_REQUIRES(obj_lock_); |
| zx_status_t SetTimerAndWaitLocked() __TA_REQUIRES(obj_lock_); |
| |
| const zx_duration_t early_slop_nsec_; |
| bool armed_ __TA_GUARDED(obj_lock_) = false; |
| bool timer_set_ __TA_GUARDED(obj_lock_) = false; |
| zx_time_t deadline_ __TA_GUARDED(obj_lock_) = 0; |
| zx_duration_t slack_amount_ __TA_GUARDED(obj_lock_) = 0; |
| |
| ProcessHandler process_handler_; |
| }; |
| |
| } // namespace dispatcher |