Subversion Repositories general

Compare Revisions

No changes between revisions

Ignore whitespace Rev 1119 → Rev 1120

/FreeBSD/mac_settime/trunk/bin/clear_src.sh
File deleted
Property changes:
Deleted: svn:executable
-*
\ No newline at end of property
/FreeBSD/mac_settime/trunk/bin/update_src.sh
4,10 → 4,8
# copy our version of files to system
#
# to update the system run as root
# ./clear_src.sh && cvsup src_update && ./copy_orig.sh && ./update_src.sh
# cvsup src_update && ( ./compare_after_update.sh | less ) && ./update_src.sh
#
# then run ./get_diffs.sh as user and examine the diffs
#
 
BIN_DIR=`dirname $0`
BASE_DIR="${BIN_DIR}/.."
/FreeBSD/mac_settime/trunk/bin/compare_after_update.sh
0,0 → 1,19
#!/bin/sh
 
#
# compare the saved original sources na dsources after update
#
 
BIN_DIR=`dirname $0`
SRC_DIR=/usr/src
SAVED_DIR="${BIN_DIR}/../origins"
 
echo "================ sys/kern/kern_time.c ============================ "
diff "${SAVED_DIR}/kern/kern_time.c" "${SRC_DIR}/sys/kern/kern_time.c"
 
echo "================ sys/kern/kern_ntptime.c ========================= "
diff "${SAVED_DIR}/kern/kern_ntptime.c" "${SRC_DIR}/sys/kern/kern_ntptime.c"
 
echo "================ contrib/ntp/ntpd/ntpd.c ========================= "
diff "${SAVED_DIR}/ntp/ntpd.c" "${SRC_DIR}/contrib/ntp/ntpd/ntpd.c"
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/FreeBSD/mac_settime/trunk/bin/copy_orig.sh
4,23 → 4,12
# make copy of all standard files in /usr/src
# which we want to work on to get diffs later
#
# to update the system run as root
# ./clear_src.sh && cvsup src_update && ./copy_orig.sh && ./update_src.sh
#
# then run ./get_diffs.sh as user and examine the diffs
#
 
PATCHED_FILES_KERN="sys/kern/kern_time.c sys/kern/kern_ntptime.c"
PATCHED_FILES_NTP="contrib/ntp/ntpd/ntpd.c"
 
BIN_DIR=`dirname $0`
SRCDIR=/usr/src
SAVED_DIR="${BIN_DIR}/../origins"
 
for f in ${PATCHED_FILES_KERN} ; do
cp "${SRCDIR}/$f" "${SRCDIR}/$f.orig"
done
cp "${SRCDIR}/sys/kern/kern_time.c" "${SAVED_DIR}/kern"
cp "${SRCDIR}/sys/kern/kern_ntptime.c" "${SAVED_DIR}/kern"
cp "${SRCDIR}/contrib/ntp/ntpd/ntpd.c" "${SAVED_DIR}/ntp"
 
for f in ${PATCHED_FILES_NTP} ; do
cp "${SRCDIR}/$f" "${SRCDIR}/$f.orig"
done
 
/FreeBSD/mac_settime/trunk/patched/kern/kern_time.c
30,7 → 30,7
*/
 
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/kern/kern_time.c,v 1.116 2005/03/31 22:51:18 jhb Exp $");
__FBSDID("$FreeBSD: src/sys/kern/kern_time.c,v 1.123 2005/11/04 09:39:17 davidxu Exp $");
 
#include "opt_mac.h"
 
49,6 → 49,7
#include <sys/sysent.h>
#include <sys/proc.h>
#include <sys/time.h>
#include <sys/timers.h>
#include <sys/timetc.h>
#include <sys/vnode.h>
 
55,9 → 56,14
#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.
*
72,6 → 78,34
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 timespec *);
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);
int itimespecfix(struct timespec *ts);
 
