Implement POSIX timers. Current only CLOCK_REALTIME and CLOCK_MONOTONIC

clock are supported. I have plan to merge XSI timer ITIMER_REAL and other
two CPU timers into the new code, current three slots are available for
the XSI timers.
The SIGEV_THREAD notification type is not supported yet because our
sigevent struct lacks of two member fields:
sigev_notify_function
sigev_notify_attributes
I have found the sigevent is used in AIO, so I won't add the two members
unless the AIO code is adjusted.
This commit is contained in:
David Xu 2005-10-23 04:22:56 +00:00
parent 5da49fcb8a
commit 86857b368d
8 changed files with 767 additions and 11 deletions

View File

@ -480,6 +480,9 @@ do_execve(td, args, mac_p)
*/
fdunshare(p, td);
/* Clear POSIX timers */
itimers_event_hook(p, ITIMER_EV_EXEC);
/*
* Malloc things before we need locks.
*/

View File

@ -207,8 +207,6 @@ exit1(struct thread *td, int rv)
PROC_LOCK(p);
stopprofclock(p);
p->p_flag &= ~(P_TRACED | P_PPWAIT);
sigqueue_flush(&p->p_sigqueue);
sigqueue_flush(&td->td_sigqueue);
/*
* Stop the real interval timer. If the handler is currently
@ -221,8 +219,12 @@ exit1(struct thread *td, int rv)
KASSERT(!timevalisset(&p->p_realtimer.it_value),
("realtime timer is still armed"));
}
sigqueue_flush(&p->p_sigqueue);
sigqueue_flush(&td->td_sigqueue);
PROC_UNLOCK(p);
itimers_event_hook(p, ITIMER_EV_EXIT);
/*
* Reset any sigio structures pointing to us as a result of
* F_SETOWN with our pid.

View File

@ -278,6 +278,7 @@ proc_linkup(struct proc *p, struct ksegrp *kg, struct thread *td)
TAILQ_INIT(&p->p_threads); /* all threads in proc */
TAILQ_INIT(&p->p_suspended); /* Threads suspended */
sigqueue_init(&p->p_sigqueue, p);
itimers_init(&p->p_itimers);
p->p_numksegrps = 0;
p->p_numthreads = 0;

View File

