blob: b5eb90413a65064850eaff23f9edc756124a1727 [file] [log] [blame]
/* Copyright (c) 2013 The Regents of the University of California
* Copyright (c) 2018 Google Inc.
* 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>
#include <parlib/uthread.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 awaiters_tailq waiters;
struct alarm_waiter *running;
uint64_t earliest_time;
uint64_t latest_time;
struct uth_cond_var cv;
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);
bool unset_alarm(struct alarm_waiter *waiter);
bool 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