| // Copyright 2016 The Fuchsia Authors |
| // Copyright (c) 2008-2009 Travis Geiselbrecht |
| // |
| // Use of this source code is governed by a MIT-style |
| // license that can be found in the LICENSE file or at |
| // https://opensource.org/licenses/MIT |
| |
| #pragma once |
| |
| #include <kernel/spinlock.h> |
| #include <list.h> |
| #include <zircon/compiler.h> |
| #include <sys/types.h> |
| |
| __BEGIN_CDECLS |
| |
| void timer_queue_init(void); |
| |
| struct timer; |
| typedef enum handler_return (*timer_callback)(struct timer*, lk_time_t now, void* arg); |
| |
| #define TIMER_MAGIC (0x74696D72) //'timr' |
| |
| enum slack_mode { |
| TIMER_SLACK_CENTER, // slack is centered arround dealine |
| TIMER_SLACK_LATE, // slack interval is [deadline, dealine + slack) |
| TIMER_SLACK_EARLY, // slack interval is (deadline - slack, dealine] |
| }; |
| |
| typedef struct timer { |
| int magic; |
| struct list_node node; |
| |
| lk_time_t scheduled_time; |
| int64_t slack; // Stores the applied slack adjustment from |
| // the ideal scheduled_time. |
| timer_callback callback; |
| void* arg; |
| |
| volatile int active_cpu; // <0 if inactive |
| volatile bool cancel; // true if cancel is pending |
| } timer_t; |
| |
| #define TIMER_INITIAL_VALUE(t) \ |
| { \ |
| .magic = TIMER_MAGIC, \ |
| .node = LIST_INITIAL_CLEARED_VALUE, \ |
| .scheduled_time = 0, \ |
| .slack = 0, \ |
| .callback = NULL, \ |
| .arg = NULL, \ |
| .active_cpu = -1, \ |
| .cancel = false, \ |
| } |
| |
| /* Rules for Timers: |
| * - Timer callbacks occur from interrupt context |
| * - Timers may be programmed or canceled from interrupt or thread context |
| * - Timers may be canceled or reprogrammed from within their callback |
| * - Setting and canceling timers is not thread safe and cannot be done concurrently |
| * - timer_cancel() may spin waiting for a pending timer to complete on another cpu |
| */ |
| |
| /** |
| * Initialize a timer object |
| */ |
| void timer_init(timer_t*); |
| |
| /** |
| * Set up a timer that executes once |
| * |
| * This function specifies a callback function to be run after a specified |
| * deadline passes. The function will be called one time. |
| * |
| * timer: the timer to use |
| * deadline: absolute time, in ns, after which the timer is executed |
| * mode: type of slack to apply, either symmetrical or one-sided to early or late |
| * slack: delta time in nanoseconds from |deadline| after or before is |
| * acceptable to execute the timer. |
| * callback: the function to call when the timer expires |
| * arg: the argument to pass to the callback |
| * |
| * The timer function is declared as: |
| * enum handler_return callback(struct timer *, lk_time_t now, void *arg) { ... } |
| * |
| * The |slack| parameter defines an interval depending on the |mode| in which |
| * is acceptable to fire the timer: |
| * |
| * - TIMER_SLACK_CENTER: |deadline - slack| to |deadline + slack| |
| * - TIMER_SLACK_LATE: |dealine| to |deadline + slack| |
| * - TIMER_SLACK_EARLY: |deadline - slack| to |deadline| |
| * |
| */ |
| void timer_set(timer_t* timer, lk_time_t deadline, |
| enum slack_mode mode, uint64_t slack, timer_callback callback, void* arg); |
| |
| /** |
| * Cancel a pending timer |
| * |
| * Returns true if the timer was canceled before it was |
| * scheduled in a cpu and false otherwise or if the timer |
| * was not scheduled at all. |
| * |
| */ |
| bool timer_cancel(timer_t*); |
| |
| /* Equivalent to timer_set with a slack of 0 */ |
| static inline void timer_set_oneshot( |
| timer_t* timer, lk_time_t deadline, timer_callback callback, void* arg) { |
| return timer_set(timer, deadline, TIMER_SLACK_CENTER, 0ull, callback, arg); |
| } |
| |
| /* Similar to timer_set_oneshot, with additional constraints: |
| * - Will reset a currently active timer |
| * - Must be called with interrupts disabled |
| * - Must be running on the cpu that the timer is set to fire on (if currently set) |
| * - Cannot be called from the timer itself |
| */ |
| /* NOTE: internal api that is needed probably only by the scheduler */ |
| void timer_reset_oneshot_local(timer_t* timer, lk_time_t deadline, timer_callback callback, void* arg); |
| |
| /* Internal routines used when bringing cpus online/offline */ |
| |
| /* Moves timers from |old_cpu| to the current cpu |
| */ |
| void timer_transition_off_cpu(uint old_cpu); |
| |
| /* This function is to be invoked after resume on each CPU that may have |
| * had timers still on it, in order to restart hardware timers. |
| */ |
| void timer_thaw_percpu(void); |
| |
| /* Special helper routine to simultaneously try to acquire a spinlock and check for |
| * timer cancel, which is needed in a few special cases. |
| * returns ZX_OK if spinlock was acquired, ZX_ERR_TIMED_OUT if timer was canceled. |
| */ |
| status_t timer_trylock_or_cancel(timer_t* t, spin_lock_t* lock); |
| |
| __END_CDECLS |