@ -47,15 +47,21 @@ __FBSDID("$FreeBSD$");
#include <sys/sysent.h>
#include <sys/proc.h>
#include <sys/time.h>
#include <sys/timers.h>
#include <sys/timetc.h>
#include <sys/vnode.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
#define MAX_CLOCKS (CLOCK_MONOTONIC+1)
int tz_minuteswest;
int tz_dsttime;
static struct kclock posix_clocks[MAX_CLOCKS];
static uma_zone_t itimer_zone = NULL;
/*
* Time of day and interval timer support.
*
@ -70,6 +76,34 @@ static int settime(struct thread *, struct timeval *);
static void timevalfix(struct timeval *);
static void no_lease_updatetime(int);
static void itimer_start(void);
static int itimer_init(void *, int, int);
static void itimer_fini(void *, int);
static void itimer_enter(struct itimer *);
static void itimer_leave(struct itimer *);
static struct itimer *itimer_find(struct proc *, timer_t, int);
static void itimers_alloc(struct proc *);
static int realtimer_create(struct itimer *);
static int realtimer_gettime(struct itimer *, struct itimerspec *);
static int realtimer_settime(struct itimer *, int,
struct itimerspec *, struct itimerspec *);
static int realtimer_delete(struct itimer *);
static void realtimer_clocktime(clockid_t, struct timeval *);
static void realtimer_expire(void *);
static void realtimer_event_hook(struct proc *, clockid_t, int event);
static int kern_timer_create(struct thread *, clockid_t,
struct sigevent *, timer_t *, timer_t);
static int kern_timer_delete(struct thread *, timer_t);
int register_posix_clock(int, struct kclock *);
void itimer_fire(struct itimer *it);
#define CLOCK_CALL(clock, call, arglist) \
((*posix_clocks[clock].call) arglist)
SYSINIT(posix_timer, SI_SUB_P1003_1B, SI_ORDER_FIRST+4, itimer_start, NULL);
static void
no_lease_updatetime(deltat)
int deltat;
@ -659,8 +693,7 @@ int
itimerfix(struct timeval *tv)
{
if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
tv->tv_usec < 0 || tv->tv_usec >= 1000000)
if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000)
return (EINVAL);
if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
tv->tv_usec = tick;
@ -807,3 +840,632 @@ ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps)
return (maxpps < 0 || *curpps < maxpps);
}
}
static void
itimer_start(void)
{
struct kclock rt_clock = {
.timer_create = realtimer_create,
.timer_delete = realtimer_delete,
.timer_settime = realtimer_settime,
.timer_gettime = realtimer_gettime,
.event_hook = realtimer_event_hook
};
itimer_zone = uma_zcreate("itimer", sizeof(struct itimer),
NULL, NULL, itimer_init, itimer_fini, UMA_ALIGN_PTR, 0);
register_posix_clock(CLOCK_REALTIME, &rt_clock);
register_posix_clock(CLOCK_MONOTONIC, &rt_clock);
}
int
register_posix_clock(int clockid, struct kclock *clk)
{
if ((unsigned)clockid >= MAX_CLOCKS) {
printf("%s: invalid clockid\n", __func__);
return (0);
}
posix_clocks[clockid] = *clk;
return (1);
}
static int
itimer_init(void *mem, int size, int flags)
{
struct itimer *it;
it = (struct itimer *)mem;
mtx_init(&it->it_mtx, "itimer lock", NULL, MTX_DEF);
return (0);
}
static void
itimer_fini(void *mem, int size)
{
struct itimer *it;
it = (struct itimer *)mem;
mtx_destroy(&it->it_mtx);
}
static void
itimer_enter(struct itimer *it)
{
mtx_assert(&it->it_mtx, MA_OWNED);
it->it_usecount++;
}
static void
itimer_leave(struct itimer *it)
{
mtx_assert(&it->it_mtx, MA_OWNED);
KASSERT(it->it_usecount > 0, ("invalid it_usecount"));
if (--it->it_usecount == 0 && (it->it_flags & ITF_WANTED) != 0)
wakeup(it);
}
#ifndef _SYS_SYSPROTO_H_
struct timer_create_args {
clockid_t clock_id;
struct sigevent * evp;
timer_t * timerid;
};
#endif
int
timer_create(struct thread *td, struct timer_create_args *uap)
{
struct sigevent *evp1, ev;
timer_t id;
int error;
if (uap->evp != NULL) {
error = copyin(uap->evp, &ev, sizeof(ev));
if (error != 0)
return (error);
evp1 = &ev;
} else
evp1 = NULL;
error = kern_timer_create(td, uap->clock_id, evp1, &id, -1);
if (error == 0) {
error = copyout(&id, uap->timerid, sizeof(timer_t));
if (error != 0)
kern_timer_delete(td, id);
}
return (error);
}
static int
kern_timer_create(struct thread *td, clockid_t clock_id,
struct sigevent *evp, timer_t *timerid, timer_t preset_id)
{
struct proc *p = td->td_proc;
struct itimer *it;
int id;
int error;
if (clock_id < 0 || clock_id >= MAX_CLOCKS)
return (EINVAL);
if (posix_clocks[clock_id].timer_create == NULL)
return (EINVAL);
if (evp != NULL) {
if (evp->sigev_notify != SIGEV_NONE &&
evp->sigev_notify != SIGEV_SIGNAL)
return (EINVAL);
if (evp->sigev_notify == SIGEV_SIGNAL &&
!_SIG_VALID(evp->sigev_signo))
return (EINVAL);
}
if (p->p_itimers.its_timers == NULL)
itimers_alloc(p);
it = uma_zalloc(itimer_zone, M_WAITOK);
it->it_flags = 0;
it->it_usecount = 0;
it->it_active = 0;
timevalclear(&it->it_time.it_value);
timevalclear(&it->it_time.it_interval);
it->it_overrun = 0;
it->it_overrun_last = 0;
it->it_clockid = clock_id;
it->it_timerid = -1;
it->it_proc = p;
ksiginfo_init(&it->it_ksi);
it->it_ksi.ksi_flags |= KSI_INS | KSI_EXT;
error = CLOCK_CALL(clock_id, timer_create, (it));
if (error != 0)
goto out;
PROC_LOCK(p);
if (preset_id != -1) {
KASSERT(preset_id >= 0 && preset_id < 3, ("invalid preset_id"));
id = preset_id;
if (p->p_itimers.its_timers[id] != NULL) {
PROC_UNLOCK(p);
error = 0;
goto out;
}
} else {
/*
* Find a free timer slot, skipping those reserved
* for setitimer().
*/
for (id = 3; id < TIMER_MAX; id++)
if (p->p_itimers.its_timers[id] == NULL)
break;
if (id == TIMER_MAX) {
PROC_UNLOCK(p);
error = EAGAIN;
goto out;
}
}
it->it_timerid = id;
p->p_itimers.its_timers[id] = it;
if (evp != NULL)
it->it_sigev = *evp;
else {
it->it_sigev.sigev_notify = SIGEV_SIGNAL;
switch (clock_id) {
default:
case CLOCK_REALTIME:
it->it_sigev.sigev_signo = SIGALRM;
break;
case CLOCK_VIRTUAL:
it->it_sigev.sigev_signo = SIGVTALRM;
break;
case CLOCK_PROF:
it->it_sigev.sigev_signo = SIGPROF;
break;
}
it->it_sigev.sigev_value.sigval_int = id;
}
if (it->it_sigev.sigev_notify == SIGEV_SIGNAL) {
it->it_ksi.ksi_signo = it->it_sigev.sigev_signo;
it->it_ksi.ksi_code = SI_TIMER;
it->it_ksi.ksi_value = it->it_sigev.sigev_value;
it->it_ksi.ksi_timerid = id;
}
PROC_UNLOCK(p);
*timerid = id;
return (0);
out:
ITIMER_LOCK(it);
CLOCK_CALL(it->it_clockid, timer_delete, (it));
ITIMER_UNLOCK(it);
uma_zfree(itimer_zone, it);
return (error);
}
#ifndef _SYS_SYSPROTO_H_
struct timer_delete_args {
timer_t timerid;
};
#endif
int
timer_delete(struct thread *td, struct timer_delete_args *uap)
{
return (kern_timer_delete(td, uap->timerid));
}
static struct itimer *
itimer_find(struct proc *p, timer_t timerid, int include_deleting)
{
struct itimer *it;
PROC_LOCK_ASSERT(p, MA_OWNED);
if ((p->p_itimers.its_timers == NULL) || (timerid >= TIMER_MAX) ||
(it = p->p_itimers.its_timers[timerid]) == NULL) {
return (NULL);
}
ITIMER_LOCK(it);
if (!include_deleting && (it->it_flags & ITF_DELETING) != 0) {
ITIMER_UNLOCK(it);
it = NULL;
}
return (it);
}
static int
kern_timer_delete(struct thread *td, timer_t timerid)
{
struct proc *p = td->td_proc;
struct itimer *it;
PROC_LOCK(p);
it = itimer_find(p, timerid, 0);
if (it == NULL) {
PROC_UNLOCK(p);
return (EINVAL);
}
PROC_UNLOCK(p);
it->it_flags |= ITF_DELETING;
while (it->it_usecount > 0) {
it->it_flags |= ITF_WANTED;
msleep(it, &it->it_mtx, PPAUSE, "itimer", 0);
}
it->it_flags &= ~ITF_WANTED;
CLOCK_CALL(it->it_clockid, timer_delete, (it));
ITIMER_UNLOCK(it);
PROC_LOCK(p);
if (KSI_ONQ(&it->it_ksi))
sigqueue_take(&it->it_ksi);
p->p_itimers.its_timers[timerid] = NULL;
PROC_UNLOCK(p);
uma_zfree(itimer_zone, it);
return (0);
}
#ifndef _SYS_SYSPROTO_H_
struct timer_settime_args {
timer_t timerid;
int flags;
const struct itimerspec * value;
struct itimerspec * ovalue;
};
#endif
int
timer_settime(struct thread *td, struct timer_settime_args *uap)
{
struct proc *p = td->td_proc;
struct itimer *it;
struct itimerspec val, oval, *ovalp;
int error;
error = copyin(uap->value, &val, sizeof(val));
if (error != 0)
return (error);
if (uap->ovalue != NULL)
ovalp = &oval;
else
ovalp = NULL;
PROC_LOCK(p);
if (uap->timerid < 3 ||
(it = itimer_find(p, uap->timerid, 0)) == NULL) {
PROC_UNLOCK(p);
error = EINVAL;
} else {
PROC_UNLOCK(p);
itimer_enter(it);
error = CLOCK_CALL(it->it_clockid, timer_settime,
(it, uap->flags, &val, ovalp));
itimer_leave(it);
ITIMER_UNLOCK(it);
}
if (error == 0 && uap->ovalue != NULL)
error = copyout(ovalp, uap->ovalue, sizeof(*ovalp));
return (error);
}
#ifndef _SYS_SYSPROTO_H_
struct timer_gettime_args {
timer_t timerid;
struct itimerspec * value;
};
#endif
int
timer_gettime(struct thread *td, struct timer_gettime_args *uap)
{
struct proc *p = td->td_proc;
struct itimer *it;
struct itimerspec val;
int error;
PROC_LOCK(p);
if (uap->timerid < 3 ||
(it = itimer_find(p, uap->timerid, 0)) == NULL) {
PROC_UNLOCK(p);
error = EINVAL;
} else {
PROC_UNLOCK(p);
itimer_enter(it);
error = CLOCK_CALL(it->it_clockid, timer_gettime,
(it, &val));
itimer_leave(it);
ITIMER_UNLOCK(it);
}
if (error == 0)
error = copyout(&val, uap->value, sizeof(val));
return (error);
}
#ifndef _SYS_SYSPROTO_H_
struct timer_getoverrun_args {
timer_t timerid;
};
#endif
int
timer_getoverrun(struct thread *td, struct timer_getoverrun_args *uap)
{
struct proc *p = td->td_proc;
struct itimer *it;
int error ;
PROC_LOCK(p);
if (uap->timerid < 3 ||
(it = itimer_find(p, uap->timerid, 0)) == NULL) {
PROC_UNLOCK(p);
error = EINVAL;
} else {
PROC_UNLOCK(p);
td->td_retval[0] = it->it_overrun_last;
ITIMER_UNLOCK(it);
error = 0;
}
return (error);
}
static int
realtimer_create(struct itimer *it)
{
callout_init_mtx(&it->it_callout, &it->it_mtx, 0);
return (0);
}
static int
realtimer_delete(struct itimer *it)
{
mtx_assert(&it->it_mtx, MA_OWNED);
callout_stop(&it->it_callout);
return (0);
}
static int
realtimer_gettime(struct itimer *it, struct itimerspec *ovalue)
{
struct timespec ts;
mtx_assert(&it->it_mtx, MA_OWNED);
TIMEVAL_TO_TIMESPEC(&it->it_time.it_value, &ovalue->it_value);
TIMEVAL_TO_TIMESPEC(&it->it_time.it_interval, &ovalue->it_interval);
if (it->it_clockid == CLOCK_REALTIME)
getnanotime(&ts);
else /* CLOCK_MONOTONIC */
getnanouptime(&ts);
if (ovalue->it_value.tv_sec != 0 || ovalue->it_value.tv_nsec != 0) {
timespecsub(&ovalue->it_value, &ts);
if (ovalue->it_value.tv_sec < 0 ||
(ovalue->it_value.tv_sec == 0 &&
ovalue->it_value.tv_nsec == 0)) {
ovalue->it_value.tv_sec = 0;
ovalue->it_value.tv_nsec = 1;
}
}
return (0);
}
static int
realtimer_settime(struct itimer *it, int flags,
struct itimerspec *value, struct itimerspec *ovalue)
{
struct timeval tv, tv2;
struct itimerval val;
mtx_assert(&it->it_mtx, MA_OWNED);
TIMESPEC_TO_TIMEVAL(&val.it_value, &value->it_value);
TIMESPEC_TO_TIMEVAL(&val.it_interval, &value->it_interval);
if (itimerfix(&val.it_value))
return (EINVAL);
if (timevalisset(&val.it_value)) {
if (itimerfix(&val.it_interval))
return (EINVAL);
} else {
timevalclear(&val.it_interval);
}
if (ovalue != NULL)
realtimer_gettime(it, ovalue);
it->it_time = val;
if (timevalisset(&val.it_value)) {
realtimer_clocktime(it->it_clockid, &tv);
tv2 = val.it_value;
if ((flags & TIMER_ABSTIME) == 0) {
/* Convert to absolute time. */
timevaladd(&it->it_time.it_value, &tv);
} else {
timevalsub(&tv2, &tv);
/*
* We don't care if tv2 is negative, tztohz will
* fix it.
*/
}
callout_reset(&it->it_callout, tvtohz(&tv2),
realtimer_expire, it);
} else {
callout_stop(&it->it_callout);
}
return (0);
}
static void
realtimer_clocktime(clockid_t id, struct timeval *tv)
{
if (id == CLOCK_REALTIME)
getmicrotime(tv);
else /* CLOCK_MONOTONIC */
getmicrouptime(tv);
}
static void
realtimer_event_hook(struct proc *p, clockid_t clock_id, int event)
{
struct itimers *its;
struct itimer *it;
int i;
/*
* Timer 0 (ITIMER_REAL) is XSI interval timer, according to POSIX
* specification, it should be inherited by new process image.
*/
if (event == ITIMER_EV_EXEC)
i = 1;
else
i = 0;
its = &p->p_itimers;
for (; i < TIMER_MAX; i++) {
if ((it = its->its_timers[i]) != NULL &&
it->it_clockid == clock_id) {
ITIMER_LOCK(it);
callout_stop(&it->it_callout);
ITIMER_UNLOCK(it);
}
}
}
/* Timeout callback for realtime timer */
static void
realtimer_expire(void *arg)
{
struct timeval tv, tv2;
struct itimer *it;
struct proc *p;
it = (struct itimer *)arg;
p = it->it_proc;
realtimer_clocktime(it->it_clockid, &tv);
/* Only fire if time is reached. */
if (timevalcmp(&it->it_time.it_value, &tv, <=)) {
if (timevalisset(&it->it_time.it_interval)) {
timevaladd(&it->it_time.it_value,
&it->it_time.it_interval);
while (timevalcmp(&it->it_time.it_value, &tv, <=)) {
it->it_overrun++;
timevaladd(&it->it_time.it_value,
&it->it_time.it_interval);
}
} else {
/* single shot timer ? */
timevalclear(&it->it_time.it_value);
}
if (timevalisset(&it->it_time.it_value)) {
tv2 = it->it_time.it_value;
timevalsub(&tv2, &tv);
callout_reset(&it->it_callout, tvtohz(&tv2),
realtimer_expire, it);
}
ITIMER_UNLOCK(it);
itimer_fire(it);
ITIMER_LOCK(it);
} else if (timevalisset(&it->it_time.it_value)) {
tv2 = it->it_time.it_value;
timevalsub(&tv2, &tv);
callout_reset(&it->it_callout, tvtohz(&tv2), realtimer_expire,
it);
}
}
void
itimer_fire(struct itimer *it)
{
struct proc *p = it->it_proc;
if (it->it_sigev.sigev_notify == SIGEV_SIGNAL) {
PROC_LOCK(p);
ITIMER_LOCK(it);
if (KSI_ONQ(&it->it_ksi)) {
it->it_overrun++;
it->it_ksi.ksi_overrun = it->it_overrun;
it->it_overrun_last = it->it_overrun;
} else {
it->it_ksi.ksi_overrun = it->it_overrun;
it->it_overrun_last = it->it_overrun;
it->it_overrun = 0;
psignal_info(p, &it->it_ksi);
}
PROC_UNLOCK(p);
ITIMER_UNLOCK(it);
}
}
static void
itimers_alloc(struct proc *p)
{
struct itimer **itp;
itp = malloc(sizeof(struct itimer *) * TIMER_MAX, M_SUBPROC,
M_WAITOK | M_ZERO);
PROC_LOCK(p);
if (p->p_itimers.its_timers == NULL) {
p->p_itimers.its_timers = itp;
PROC_UNLOCK(p);
} else {
PROC_UNLOCK(p);
free(itp, M_SUBPROC);
}
}
void
itimers_init(struct itimers *its)
{
LIST_INIT(&its->its_virtual);
LIST_INIT(&its->its_prof);
TAILQ_INIT(&its->its_worklist);
its->its_timers = NULL;
}
/* Clean up timers when some process events are being triggered. */
void
itimers_event_hook(struct proc *p, int event)
{
struct itimers *its;
struct itimer *it;
int i;
if (p->p_itimers.its_timers != NULL) {
its = &p->p_itimers;
for (i = 0; i < MAX_CLOCKS; ++i) {
if (posix_clocks[i].event_hook != NULL)
CLOCK_CALL(i, event_hook, (p, i, event));
}
/*
* According to susv3, XSI interval timers should be inherited
* by new image.
*/
if (event == ITIMER_EV_EXEC)
i = 3;
else if (event == ITIMER_EV_EXIT)
i = 0;
else
panic("unhandled event");
for (; i < TIMER_MAX; ++i) {
if ((it = its->its_timers[i]) != NULL) {
PROC_LOCK(p);
if (KSI_ONQ(&it->it_ksi))
sigqueue_take(&it->it_ksi);
PROC_UNLOCK(p);
uma_zfree(itimer_zone, its->its_timers[i]);
its->its_timers[i] = NULL;
}
}
if (its->its_timers[0] == NULL &&
its->its_timers[1] == NULL &&
its->its_timers[2] == NULL) {
free(its->its_timers, M_SUBPROC);
p->p_itimers.its_timers = NULL;
}
}
}