#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 int cf_usersettime;
static int cf_jailsettime;
SYSCTL_INT(_kern, OID_AUTO, usersettime, CTLFLAG_RW, &cf_usersettime, 0,
164,19 → 198,31
clock_gettime(struct thread *td, struct clock_gettime_args *uap)
{
struct timespec ats;
int error;
 
error = kern_clock_gettime(td, uap->clock_id, &ats);
if (error == 0)
error = copyout(&ats, uap->tp, sizeof(ats));
 
return (error);
}
 
int
kern_clock_gettime(struct thread *td, clockid_t clock_id, struct timespec *ats)
{
struct timeval sys, user;
struct proc *p;
 
p = td->td_proc;
switch (uap->clock_id) {
switch (clock_id) {
case CLOCK_REALTIME:
nanotime(&ats);
nanotime(ats);
break;
case CLOCK_VIRTUAL:
PROC_LOCK(p);
calcru(p, &user, &sys);
PROC_UNLOCK(p);
TIMEVAL_TO_TIMESPEC(&user, &ats);
TIMEVAL_TO_TIMESPEC(&user, ats);
break;
case CLOCK_PROF:
PROC_LOCK(p);
183,15 → 229,15
calcru(p, &user, &sys);
PROC_UNLOCK(p);
timevaladd(&user, &sys);
TIMEVAL_TO_TIMESPEC(&user, &ats);
TIMEVAL_TO_TIMESPEC(&user, ats);
break;
case CLOCK_MONOTONIC:
nanouptime(&ats);
nanouptime(ats);
break;
default:
return (EINVAL);
}
return (copyout(&ats, uap->tp, sizeof(ats)));
return (0);
}
 
#ifndef _SYS_SYSPROTO_H_
208,10 → 254,20
int
clock_settime(struct thread *td, struct clock_settime_args *uap)
{
struct timeval atv;
struct timespec ats;
int error;
 
if ((error = copyin(uap->tp, &ats, sizeof(ats))) != 0)
return (error);
return (kern_clock_settime(td, uap->clock_id, &ats));
}
 
int
kern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats)
{
struct timeval atv;
int error;
 
#ifdef MAC
error = mac_check_system_settime(td->td_ucred);
if (error)
220,16 → 276,13
if (!cf_jailsettime && jailed(td->td_ucred))
return (EPERM);
if (!cf_usersettime && (error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL)) != 0)
return (error); /* jail is already checked */
 
if (uap->clock_id != CLOCK_REALTIME)
return (error); /* jail is already checked */
if (clock_id != CLOCK_REALTIME)
return (EINVAL);
if ((error = copyin(uap->tp, &ats, sizeof(ats))) != 0)
return (error);
if (ats.tv_nsec < 0 || ats.tv_nsec >= 1000000000)
if (ats->tv_nsec < 0 || ats->tv_nsec >= 1000000000)
return (EINVAL);
/* XXX Don't convert nsec->usec and back */
TIMESPEC_TO_TIMEVAL(&atv, &ats);
TIMESPEC_TO_TIMEVAL(&atv, ats);
error = settime(td, &atv);
return (error);
}
245,9 → 298,23
clock_getres(struct thread *td, struct clock_getres_args *uap)
{
struct timespec ts;
int error;
 
ts.tv_sec = 0;
switch (uap->clock_id) {
if (uap->tp == NULL)
return (0);
 
error = kern_clock_getres(td, uap->clock_id, &ts);
if (error == 0)
error = copyout(&ts, uap->tp, sizeof(ts));
return (error);
}
 
int
kern_clock_getres(struct thread *td, clockid_t clock_id, struct timespec *ts)
{
 
ts->tv_sec = 0;
switch (clock_id) {
case CLOCK_REALTIME:
case CLOCK_MONOTONIC:
/*
255,19 → 322,17
* Rounding up is especially important if rounding down
* would give 0. Perfect rounding is unimportant.
*/
ts.tv_nsec = 1000000000 / tc_getfrequency() + 1;
ts->tv_nsec = 1000000000 / tc_getfrequency() + 1;
break;
case CLOCK_VIRTUAL:
case CLOCK_PROF:
/* Accurately round up here because we can do so cheaply. */
ts.tv_nsec = (1000000000 + hz - 1) / hz;
ts->tv_nsec = (1000000000 + hz - 1) / hz;
break;
default:
return (EINVAL);
}
if (uap->tp == NULL)
return (0);
return (copyout(&ts, uap->tp, sizeof(ts)));
return (0);
}
 
static int nanowait;
410,7 → 475,7
int
kern_settimeofday(struct thread *td, struct timeval *tv, struct timezone *tzp)
{
int error = 0;
int error;
 
#ifdef MAC
error = mac_check_system_settime(td->td_ucred);
420,8 → 485,9
if (!cf_jailsettime && jailed(td->td_ucred))
return (EPERM);
if (!cf_usersettime && (error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL)) != 0)
return (error); /* jail is already checked */
 
return (error); /* jail is already checked */
else
error = 0;
/* Verify all parameters before changing time. */
if (tv) {
if (tv->tv_usec < 0 || tv->tv_usec >= 1000000)
641,8 → 707,7
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;
789,3 → 854,668
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 &&
evp->sigev_notify != SIGEV_THREAD_ID)
return (EINVAL);
if ((evp->sigev_notify == SIGEV_SIGNAL ||
evp->sigev_notify == SIGEV_THREAD_ID) &&
!_SIG_VALID(evp->sigev_signo))
return (EINVAL);
}
if (p->p_itimers == NULL)
itimers_alloc(p);
it = uma_zalloc(itimer_zone, M_WAITOK);
it->it_flags = 0;
it->it_usecount = 0;
it->it_active = 0;
timespecclear(&it->it_time.it_value);
timespecclear(&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.sival_int = id;
}
 
