version 1.141, 2008/02/25 12:25:03 |
version 1.141.4.1, 2008/05/18 12:35:09 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
|
|
/*- |
/*- |
* Copyright (c) 2000, 2004, 2005, 2007 The NetBSD Foundation, Inc. |
* Copyright (c) 2000, 2004, 2005, 2007, 2008 The NetBSD Foundation, Inc. |
* All rights reserved. |
* All rights reserved. |
* |
* |
* This code is derived from software contributed to The NetBSD Foundation |
* This code is derived from software contributed to The NetBSD Foundation |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
|
* must display the following acknowledgement: |
|
* This product includes software developed by the NetBSD |
|
* Foundation, Inc. and its contributors. |
|
* 4. Neither the name of The NetBSD Foundation nor the names of its |
|
* contributors may be used to endorse or promote products derived |
|
* from this software without specific prior written permission. |
|
* |
* |
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
Line 79 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 72 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/signalvar.h> |
#include <sys/signalvar.h> |
#include <sys/syslog.h> |
#include <sys/syslog.h> |
#include <sys/timetc.h> |
#include <sys/timetc.h> |
|
#include <sys/timex.h> |
#include <sys/kauth.h> |
#include <sys/kauth.h> |
|
|
#include <sys/mount.h> |
#include <sys/mount.h> |
#include <sys/syscallargs.h> |
#include <sys/syscallargs.h> |
|
#include <sys/cpu.h> |
|
|
#include <uvm/uvm_extern.h> |
#include <uvm/uvm_extern.h> |
|
|
#include <sys/cpu.h> |
static void timer_intr(void *); |
|
static void itimerfire(struct ptimer *); |
|
static void itimerfree(struct ptimers *, int); |
|
|
kmutex_t time_lock; |
kmutex_t timer_lock; |
|
|
|
static void *timer_sih; |
|
static TAILQ_HEAD(, ptimer) timer_queue; |
|
|
POOL_INIT(ptimer_pool, sizeof(struct ptimer), 0, 0, 0, "ptimerpl", |
POOL_INIT(ptimer_pool, sizeof(struct ptimer), 0, 0, 0, "ptimerpl", |
&pool_allocator_nointr, IPL_NONE); |
&pool_allocator_nointr, IPL_NONE); |
|
|
time_init(void) |
time_init(void) |
{ |
{ |
|
|
mutex_init(&time_lock, MUTEX_DEFAULT, IPL_NONE); |
/* nothing yet */ |
|
} |
|
|
|
void |
|
time_init2(void) |
|
{ |
|
|
|
TAILQ_INIT(&timer_queue); |
|
mutex_init(&timer_lock, MUTEX_DEFAULT, IPL_SCHED); |
|
timer_sih = softint_establish(SOFTINT_CLOCK | SOFTINT_MPSAFE, |
|
timer_intr, NULL); |
} |
} |
|
|
/* Time of day and interval timer support. |
/* Time of day and interval timer support. |
Line 157 settime1(struct proc *p, struct timespec |
|
Line 166 settime1(struct proc *p, struct timespec |
|
* pausing all CPUs while we adjust the clock. |
* pausing all CPUs while we adjust the clock. |
*/ |
*/ |
timeval2bintime(&delta, &btdelta); |
timeval2bintime(&delta, &btdelta); |
mutex_enter(&proclist_lock); |
mutex_enter(proc_lock); |
LIST_FOREACH(l, &alllwp, l_list) { |
LIST_FOREACH(l, &alllwp, l_list) { |
lwp_lock(l); |
lwp_lock(l); |
bintime_add(&l->l_stime, &btdelta); |
bintime_add(&l->l_stime, &btdelta); |
lwp_unlock(l); |
lwp_unlock(l); |
} |
} |
mutex_exit(&proclist_lock); |
mutex_exit(proc_lock); |
resettodr(); |
resettodr(); |
splx(s); |
splx(s); |
|
|
Line 446 adjtime1(const struct timeval *delta, st |
|
Line 455 adjtime1(const struct timeval *delta, st |
|
extern int64_t time_adjtime; /* in kern_ntptime.c */ |
extern int64_t time_adjtime; /* in kern_ntptime.c */ |
|
|
if (olddelta) { |
if (olddelta) { |
|
mutex_spin_enter(&timecounter_lock); |
atv.tv_sec = time_adjtime / 1000000; |
atv.tv_sec = time_adjtime / 1000000; |
atv.tv_usec = time_adjtime % 1000000; |
atv.tv_usec = time_adjtime % 1000000; |
|
mutex_spin_exit(&timecounter_lock); |
if (atv.tv_usec < 0) { |
if (atv.tv_usec < 0) { |
atv.tv_usec += 1000000; |
atv.tv_usec += 1000000; |
atv.tv_sec--; |
atv.tv_sec--; |
Line 462 adjtime1(const struct timeval *delta, st |
|
Line 473 adjtime1(const struct timeval *delta, st |
|
if (error) |
if (error) |
return (error); |
return (error); |
|
|
|
mutex_spin_enter(&timecounter_lock); |
time_adjtime = (int64_t)atv.tv_sec * 1000000 + |
time_adjtime = (int64_t)atv.tv_sec * 1000000 + |
atv.tv_usec; |
atv.tv_usec; |
|
if (time_adjtime) { |
if (time_adjtime) |
|
/* We need to save the system time during shutdown */ |
/* We need to save the system time during shutdown */ |
time_adjusted |= 1; |
time_adjusted |= 1; |
|
} |
|
mutex_spin_exit(&timecounter_lock); |
} |
} |
|
|
return error; |
return error; |
Line 517 timer_create1(timer_t *tid, clockid_t id |
|
Line 530 timer_create1(timer_t *tid, clockid_t id |
|
{ |
{ |
int error; |
int error; |
timer_t timerid; |
timer_t timerid; |
|
struct ptimers *pts; |
struct ptimer *pt; |
struct ptimer *pt; |
struct proc *p; |
struct proc *p; |
|
|
p = l->l_proc; |
p = l->l_proc; |
|
|
if (id < CLOCK_REALTIME || |
if (id < CLOCK_REALTIME || id > CLOCK_PROF) |
id > CLOCK_PROF) |
|
return (EINVAL); |
return (EINVAL); |
|
|
if (p->p_timers == NULL) |
if ((pts = p->p_timers) == NULL) |
timers_alloc(p); |
pts = timers_alloc(p); |
|
|
/* Find a free timer slot, skipping those reserved for setitimer(). */ |
|
for (timerid = 3; timerid < TIMER_MAX; timerid++) |
|
if (p->p_timers->pts_timers[timerid] == NULL) |
|
break; |
|
|
|
if (timerid == TIMER_MAX) |
|
return EAGAIN; |
|
|
|
pt = pool_get(&ptimer_pool, PR_WAITOK); |
pt = pool_get(&ptimer_pool, PR_WAITOK); |
if (evp) { |
if (evp != NULL) { |
if (((error = |
if (((error = |
(*fetch_event)(evp, &pt->pt_ev, sizeof(pt->pt_ev))) != 0) || |
(*fetch_event)(evp, &pt->pt_ev, sizeof(pt->pt_ev))) != 0) || |
((pt->pt_ev.sigev_notify < SIGEV_NONE) || |
((pt->pt_ev.sigev_notify < SIGEV_NONE) || |
Line 546 timer_create1(timer_t *tid, clockid_t id |
|
Line 551 timer_create1(timer_t *tid, clockid_t id |
|
pool_put(&ptimer_pool, pt); |
pool_put(&ptimer_pool, pt); |
return (error ? error : EINVAL); |
return (error ? error : EINVAL); |
} |
} |
} else { |
} |
|
|
|
/* Find a free timer slot, skipping those reserved for setitimer(). */ |
|
mutex_spin_enter(&timer_lock); |
|
for (timerid = 3; timerid < TIMER_MAX; timerid++) |
|
if (pts->pts_timers[timerid] == NULL) |
|
break; |
|
if (timerid == TIMER_MAX) { |
|
mutex_spin_exit(&timer_lock); |
|
pool_put(&ptimer_pool, pt); |
|
return EAGAIN; |
|
} |
|
if (evp == NULL) { |
pt->pt_ev.sigev_notify = SIGEV_SIGNAL; |
pt->pt_ev.sigev_notify = SIGEV_SIGNAL; |
switch (id) { |
switch (id) { |
case CLOCK_REALTIME: |
case CLOCK_REALTIME: |
Line 567 timer_create1(timer_t *tid, clockid_t id |
|
Line 584 timer_create1(timer_t *tid, clockid_t id |
|
pt->pt_info.ksi_pid = p->p_pid; |
pt->pt_info.ksi_pid = p->p_pid; |
pt->pt_info.ksi_uid = kauth_cred_getuid(l->l_cred); |
pt->pt_info.ksi_uid = kauth_cred_getuid(l->l_cred); |
pt->pt_info.ksi_value = pt->pt_ev.sigev_value; |
pt->pt_info.ksi_value = pt->pt_ev.sigev_value; |
|
|
pt->pt_type = id; |
pt->pt_type = id; |
pt->pt_proc = p; |
pt->pt_proc = p; |
pt->pt_overruns = 0; |
pt->pt_overruns = 0; |
pt->pt_poverruns = 0; |
pt->pt_poverruns = 0; |
pt->pt_entry = timerid; |
pt->pt_entry = timerid; |
|
pt->pt_queued = false; |
|
pt->pt_active = 0; |
timerclear(&pt->pt_time.it_value); |
timerclear(&pt->pt_time.it_value); |
if (id == CLOCK_REALTIME) |
callout_init(&pt->pt_ch, 0); |
callout_init(&pt->pt_ch, 0); |
pts->pts_timers[timerid] = pt; |
else |
mutex_spin_exit(&timer_lock); |
pt->pt_active = 0; |
|
|
|
p->p_timers->pts_timers[timerid] = pt; |
|
|
|
return copyout(&timerid, tid, sizeof(timerid)); |
return copyout(&timerid, tid, sizeof(timerid)); |
} |
} |
Line 594 sys_timer_delete(struct lwp *l, const st |
|
Line 609 sys_timer_delete(struct lwp *l, const st |
|
} */ |
} */ |
struct proc *p = l->l_proc; |
struct proc *p = l->l_proc; |
timer_t timerid; |
timer_t timerid; |
|
struct ptimers *pts; |
struct ptimer *pt, *ptn; |
struct ptimer *pt, *ptn; |
int s; |
|
|
|
timerid = SCARG(uap, timerid); |
timerid = SCARG(uap, timerid); |
|
pts = p->p_timers; |
if ((p->p_timers == NULL) || |
|
(timerid < 2) || (timerid >= TIMER_MAX) || |
if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX) |
((pt = p->p_timers->pts_timers[timerid]) == NULL)) |
|
return (EINVAL); |
return (EINVAL); |
|
|
if (pt->pt_type == CLOCK_REALTIME) { |
mutex_spin_enter(&timer_lock); |
callout_stop(&pt->pt_ch); |
if ((pt = pts->pts_timers[timerid]) == NULL) { |
callout_destroy(&pt->pt_ch); |
mutex_spin_exit(&timer_lock); |
} else if (pt->pt_active) { |
return (EINVAL); |
s = splclock(); |
} |
|
if (pt->pt_active) { |
ptn = LIST_NEXT(pt, pt_list); |
ptn = LIST_NEXT(pt, pt_list); |
LIST_REMOVE(pt, pt_list); |
LIST_REMOVE(pt, pt_list); |
for ( ; ptn; ptn = LIST_NEXT(ptn, pt_list)) |
for ( ; ptn; ptn = LIST_NEXT(ptn, pt_list)) |
timeradd(&pt->pt_time.it_value, &ptn->pt_time.it_value, |
timeradd(&pt->pt_time.it_value, &ptn->pt_time.it_value, |
&ptn->pt_time.it_value); |
&ptn->pt_time.it_value); |
splx(s); |
pt->pt_active = 0; |
} |
} |
|
itimerfree(pts, timerid); |
p->p_timers->pts_timers[timerid] = NULL; |
|
pool_put(&ptimer_pool, pt); |
|
|
|
return (0); |
return (0); |
} |
} |
Line 635 timer_settime(struct ptimer *pt) |
|
Line 648 timer_settime(struct ptimer *pt) |
|
struct ptimer *ptn, *pptn; |
struct ptimer *ptn, *pptn; |
struct ptlist *ptl; |
struct ptlist *ptl; |
|
|
|
KASSERT(mutex_owned(&timer_lock)); |
|
|
if (pt->pt_type == CLOCK_REALTIME) { |
if (pt->pt_type == CLOCK_REALTIME) { |
callout_stop(&pt->pt_ch); |
callout_stop(&pt->pt_ch); |
if (timerisset(&pt->pt_time.it_value)) { |
if (timerisset(&pt->pt_time.it_value)) { |
Line 690 timer_gettime(struct ptimer *pt, struct |
|
Line 705 timer_gettime(struct ptimer *pt, struct |
|
struct timeval now; |
struct timeval now; |
struct ptimer *ptn; |
struct ptimer *ptn; |
|
|
|
KASSERT(mutex_owned(&timer_lock)); |
|
|
*aitv = pt->pt_time; |
*aitv = pt->pt_time; |
if (pt->pt_type == CLOCK_REALTIME) { |
if (pt->pt_type == CLOCK_REALTIME) { |
/* |
/* |
Line 759 dotimer_settime(int timerid, struct itim |
|
Line 776 dotimer_settime(int timerid, struct itim |
|
{ |
{ |
struct timeval now; |
struct timeval now; |
struct itimerval val, oval; |
struct itimerval val, oval; |
|
struct ptimers *pts; |
struct ptimer *pt; |
struct ptimer *pt; |
int s; |
|
|
|
if ((p->p_timers == NULL) || |
pts = p->p_timers; |
(timerid < 2) || (timerid >= TIMER_MAX) || |
|
((pt = p->p_timers->pts_timers[timerid]) == NULL)) |
|
return (EINVAL); |
|
|
|
|
if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX) |
|
return EINVAL; |
TIMESPEC_TO_TIMEVAL(&val.it_value, &value->it_value); |
TIMESPEC_TO_TIMEVAL(&val.it_value, &value->it_value); |
TIMESPEC_TO_TIMEVAL(&val.it_interval, &value->it_interval); |
TIMESPEC_TO_TIMEVAL(&val.it_interval, &value->it_interval); |
if (itimerfix(&val.it_value) || itimerfix(&val.it_interval)) |
if (itimerfix(&val.it_value) || itimerfix(&val.it_interval)) |
return (EINVAL); |
return (EINVAL); |
|
|
|
mutex_spin_enter(&timer_lock); |
|
if ((pt = pts->pts_timers[timerid]) == NULL) { |
|
mutex_spin_exit(&timer_lock); |
|
return (EINVAL); |
|
} |
|
|
oval = pt->pt_time; |
oval = pt->pt_time; |
pt->pt_time = val; |
pt->pt_time = val; |
|
|
s = splclock(); |
|
/* |
/* |
* If we've been passed a relative time for a realtime timer, |
* If we've been passed a relative time for a realtime timer, |
* convert it to absolute; if an absolute time for a virtual |
* convert it to absolute; if an absolute time for a virtual |
Line 805 dotimer_settime(int timerid, struct itim |
|
Line 826 dotimer_settime(int timerid, struct itim |
|
} |
} |
|
|
timer_settime(pt); |
timer_settime(pt); |
splx(s); |
mutex_spin_exit(&timer_lock); |
|
|
if (ovalue) { |
if (ovalue) { |
TIMEVAL_TO_TIMESPEC(&oval.it_value, &ovalue->it_value); |
TIMEVAL_TO_TIMESPEC(&oval.it_value, &ovalue->it_value); |
Line 837 sys_timer_gettime(struct lwp *l, const s |
|
Line 858 sys_timer_gettime(struct lwp *l, const s |
|
int |
int |
dotimer_gettime(int timerid, struct proc *p, struct itimerspec *its) |
dotimer_gettime(int timerid, struct proc *p, struct itimerspec *its) |
{ |
{ |
int s; |
|
struct ptimer *pt; |
struct ptimer *pt; |
|
struct ptimers *pts; |
struct itimerval aitv; |
struct itimerval aitv; |
|
|
if ((p->p_timers == NULL) || |
pts = p->p_timers; |
(timerid < 2) || (timerid >= TIMER_MAX) || |
if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX) |
((pt = p->p_timers->pts_timers[timerid]) == NULL)) |
|
return (EINVAL); |
return (EINVAL); |
|
mutex_spin_enter(&timer_lock); |
s = splclock(); |
if ((pt = pts->pts_timers[timerid]) == NULL) { |
|
mutex_spin_exit(&timer_lock); |
|
return (EINVAL); |
|
} |
timer_gettime(pt, &aitv); |
timer_gettime(pt, &aitv); |
splx(s); |
mutex_spin_exit(&timer_lock); |
|
|
TIMEVAL_TO_TIMESPEC(&aitv.it_interval, &its->it_interval); |
TIMEVAL_TO_TIMESPEC(&aitv.it_interval, &its->it_interval); |
TIMEVAL_TO_TIMESPEC(&aitv.it_value, &its->it_value); |
TIMEVAL_TO_TIMESPEC(&aitv.it_value, &its->it_value); |
Line 869 sys_timer_getoverrun(struct lwp *l, cons |
|
Line 892 sys_timer_getoverrun(struct lwp *l, cons |
|
syscallarg(timer_t) timerid; |
syscallarg(timer_t) timerid; |
} */ |
} */ |
struct proc *p = l->l_proc; |
struct proc *p = l->l_proc; |
|
struct ptimers *pts; |
int timerid; |
int timerid; |
struct ptimer *pt; |
struct ptimer *pt; |
|
|
timerid = SCARG(uap, timerid); |
timerid = SCARG(uap, timerid); |
|
|
if ((p->p_timers == NULL) || |
pts = p->p_timers; |
(timerid < 2) || (timerid >= TIMER_MAX) || |
if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX) |
((pt = p->p_timers->pts_timers[timerid]) == NULL)) |
|
return (EINVAL); |
return (EINVAL); |
|
mutex_spin_enter(&timer_lock); |
|
if ((pt = pts->pts_timers[timerid]) == NULL) { |
|
mutex_spin_exit(&timer_lock); |
|
return (EINVAL); |
|
} |
*retval = pt->pt_poverruns; |
*retval = pt->pt_poverruns; |
|
mutex_spin_exit(&timer_lock); |
|
|
return (0); |
return (0); |
} |
} |
Line 897 realtimerexpire(void *arg) |
|
Line 925 realtimerexpire(void *arg) |
|
{ |
{ |
struct timeval now; |
struct timeval now; |
struct ptimer *pt; |
struct ptimer *pt; |
int s; |
|
|
|
pt = (struct ptimer *)arg; |
pt = arg; |
|
|
|
mutex_spin_enter(&timer_lock); |
itimerfire(pt); |
itimerfire(pt); |
|
|
if (!timerisset(&pt->pt_time.it_interval)) { |
if (!timerisset(&pt->pt_time.it_interval)) { |
timerclear(&pt->pt_time.it_value); |
timerclear(&pt->pt_time.it_value); |
|
mutex_spin_exit(&timer_lock); |
return; |
return; |
} |
} |
for (;;) { |
for (;;) { |
s = splclock(); /* XXX need spl now? */ |
|
timeradd(&pt->pt_time.it_value, |
timeradd(&pt->pt_time.it_value, |
&pt->pt_time.it_interval, &pt->pt_time.it_value); |
&pt->pt_time.it_interval, &pt->pt_time.it_value); |
getmicrotime(&now); |
getmicrotime(&now); |
Line 919 realtimerexpire(void *arg) |
|
Line 947 realtimerexpire(void *arg) |
|
*/ |
*/ |
callout_reset(&pt->pt_ch, hzto(&pt->pt_time.it_value), |
callout_reset(&pt->pt_ch, hzto(&pt->pt_time.it_value), |
realtimerexpire, pt); |
realtimerexpire, pt); |
splx(s); |
mutex_spin_exit(&timer_lock); |
return; |
return; |
} |
} |
splx(s); |
mutex_spin_exit(&timer_lock); |
pt->pt_overruns++; |
pt->pt_overruns++; |
|
mutex_spin_enter(&timer_lock); |
} |
} |
} |
} |
|
|
Line 950 sys_getitimer(struct lwp *l, const struc |
|
Line 979 sys_getitimer(struct lwp *l, const struc |
|
int |
int |
dogetitimer(struct proc *p, int which, struct itimerval *itvp) |
dogetitimer(struct proc *p, int which, struct itimerval *itvp) |
{ |
{ |
int s; |
struct ptimers *pts; |
|
struct ptimer *pt; |
|
|
if ((u_int)which > ITIMER_PROF) |
if ((u_int)which > ITIMER_PROF) |
return (EINVAL); |
return (EINVAL); |
|
|
if ((p->p_timers == NULL) || (p->p_timers->pts_timers[which] == NULL)){ |
mutex_spin_enter(&timer_lock); |
|
pts = p->p_timers; |
|
if (pts == NULL || (pt = pts->pts_timers[which]) == NULL) { |
timerclear(&itvp->it_value); |
timerclear(&itvp->it_value); |
timerclear(&itvp->it_interval); |
timerclear(&itvp->it_interval); |
} else { |
} else |
s = splclock(); |
timer_gettime(pt, itvp); |
timer_gettime(p->p_timers->pts_timers[which], itvp); |
mutex_spin_exit(&timer_lock); |
splx(s); |
|
} |
|
|
|
return 0; |
return 0; |
} |
} |
|
|
dosetitimer(struct proc *p, int which, struct itimerval *itvp) |
dosetitimer(struct proc *p, int which, struct itimerval *itvp) |
{ |
{ |
struct timeval now; |
struct timeval now; |
struct ptimer *pt; |
struct ptimers *pts; |
int s; |
struct ptimer *pt, *spare; |
|
|
if (itimerfix(&itvp->it_value) || itimerfix(&itvp->it_interval)) |
if (itimerfix(&itvp->it_value) || itimerfix(&itvp->it_interval)) |
return (EINVAL); |
return (EINVAL); |
Line 1017 dosetitimer(struct proc *p, int which, s |
|
Line 1047 dosetitimer(struct proc *p, int which, s |
|
* Don't bother allocating data structures if the process just |
* Don't bother allocating data structures if the process just |
* wants to clear the timer. |
* wants to clear the timer. |
*/ |
*/ |
if (!timerisset(&itvp->it_value) && |
spare = NULL; |
((p->p_timers == NULL) ||(p->p_timers->pts_timers[which] == NULL))) |
pts = p->p_timers; |
|
retry: |
|
if (!timerisset(&itvp->it_value) && (pts == NULL || |
|
pts->pts_timers[which] == NULL)) |
return (0); |
return (0); |
|
if (pts == NULL) |
if (p->p_timers == NULL) |
pts = timers_alloc(p); |
timers_alloc(p); |
mutex_spin_enter(&timer_lock); |
if (p->p_timers->pts_timers[which] == NULL) { |
pt = pts->pts_timers[which]; |
pt = pool_get(&ptimer_pool, PR_WAITOK); |
if (pt == NULL) { |
|
if (spare == NULL) { |
|
mutex_spin_exit(&timer_lock); |
|
spare = pool_get(&ptimer_pool, PR_WAITOK); |
|
goto retry; |
|
} |
|
pt = spare; |
|
spare = NULL; |
pt->pt_ev.sigev_notify = SIGEV_SIGNAL; |
pt->pt_ev.sigev_notify = SIGEV_SIGNAL; |
pt->pt_ev.sigev_value.sival_int = which; |
pt->pt_ev.sigev_value.sival_int = which; |
pt->pt_overruns = 0; |
pt->pt_overruns = 0; |
pt->pt_proc = p; |
pt->pt_proc = p; |
pt->pt_type = which; |
pt->pt_type = which; |
pt->pt_entry = which; |
pt->pt_entry = which; |
|
pt->pt_active = 0; |
|
pt->pt_queued = false; |
|
callout_init(&pt->pt_ch, CALLOUT_MPSAFE); |
switch (which) { |
switch (which) { |
case ITIMER_REAL: |
case ITIMER_REAL: |
callout_init(&pt->pt_ch, 0); |
|
pt->pt_ev.sigev_signo = SIGALRM; |
pt->pt_ev.sigev_signo = SIGALRM; |
break; |
break; |
case ITIMER_VIRTUAL: |
case ITIMER_VIRTUAL: |
pt->pt_active = 0; |
|
pt->pt_ev.sigev_signo = SIGVTALRM; |
pt->pt_ev.sigev_signo = SIGVTALRM; |
break; |
break; |
case ITIMER_PROF: |
case ITIMER_PROF: |
pt->pt_active = 0; |
|
pt->pt_ev.sigev_signo = SIGPROF; |
pt->pt_ev.sigev_signo = SIGPROF; |
break; |
break; |
} |
} |
} else |
pts->pts_timers[which] = pt; |
pt = p->p_timers->pts_timers[which]; |
} |
|
|
pt->pt_time = *itvp; |
pt->pt_time = *itvp; |
p->p_timers->pts_timers[which] = pt; |
|
|
|
s = splclock(); |
|
if ((which == ITIMER_REAL) && timerisset(&pt->pt_time.it_value)) { |
if ((which == ITIMER_REAL) && timerisset(&pt->pt_time.it_value)) { |
/* Convert to absolute time */ |
/* Convert to absolute time */ |
/* XXX need to wrap in splclock for timecounters case? */ |
/* XXX need to wrap in splclock for timecounters case? */ |
Line 1059 dosetitimer(struct proc *p, int which, s |
|
Line 1096 dosetitimer(struct proc *p, int which, s |
|
timeradd(&pt->pt_time.it_value, &now, &pt->pt_time.it_value); |
timeradd(&pt->pt_time.it_value, &now, &pt->pt_time.it_value); |
} |
} |
timer_settime(pt); |
timer_settime(pt); |
splx(s); |
mutex_spin_exit(&timer_lock); |
|
if (spare != NULL) |
|
pool_put(&ptimer_pool, spare); |
|
|
return (0); |
return (0); |
} |
} |
|
|
/* Utility routines to manage the array of pointers to timers. */ |
/* Utility routines to manage the array of pointers to timers. */ |
void |
struct ptimers * |
timers_alloc(struct proc *p) |
timers_alloc(struct proc *p) |
{ |
{ |
int i; |
|
struct ptimers *pts; |
struct ptimers *pts; |
|
int i; |
|
|
pts = pool_get(&ptimers_pool, PR_WAITOK); |
pts = pool_get(&ptimers_pool, PR_WAITOK); |
LIST_INIT(&pts->pts_virtual); |
LIST_INIT(&pts->pts_virtual); |
Line 1077 timers_alloc(struct proc *p) |
|
Line 1116 timers_alloc(struct proc *p) |
|
for (i = 0; i < TIMER_MAX; i++) |
for (i = 0; i < TIMER_MAX; i++) |
pts->pts_timers[i] = NULL; |
pts->pts_timers[i] = NULL; |
pts->pts_fired = 0; |
pts->pts_fired = 0; |
p->p_timers = pts; |
mutex_spin_enter(&timer_lock); |
|
if (p->p_timers == NULL) { |
|
p->p_timers = pts; |
|
mutex_spin_exit(&timer_lock); |
|
return pts; |
|
} |
|
mutex_spin_exit(&timer_lock); |
|
pool_put(&ptimers_pool, pts); |
|
return p->p_timers; |
} |
} |
|
|
/* |
/* |
Line 1090 timers_alloc(struct proc *p) |
|
Line 1137 timers_alloc(struct proc *p) |
|
void |
void |
timers_free(struct proc *p, int which) |
timers_free(struct proc *p, int which) |
{ |
{ |
int i, s; |
|
struct ptimers *pts; |
struct ptimers *pts; |
struct ptimer *pt, *ptn; |
struct ptimer *ptn; |
struct timeval tv; |
struct timeval tv; |
|
int i; |
|
|
if (p->p_timers) { |
if (p->p_timers == NULL) |
pts = p->p_timers; |
return; |
if (which == TIMERS_ALL) |
|
i = 0; |
|
else { |
|
s = splclock(); |
|
timerclear(&tv); |
|
for (ptn = LIST_FIRST(&p->p_timers->pts_virtual); |
|
ptn && ptn != pts->pts_timers[ITIMER_VIRTUAL]; |
|
ptn = LIST_NEXT(ptn, pt_list)) |
|
timeradd(&tv, &ptn->pt_time.it_value, &tv); |
|
LIST_FIRST(&p->p_timers->pts_virtual) = NULL; |
|
if (ptn) { |
|
timeradd(&tv, &ptn->pt_time.it_value, |
|
&ptn->pt_time.it_value); |
|
LIST_INSERT_HEAD(&p->p_timers->pts_virtual, |
|
ptn, pt_list); |
|
} |
|
|
|
timerclear(&tv); |
pts = p->p_timers; |
for (ptn = LIST_FIRST(&p->p_timers->pts_prof); |
mutex_spin_enter(&timer_lock); |
ptn && ptn != pts->pts_timers[ITIMER_PROF]; |
if (which == TIMERS_ALL) { |
ptn = LIST_NEXT(ptn, pt_list)) |
p->p_timers = NULL; |
timeradd(&tv, &ptn->pt_time.it_value, &tv); |
i = 0; |
LIST_FIRST(&p->p_timers->pts_prof) = NULL; |
} else { |
if (ptn) { |
timerclear(&tv); |
timeradd(&tv, &ptn->pt_time.it_value, |
for (ptn = LIST_FIRST(&pts->pts_virtual); |
&ptn->pt_time.it_value); |
ptn && ptn != pts->pts_timers[ITIMER_VIRTUAL]; |
LIST_INSERT_HEAD(&p->p_timers->pts_prof, ptn, |
ptn = LIST_NEXT(ptn, pt_list)) |
pt_list); |
timeradd(&tv, &ptn->pt_time.it_value, &tv); |
} |
LIST_FIRST(&pts->pts_virtual) = NULL; |
splx(s); |
if (ptn) { |
i = 3; |
timeradd(&tv, &ptn->pt_time.it_value, |
|
&ptn->pt_time.it_value); |
|
LIST_INSERT_HEAD(&pts->pts_virtual, ptn, pt_list); |
} |
} |
for ( ; i < TIMER_MAX; i++) |
timerclear(&tv); |
if ((pt = pts->pts_timers[i]) != NULL) { |
for (ptn = LIST_FIRST(&pts->pts_prof); |
if (pt->pt_type == CLOCK_REALTIME) { |
ptn && ptn != pts->pts_timers[ITIMER_PROF]; |
callout_stop(&pt->pt_ch); |
ptn = LIST_NEXT(ptn, pt_list)) |
callout_destroy(&pt->pt_ch); |
timeradd(&tv, &ptn->pt_time.it_value, &tv); |
} |
LIST_FIRST(&pts->pts_prof) = NULL; |
pts->pts_timers[i] = NULL; |
if (ptn) { |
pool_put(&ptimer_pool, pt); |
timeradd(&tv, &ptn->pt_time.it_value, |
} |
&ptn->pt_time.it_value); |
if ((pts->pts_timers[0] == NULL) && |
LIST_INSERT_HEAD(&pts->pts_prof, ptn, pt_list); |
(pts->pts_timers[1] == NULL) && |
|
(pts->pts_timers[2] == NULL)) { |
|
p->p_timers = NULL; |
|
pool_put(&ptimers_pool, pts); |
|
} |
} |
|
i = 3; |
} |
} |
|
for ( ; i < TIMER_MAX; i++) { |
|
if (pts->pts_timers[i] != NULL) { |
|
itimerfree(pts, i); |
|
mutex_spin_enter(&timer_lock); |
|
} |
|
} |
|
if (pts->pts_timers[0] == NULL && pts->pts_timers[1] == NULL && |
|
pts->pts_timers[2] == NULL) { |
|
p->p_timers = NULL; |
|
mutex_spin_exit(&timer_lock); |
|
pool_put(&ptimers_pool, pts); |
|
} else |
|
mutex_spin_exit(&timer_lock); |
|
} |
|
|
|
static void |
|
itimerfree(struct ptimers *pts, int index) |
|
{ |
|
struct ptimer *pt; |
|
|
|
KASSERT(mutex_owned(&timer_lock)); |
|
|
|
pt = pts->pts_timers[index]; |
|
pts->pts_timers[index] = NULL; |
|
if (pt->pt_type == CLOCK_REALTIME) |
|
callout_halt(&pt->pt_ch, &timer_lock); |
|
else if (pt->pt_queued) |
|
TAILQ_REMOVE(&timer_queue, pt, pt_chain); |
|
mutex_spin_exit(&timer_lock); |
|
callout_destroy(&pt->pt_ch); |
|
pool_put(&ptimer_pool, pt); |
} |
} |
|
|
/* |
/* |
Line 1157 timers_free(struct proc *p, int which) |
|
Line 1218 timers_free(struct proc *p, int which) |
|
* that it is called in a context where the timers |
* that it is called in a context where the timers |
* on which it is operating cannot change in value. |
* on which it is operating cannot change in value. |
*/ |
*/ |
int |
static int |
itimerdecr(struct ptimer *pt, int usec) |
itimerdecr(struct ptimer *pt, int usec) |
{ |
{ |
struct itimerval *itp; |
struct itimerval *itp; |
|
|
|
KASSERT(mutex_owned(&timer_lock)); |
|
|
itp = &pt->pt_time; |
itp = &pt->pt_time; |
if (itp->it_value.tv_usec < usec) { |
if (itp->it_value.tv_usec < usec) { |
if (itp->it_value.tv_sec == 0) { |
if (itp->it_value.tv_sec == 0) { |
|
|
return (0); |
return (0); |
} |
} |
|
|
void |
static void |
itimerfire(struct ptimer *pt) |
itimerfire(struct ptimer *pt) |
{ |
{ |
struct proc *p = pt->pt_proc; |
|
|
|
if (pt->pt_ev.sigev_notify == SIGEV_SIGNAL) { |
KASSERT(mutex_owned(&timer_lock)); |
|
|
|
/* |
|
* XXX Can overrun, but we don't do signal queueing yet, anyway. |
|
* XXX Relying on the clock interrupt is stupid. |
|
*/ |
|
if (pt->pt_ev.sigev_notify != SIGEV_SIGNAL || pt->pt_queued) |
|
return; |
|
TAILQ_INSERT_TAIL(&timer_queue, pt, pt_chain); |
|
pt->pt_queued = true; |
|
softint_schedule(timer_sih); |
|
} |
|
|
|
void |
|
timer_tick(lwp_t *l, bool user) |
|
{ |
|
struct ptimers *pts; |
|
struct ptimer *pt; |
|
proc_t *p; |
|
|
|
p = l->l_proc; |
|
if (p->p_timers == NULL) |
|
return; |
|
|
|
mutex_spin_enter(&timer_lock); |
|
if ((pts = l->l_proc->p_timers) != NULL) { |
/* |
/* |
* No RT signal infrastructure exists at this time; |
* Run current process's virtual and profile time, as needed. |
* just post the signal number and throw away the |
|
* value. |
|
*/ |
*/ |
if (sigismember(&p->p_sigpend.sp_set, pt->pt_ev.sigev_signo)) |
if (user && (pt = LIST_FIRST(&pts->pts_virtual)) != NULL) |
|
if (itimerdecr(pt, tick) == 0) |
|
itimerfire(pt); |
|
if ((pt = LIST_FIRST(&pts->pts_prof)) != NULL) |
|
if (itimerdecr(pt, tick) == 0) |
|
itimerfire(pt); |
|
} |
|
mutex_spin_exit(&timer_lock); |
|
} |
|
|
|
static void |
|
timer_intr(void *cookie) |
|
{ |
|
ksiginfo_t ksi; |
|
struct ptimer *pt; |
|
proc_t *p; |
|
|
|
mutex_spin_enter(&timer_lock); |
|
while ((pt = TAILQ_FIRST(&timer_queue)) != NULL) { |
|
TAILQ_REMOVE(&timer_queue, pt, pt_chain); |
|
KASSERT(pt->pt_queued); |
|
pt->pt_queued = false; |
|
|
|
if (pt->pt_ev.sigev_notify != SIGEV_SIGNAL) |
|
continue; |
|
p = pt->pt_proc; |
|
if (pt->pt_proc->p_timers == NULL) { |
|
/* Process is dying. */ |
|
continue; |
|
} |
|
if (sigismember(&p->p_sigpend.sp_set, pt->pt_ev.sigev_signo)) { |
pt->pt_overruns++; |
pt->pt_overruns++; |
else { |
continue; |
ksiginfo_t ksi; |
|
KSI_INIT(&ksi); |
|
ksi.ksi_signo = pt->pt_ev.sigev_signo; |
|
ksi.ksi_code = SI_TIMER; |
|
ksi.ksi_value = pt->pt_ev.sigev_value; |
|
pt->pt_poverruns = pt->pt_overruns; |
|
pt->pt_overruns = 0; |
|
mutex_enter(&proclist_mutex); |
|
kpsignal(p, &ksi, NULL); |
|
mutex_exit(&proclist_mutex); |
|
} |
} |
|
|
|
KSI_INIT(&ksi); |
|
ksi.ksi_signo = pt->pt_ev.sigev_signo; |
|
ksi.ksi_code = SI_TIMER; |
|
ksi.ksi_value = pt->pt_ev.sigev_value; |
|
pt->pt_poverruns = pt->pt_overruns; |
|
pt->pt_overruns = 0; |
|
mutex_spin_exit(&timer_lock); |
|
|
|
mutex_enter(proc_lock); |
|
kpsignal(p, &ksi, NULL); |
|
mutex_exit(proc_lock); |
|
|
|
mutex_spin_enter(&timer_lock); |
} |
} |
|
mutex_spin_exit(&timer_lock); |
} |
} |
|
|
/* |
/* |