View File

@ -439,11 +439,15 @@
const struct timespec *tp); }
234 AUE_NULL MSTD { int clock_getres(clockid_t clock_id, \
struct timespec *tp); }
235 AUE_NULL UNIMPL timer_create
236 AUE_NULL UNIMPL timer_delete
237 AUE_NULL UNIMPL timer_settime
238 AUE_NULL UNIMPL timer_gettime
239 AUE_NULL UNIMPL timer_getoverrun
235 AUE_NULL MSTD { int timer_create(clockid_t clock_id, \
struct sigevent *evp, timer_t *timerid); }
236 AUE_NULL MSTD { int timer_delete(timer_t timerid); }
237 AUE_NULL MSTD { int timer_settime(timer_t timerid, int flags, \
const struct itimerspec *value, \
struct itimerspec *ovalue); }
238 AUE_NULL MSTD { int timer_gettime(timer_t timerid, struct \
itimerspec *value); }
239 AUE_NULL MSTD { int timer_getoverrun(timer_t timerid); }
240 AUE_NULL MSTD { int nanosleep(const struct timespec *rqtp, \
struct timespec *rmtp); }
241 AUE_NULL UNIMPL nosys

View File

@ -57,6 +57,7 @@
#else
#include <sys/pcpu.h>
#endif
#include <sys/timers.h>
#include <sys/ucontext.h>
#include <sys/ucred.h>
#include <machine/proc.h> /* Machine-dependent proc substruct. */
@ -546,6 +547,7 @@ struct proc {
LIST_ENTRY(proc) p_sibling; /* (e) List of sibling processes. */
LIST_HEAD(, proc) p_children; /* (e) Pointer to list of children. */
struct mtx p_mtx; /* (n) Lock for this struct. */
struct itimers p_itimers; /* (c) POSIX interval timers. */
sigqueue_t p_sigqueue; /* (c) Sigs not delivered to a td. */
#define p_siglist p_sigqueue.sq_signals

View File

@ -1,4 +1,5 @@
/*-
* Copyright (c) 2005 David Xu <davidxu@freebsd.org>
* Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
* All rights reserved.
*
@ -37,6 +38,78 @@
#ifndef _SYS_TIMERS_H_
#define _SYS_TIMERS_H_
#include <sys/time.h>
/*
* Structures used to manage POSIX timers in a process.
*/
struct itimer {
struct mtx it_mtx;
struct sigevent it_sigev;
struct itimerval it_time;
struct proc *it_proc;
int it_flags;
int it_usecount;
int it_overrun; /* Overruns currently accumulating */
int it_overrun_last; /* Overruns associated w/ a delivery */
int it_clockid;
int it_timerid;
ksiginfo_t it_ksi;
union {
/* realtime */
struct {
struct callout it_callout;
} _rt;
#endif
/* cpu timer */
struct {
LIST_ENTRY(itimer) it_link;
TAILQ_ENTRY(itimer) it_worklink;
int it_active;
int it_cflags;
} _cpu;
} _data;
};
#define it_callout _data._rt.it_callout
#define it_link _data._cpu.it_link
#define it_active _data._cpu.it_active
#define it_worklink _data._cpu.it_worklink
#define it_cflags _data._cpu.it_cflags
#define ITF_DELETING 0x01
#define ITF_WANTED 0x02
#define ITCF_ONWORKLIST 0x01
#define TIMER_MAX 32
#define ITIMER_LOCK(it) mtx_lock(&(it)->it_mtx)
#define ITIMER_UNLOCK(it) mtx_unlock(&(it)->it_mtx)
LIST_HEAD(itimerlist, itimer);
struct itimers {
struct itimerlist its_virtual;
struct itimerlist its_prof;
TAILQ_HEAD(, itimer) its_worklist;
struct itimer **its_timers;
};
struct kclock {
int (*timer_create)(struct itimer *timer);
int (*timer_settime)(struct itimer * timer, int flags,
struct itimerspec * new_value,
struct itimerspec * old_value);
int (*timer_delete)(struct itimer * timer);
int (*timer_gettime)(struct itimer * timer,
struct itimerspec * cur_value);
void (*event_hook)(struct proc *p, clockid_t clock_id, int event);
};
/* Event values for event_hook() */
#define ITIMER_EV_EXEC 0
#define ITIMER_EV_EXIT 1
void itimers_init(struct itimers *its);
void itimers_event_hook(struct proc *p, int event);
#endif /* !_SYS_TIMERS_H_ */

View File

@ -62,4 +62,13 @@ struct timespec {
#endif /* __BSD_VISIBLE */
/*
* Structure defined by POSIX.1b to be like a itimerval, but with
* timespecs. Used in the timer_*() system calls.
*/
struct itimerspec {
struct timespec it_interval;
struct timespec it_value;
};
#endif /* _SYS_TIMESPEC_H_ */