if (it->it_sigev.sigev_notify == SIGEV_SIGNAL ||
it->it_sigev.sigev_notify == SIGEV_THREAD_ID) {
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 == 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 {
td->td_retval[0] = it->it_overrun_last;
ITIMER_UNLOCK(it);
PROC_UNLOCK(p);
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 cts;
 
mtx_assert(&it->it_mtx, MA_OWNED);
 
realtimer_clocktime(it->it_clockid, &cts);
*ovalue = it->it_time;
if (ovalue->it_value.tv_sec != 0 || ovalue->it_value.tv_nsec != 0) {
timespecsub(&ovalue->it_value, &cts);
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 timespec cts, ts;
struct timeval tv;
struct itimerspec val;
 
mtx_assert(&it->it_mtx, MA_OWNED);
 
val = *value;
if (itimespecfix(&val.it_value))
return (EINVAL);
 
if (timespecisset(&val.it_value)) {
if (itimespecfix(&val.it_interval))
return (EINVAL);
} else {
timespecclear(&val.it_interval);
}
if (ovalue != NULL)
realtimer_gettime(it, ovalue);
 
it->it_time = val;
if (timespecisset(&val.it_value)) {
realtimer_clocktime(it->it_clockid, &cts);
ts = val.it_value;
if ((flags & TIMER_ABSTIME) == 0) {
/* Convert to absolute time. */
timespecadd(&it->it_time.it_value, &cts);
} else {
timespecsub(&ts, &cts);
/*
* We don't care if ts is negative, tztohz will
* fix it.
*/
}
TIMESPEC_TO_TIMEVAL(&tv, &ts);
callout_reset(&it->it_callout, tvtohz(&tv),
realtimer_expire, it);
} else {
callout_stop(&it->it_callout);
}
 
return (0);
}
 
static void
realtimer_clocktime(clockid_t id, struct timespec *ts)
{
if (id == CLOCK_REALTIME)
getnanotime(ts);
else /* CLOCK_MONOTONIC */
getnanouptime(ts);
}
 
int
itimer_accept(struct proc *p, timer_t timerid, ksiginfo_t *ksi)
{
struct itimer *it;
 
PROC_LOCK_ASSERT(p, MA_OWNED);
it = itimer_find(p, timerid, 0);
if (it != NULL) {
ksi->ksi_overrun = it->it_overrun;
it->it_overrun_last = it->it_overrun;
it->it_overrun = 0;
ITIMER_UNLOCK(it);
return (0);
}
return (EINVAL);
}
 
int
itimespecfix(struct timespec *ts)
{
 
if (ts->tv_sec < 0 || ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000)
return (EINVAL);
if (ts->tv_sec == 0 && ts->tv_nsec != 0 && ts->tv_nsec < tick * 1000)
ts->tv_nsec = tick * 1000;
return (0);
}
 
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 timespec cts, ts;
struct timeval tv;
struct itimer *it;
struct proc *p;
 
it = (struct itimer *)arg;
p = it->it_proc;
 
realtimer_clocktime(it->it_clockid, &cts);
/* Only fire if time is reached. */
if (timespeccmp(&cts, &it->it_time.it_value, >=)) {
if (timespecisset(&it->it_time.it_interval)) {
timespecadd(&it->it_time.it_value,
&it->it_time.it_interval);
while (timespeccmp(&cts, &it->it_time.it_value, >=)) {
it->it_overrun++;
timespecadd(&it->it_time.it_value,
&it->it_time.it_interval);
}
} else {
/* single shot timer ? */
timespecclear(&it->it_time.it_value);
}
if (timespecisset(&it->it_time.it_value)) {
ts = it->it_time.it_value;
timespecsub(&ts, &cts);
TIMESPEC_TO_TIMEVAL(&tv, &ts);
callout_reset(&it->it_callout, tvtohz(&tv),
realtimer_expire, it);
}
ITIMER_UNLOCK(it);
itimer_fire(it);
ITIMER_LOCK(it);
} else if (timespecisset(&it->it_time.it_value)) {
ts = it->it_time.it_value;
timespecsub(&ts, &cts);
TIMESPEC_TO_TIMEVAL(&tv, &ts);
callout_reset(&it->it_callout, tvtohz(&tv), realtimer_expire,
it);
}
}
 
void
itimer_fire(struct itimer *it)
{
struct proc *p = it->it_proc;
int ret;
 
if (it->it_sigev.sigev_notify == SIGEV_SIGNAL ||
it->it_sigev.sigev_notify == SIGEV_THREAD_ID) {
PROC_LOCK(p);
if (!KSI_ONQ(&it->it_ksi)) {
ret = psignal_event(p, &it->it_sigev, &it->it_ksi);
if (__predict_false(ret != 0)) {
it->it_overrun++;
/*
* Broken userland code, thread went
* away, disarm the timer.
*/
if (ret == ESRCH) {
ITIMER_LOCK(it);
timespecclear(&it->it_time.it_value);
timespecclear(&it->it_time.it_interval);
callout_stop(&it->it_callout);
ITIMER_UNLOCK(it);
}
}
} else {
it->it_overrun++;
}
PROC_UNLOCK(p);
}
}
 
static void
itimers_alloc(struct proc *p)
{
struct itimers *its;
int i;
 
its = malloc(sizeof (struct itimers), M_SUBPROC, M_WAITOK | M_ZERO);
LIST_INIT(&its->its_virtual);
LIST_INIT(&its->its_prof);
TAILQ_INIT(&its->its_worklist);
for (i = 0; i < TIMER_MAX; i++)
its->its_timers[i] = NULL;
PROC_LOCK(p);
if (p->p_itimers == NULL) {
p->p_itimers = its;
PROC_UNLOCK(p);
}
else {
PROC_UNLOCK(p);
free(its, M_SUBPROC);
}
}
 
/* 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 != 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, M_SUBPROC);
p->p_itimers = NULL;
}
}
}
/FreeBSD/mac_settime/trunk/patched/kern/kern_ntptime.c
968,7 → 968,7
kern_adjtime(struct thread *td, struct timeval *delta, struct timeval *olddelta)
{
struct timeval atv;
int error = 0;
int error;
 
#ifdef MAC
error = mac_check_system_settime(td->td_ucred);
979,6 → 979,8
return (EPERM);
if (!cf_useradjtime && (error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL)) != 0)
return (error); /* jail is already checked */
else
error = 0;
 
mtx_lock(&Giant);
if (olddelta) {
/FreeBSD/mac_settime/trunk/origins/kern/kern_time.c
30,7 → 30,7
*/
 
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/kern/kern_time.c,v 1.116 2005/03/31 22:51:18 jhb Exp $");
__FBSDID("$FreeBSD: src/sys/kern/kern_time.c,v 1.123 2005/11/04 09:39:17 davidxu Exp $");
 
#include "opt_mac.h"
 
47,6 → 47,7
#include <sys/sysent.h>
#include <sys/proc.h>
#include <sys/time.h>
#include <sys/timers.h>
#include <sys/timetc.h>
#include <sys/vnode.h>
 
53,9 → 54,14
#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,35
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 timespec *);
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);
int itimespecfix(struct timespec *ts);
 
