|  | /* Copyright (c) 2013 The Regents of the University of California | 
|  | * Barret Rhoden <brho@cs.berkeley.edu> | 
|  | * See LICENSE for details. | 
|  | * | 
|  | * Userspace alarms.  There are lower level helpers to build your own alarms | 
|  | * from the #A device and an alarm service, based off a slimmed down version of | 
|  | * the kernel alarms.  Under the hood, the user alarm uses the #A service for | 
|  | * the root of the alarm chain. | 
|  | * | 
|  | * There's only one timer chain, unlike in the kernel, for the entire process. | 
|  | * If you want one-off timers unrelated to the chain (and sent to other vcores), | 
|  | * use #A directly. | 
|  | * | 
|  | * Your handlers will run from vcore context. | 
|  | * | 
|  | * 1) To set a handler to run on an alarm: | 
|  | * 	struct alarm_waiter *waiter = malloc(sizeof(struct alarm_waiter)); | 
|  | * 	init_awaiter(waiter, HANDLER); | 
|  | * 	waiter->data = something; | 
|  | * 	set_awaiter_rel(waiter, USEC); | 
|  | * 	set_alarm(waiter); | 
|  | * If you want the HANDLER to run again, do this at the end of it: | 
|  | * 	set_awaiter_rel(waiter, USEC); | 
|  | * 	__set_alarm(waiter); | 
|  | * Do not call set_alarm() from within an alarm handler; you'll deadlock. | 
|  | * Don't forget to manage your memory at some (safe) point: | 
|  | * 	free(waiter); */ | 
|  |  | 
|  | #pragma once | 
|  |  | 
|  | #include <parlib/common.h> | 
|  | #include <sys/queue.h> | 
|  | #include <parlib/spinlock.h> | 
|  | #include <parlib/event.h> | 
|  |  | 
|  | __BEGIN_DECLS | 
|  |  | 
|  | /* Low-level alarm interface */ | 
|  |  | 
|  | int devalarm_get_fds(int *ctlfd_r, int *timerfd_r, int *alarmid_r); | 
|  | int devalarm_set_evq(int timerfd, struct event_queue *ev_q, int alarmid); | 
|  | int devalarm_set_time(int timerfd, uint64_t tsc_time); | 
|  | int devalarm_get_id(struct event_msg *ev_msg); | 
|  | int devalarm_disable(int timerfd); | 
|  |  | 
|  | /* Alarm service */ | 
|  |  | 
|  | /* Specifc waiter, per alarm */ | 
|  | struct alarm_waiter { | 
|  | uint64_t 					wake_up_time;	/* tsc time */ | 
|  | void (*func) (struct alarm_waiter *waiter); | 
|  | void						*data; | 
|  | TAILQ_ENTRY(alarm_waiter)	next; | 
|  | bool						on_tchain; | 
|  | }; | 
|  | TAILQ_HEAD(awaiters_tailq, alarm_waiter);		/* ideally not a LL */ | 
|  |  | 
|  | typedef void (*alarm_handler)(struct alarm_waiter *waiter); | 
|  |  | 
|  | /* Sorted collection of alarms. */ | 
|  | struct timer_chain { | 
|  | struct spin_pdr_lock		lock; | 
|  | struct awaiters_tailq		waiters; | 
|  | uint64_t					earliest_time; | 
|  | uint64_t					latest_time; | 
|  | int							ctlfd; | 
|  | int							timerfd; | 
|  | int							alarmid; | 
|  | struct event_queue			*ev_q; | 
|  | }; | 
|  |  | 
|  | /* For fresh alarm waiters.  func == 0 for kthreads */ | 
|  | void init_awaiter(struct alarm_waiter *waiter, | 
|  | void (*func) (struct alarm_waiter *)); | 
|  | /* Sets the time an awaiter goes off */ | 
|  | void set_awaiter_abs_unix(struct alarm_waiter *waiter, uint64_t abs_usec); | 
|  | void set_awaiter_rel(struct alarm_waiter *waiter, uint64_t usleep); | 
|  | void set_awaiter_inc(struct alarm_waiter *waiter, uint64_t usleep); | 
|  |  | 
|  | /* Helper: converts a timespec to the units of the #alarm service (usec).  A | 
|  | * common usage: | 
|  | * 		set_awaiter_abs_unix(w, timespec_to_alarm_time(abs_ts)); | 
|  | */ | 
|  | static uint64_t timespec_to_alarm_time(const struct timespec *ts) | 
|  | { | 
|  | return ts->tv_nsec / 1000 + ts->tv_sec * 1000000ULL; | 
|  | } | 
|  |  | 
|  | /* Arms/disarms the alarm */ | 
|  | void __set_alarm(struct alarm_waiter *waiter); | 
|  | void set_alarm(struct alarm_waiter *waiter); | 
|  | bool unset_alarm(struct alarm_waiter *waiter); | 
|  | void reset_alarm_abs(struct alarm_waiter *waiter, uint64_t abs_time); | 
|  |  | 
|  | /* "parlib" alarm handlers */ | 
|  | void alarm_abort_sysc(struct alarm_waiter *awaiter); | 
|  |  | 
|  | /* Debugging */ | 
|  | #define ALARM_POISON_TIME 12345 | 
|  | void print_chain(struct timer_chain *tchain); | 
|  |  | 
|  | __END_DECLS |