#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;
155,19 → 190,31
clock_gettime(struct thread *td, struct clock_gettime_args *uap)
{
struct timespec ats;
int error;
 
error = kern_clock_gettime(td, uap->clock_id, &ats);
if (error == 0)
error = copyout(&ats, uap->tp, sizeof(ats));
 
return (error);
}
 
int
kern_clock_gettime(struct thread *td, clockid_t clock_id, struct timespec *ats)
{
struct timeval sys, user;
struct proc *p;
 
p = td->td_proc;
switch (uap->clock_id) {
switch (clock_id) {
case CLOCK_REALTIME:
nanotime(&ats);
nanotime(ats);
break;
case CLOCK_VIRTUAL:
PROC_LOCK(p);
calcru(p, &user, &sys);
PROC_UNLOCK(p);
TIMEVAL_TO_TIMESPEC(&user, &ats);
TIMEVAL_TO_TIMESPEC(&user, ats);
break;
case CLOCK_PROF:
PROC_LOCK(p);
174,15 → 221,15
calcru(p, &user, &sys);
PROC_UNLOCK(p);
timevaladd(&user, &sys);
TIMEVAL_TO_TIMESPEC(&user, &ats);
TIMEVAL_TO_TIMESPEC(&user, ats);
break;
case CLOCK_MONOTONIC:
nanouptime(&ats);
nanouptime(ats);
break;
default:
return (EINVAL);
}
return (copyout(&ats, uap->tp, sizeof(ats)));
return (0);
}
 
#ifndef _SYS_SYSPROTO_H_
199,10 → 246,20
int
clock_settime(struct thread *td, struct clock_settime_args *uap)
{
struct timeval atv;
struct timespec ats;
int error;
 
if ((error = copyin(uap->tp, &ats, sizeof(ats))) != 0)
return (error);
return (kern_clock_settime(td, uap->clock_id, &ats));
}
 
int
kern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats)
{
struct timeval atv;
int error;
 
#ifdef MAC
error = mac_check_system_settime(td->td_ucred);
if (error)
210,14 → 267,12
#endif
if ((error = suser(td)) != 0)
return (error);
if (uap->clock_id != CLOCK_REALTIME)
if (clock_id != CLOCK_REALTIME)
return (EINVAL);
if ((error = copyin(uap->tp, &ats, sizeof(ats))) != 0)
return (error);
if (ats.tv_nsec < 0 || ats.tv_nsec >= 1000000000)
if (ats->tv_nsec < 0 || ats->tv_nsec >= 1000000000)
return (EINVAL);
/* XXX Don't convert nsec->usec and back */
TIMESPEC_TO_TIMEVAL(&atv, &ats);
TIMESPEC_TO_TIMEVAL(&atv, ats);
error = settime(td, &atv);
return (error);
}
233,9 → 288,23
clock_getres(struct thread *td, struct clock_getres_args *uap)
{
struct timespec ts;
int error;
 
ts.tv_sec = 0;
switch (uap->clock_id) {
if (uap->tp == NULL)
return (0);
 
error = kern_clock_getres(td, uap->clock_id, &ts);
if (error == 0)
error = copyout(&ts, uap->tp, sizeof(ts));
return (error);
}
 
int
kern_clock_getres(struct thread *td, clockid_t clock_id, struct timespec *ts)
{
 
ts->tv_sec = 0;
switch (clock_id) {
case CLOCK_REALTIME:
case CLOCK_MONOTONIC:
/*
243,19 → 312,17
* Rounding up is especially important if rounding down
* would give 0. Perfect rounding is unimportant.
*/
ts.tv_nsec = 1000000000 / tc_getfrequency() + 1;
ts->tv_nsec = 1000000000 / tc_getfrequency() + 1;
break;
case CLOCK_VIRTUAL:
case CLOCK_PROF:
/* Accurately round up here because we can do so cheaply. */
ts.tv_nsec = (1000000000 + hz - 1) / hz;
ts->tv_nsec = (1000000000 + hz - 1) / hz;
break;
default:
return (EINVAL);
}
if (uap->tp == NULL)
return (0);
return (copyout(&ts, uap->tp, sizeof(ts)));
return (0);
}
 
static int nanowait;
627,8 → 694,7
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;
775,3 → 841,668
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 &&
evp->sigev_notify != SIGEV_THREAD_ID)
return (EINVAL);
if ((evp->sigev_notify == SIGEV_SIGNAL ||
evp->sigev_notify == SIGEV_THREAD_ID) &&
!_SIG_VALID(evp->sigev_signo))
return (EINVAL);
}
if (p->p_itimers == NULL)
itimers_alloc(p);
it = uma_zalloc(itimer_zone, M_WAITOK);
it->it_flags = 0;
it->it_usecount = 0;
it->it_active = 0;
timespecclear(&it->it_time.it_value);
timespecclear(&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.sival_int = id;
}
 
if (it->it_sigev.sigev_notify == SIGEV_SIGNAL ||
it->it_sigev.sigev_notify == SIGEV_THREAD_ID) {
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 == 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 {
td->td_retval[0] = it->it_overrun_last;
ITIMER_UNLOCK(it);
PROC_UNLOCK(p);
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 cts;
 
mtx_assert(&it->it_mtx, MA_OWNED);
 
realtimer_clocktime(it->it_clockid, &cts);
*ovalue = it->it_time;
if (ovalue->it_value.tv_sec != 0 || ovalue->it_value.tv_nsec != 0) {
timespecsub(&ovalue->it_value, &cts);
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 timespec cts, ts;
struct timeval tv;
struct itimerspec val;
 
mtx_assert(&it->it_mtx, MA_OWNED);
 
val = *value;
if (itimespecfix(&val.it_value))
return (EINVAL);
 
if (timespecisset(&val.it_value)) {
if (itimespecfix(&val.it_interval))
return (EINVAL);
} else {
timespecclear(&val.it_interval);
}
if (ovalue != NULL)
realtimer_gettime(it, ovalue);
 
it->it_time = val;
if (timespecisset(&val.it_value)) {
realtimer_clocktime(it->it_clockid, &cts);
ts = val.it_value;
if ((flags & TIMER_ABSTIME) == 0) {
/* Convert to absolute time. */
timespecadd(&it->it_time.it_value, &cts);
} else {
timespecsub(&ts, &cts);
/*
* We don't care if ts is negative, tztohz will
* fix it.
*/
}
TIMESPEC_TO_TIMEVAL(&tv, &ts);
callout_reset(&it->it_callout, tvtohz(&tv),
realtimer_expire, it);
} else {
callout_stop(&it->it_callout);
}
 
return (0);
}
 
static void
realtimer_clocktime(clockid_t id, struct timespec *ts)
{
if (id == CLOCK_REALTIME)
getnanotime(ts);
else /* CLOCK_MONOTONIC */
getnanouptime(ts);
}
 
int
itimer_accept(struct proc *p, timer_t timerid, ksiginfo_t *ksi)
{
struct itimer *it;
 
PROC_LOCK_ASSERT(p, MA_OWNED);
it = itimer_find(p, timerid, 0);
if (it != NULL) {
ksi->ksi_overrun = it->it_overrun;
it->it_overrun_last = it->it_overrun;
it->it_overrun = 0;
ITIMER_UNLOCK(it);
return (0);
}
return (EINVAL);
}
 
int
itimespecfix(struct timespec *ts)
{
 
if (ts->tv_sec < 0 || ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000)
return (EINVAL);
if (ts->tv_sec == 0 && ts->tv_nsec != 0 && ts->tv_nsec < tick * 1000)
ts->tv_nsec = tick * 1000;
return (0);
}
 
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 timespec cts, ts;
struct timeval tv;
struct itimer *it;
struct proc *p;
 
it = (struct itimer *)arg;
p = it->it_proc;
 
realtimer_clocktime(it->it_clockid, &cts);
/* Only fire if time is reached. */
if (timespeccmp(&cts, &it->it_time.it_value, >=)) {
if (timespecisset(&it->it_time.it_interval)) {
timespecadd(&it->it_time.it_value,
&it->it_time.it_interval);
while (timespeccmp(&cts, &it->it_time.it_value, >=)) {
it->it_overrun++;
timespecadd(&it->it_time.it_value,
&it->it_time.it_interval);
}
} else {
/* single shot timer ? */
timespecclear(&it->it_time.it_value);
}
if (timespecisset(&it->it_time.it_value)) {
ts = it->it_time.it_value;
timespecsub(&ts, &cts);
TIMESPEC_TO_TIMEVAL(&tv, &ts);
callout_reset(&it->it_callout, tvtohz(&tv),
realtimer_expire, it);
}
ITIMER_UNLOCK(it);
itimer_fire(it);
ITIMER_LOCK(it);
} else if (timespecisset(&it->it_time.it_value)) {
ts = it->it_time.it_value;
timespecsub(&ts, &cts);
TIMESPEC_TO_TIMEVAL(&tv, &ts);
callout_reset(&it->it_callout, tvtohz(&tv), realtimer_expire,
it);
}
}
 
void
itimer_fire(struct itimer *it)
{
struct proc *p = it->it_proc;
int ret;
 
if (it->it_sigev.sigev_notify == SIGEV_SIGNAL ||
it->it_sigev.sigev_notify == SIGEV_THREAD_ID) {
PROC_LOCK(p);
if (!KSI_ONQ(&it->it_ksi)) {
ret = psignal_event(p, &it->it_sigev, &it->it_ksi);
if (__predict_false(ret != 0)) {
it->it_overrun++;
/*
* Broken userland code, thread went
* away, disarm the timer.
*/
if (ret == ESRCH) {
ITIMER_LOCK(it);
timespecclear(&it->it_time.it_value);
timespecclear(&it->it_time.it_interval);
callout_stop(&it->it_callout);
ITIMER_UNLOCK(it);
}
}
} else {
it->it_overrun++;
}
PROC_UNLOCK(p);
}
}
 
static void
itimers_alloc(struct proc *p)
{
struct itimers *its;
int i;
 
its = malloc(sizeof (struct itimers), M_SUBPROC, M_WAITOK | M_ZERO);
LIST_INIT(&its->its_virtual);
LIST_INIT(&its->its_prof);
TAILQ_INIT(&its->its_worklist);
for (i = 0; i < TIMER_MAX; i++)
its->its_timers[i] = NULL;
PROC_LOCK(p);
if (p->p_itimers == NULL) {
p->p_itimers = its;
PROC_UNLOCK(p);
}
else {
PROC_UNLOCK(p);
free(its, M_SUBPROC);
}
}
 
/* 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 != 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, M_SUBPROC);
p->p_itimers = NULL;
}
}
}