Split out kernel side of {get,set}itimer(2) into two parts: the first that

pops data from the userland and pushes results back and the second which does
actual processing. Use the latter to eliminate stackgap in the linux wrappers
of those syscalls.

MFC after:	2 weeks
This commit is contained in:
Maxim Sobolev 2005-01-25 21:28:28 +00:00
parent c80f5eee7f
commit cfa0efe7ab
3 changed files with 92 additions and 99 deletions

View File

@ -950,97 +950,66 @@ struct l_itimerval {
l_timeval it_value; l_timeval it_value;
}; };
#define B2L_ITIMERVAL(bip, lip) \
(bip)->it_interval.tv_sec = (lip)->it_interval.tv_sec; \
(bip)->it_interval.tv_usec = (lip)->it_interval.tv_usec; \
(bip)->it_value.tv_sec = (lip)->it_value.tv_sec; \
(bip)->it_value.tv_usec = (lip)->it_value.tv_usec;
int int
linux_setitimer(struct thread *td, struct linux_setitimer_args *uap) linux_setitimer(struct thread *td, struct linux_setitimer_args *uap)
{ {
int error; int error;
caddr_t sg; struct l_itimerval ls;
struct l_itimerval *lp, *lop, ls; struct itimerval aitv, oitv;
struct itimerval *p = NULL, *op = NULL, s;
#ifdef DEBUG #ifdef DEBUG
if (ldebug(setitimer)) if (ldebug(setitimer))
printf(ARGS(setitimer, "%p, %p"), printf(ARGS(setitimer, "%p, %p"),
(void *)uap->itv, (void *)uap->oitv); (void *)uap->itv, (void *)uap->oitv);
#endif #endif
lp = uap->itv;
if (lp != NULL) { if (uap->itv == NULL) {
sg = stackgap_init(); uap->itv = uap->oitv;
p = stackgap_alloc(&sg, sizeof(struct itimerval)); return (linux_getitimer(td, (struct linux_getitimer_args *)uap));
uap->itv = (struct l_itimerval *)p;
error = copyin(lp, &ls, sizeof(ls));
if (error != 0)
return (error);
s.it_interval.tv_sec = ls.it_interval.tv_sec;
s.it_interval.tv_usec = ls.it_interval.tv_usec;
s.it_value.tv_sec = ls.it_value.tv_sec;
s.it_value.tv_usec = ls.it_value.tv_usec;
error = copyout(&s, p, sizeof(s));
if (error != 0)
return (error);
#ifdef DEBUG
if (ldebug(setitimer)) {
printf("setitimer: value: sec: %ld, usec: %ld\n",
s.it_value.tv_sec, s.it_value.tv_usec);
printf("setitimer: interval: sec: %ld, usec: %ld\n",
s.it_interval.tv_sec, s.it_interval.tv_usec);
}
#endif
} }
lop = uap->oitv;
if (lop != NULL) { error = copyin(uap->itv, &ls, sizeof(ls));
sg = stackgap_init();
op = stackgap_alloc(&sg, sizeof(struct itimerval));
uap->oitv = (struct l_itimerval *)op;
}
error = setitimer(td, (struct setitimer_args *) uap);
if (error != 0) if (error != 0)
return (error); return (error);
if (lop != NULL) { B2L_ITIMERVAL(&aitv, &ls);
error = copyin(op, &s, sizeof(s)); #ifdef DEBUG
if (error != 0) if (ldebug(setitimer)) {
return (error); printf("setitimer: value: sec: %ld, usec: %ld\n",
ls.it_interval.tv_sec = s.it_interval.tv_sec; aitv.it_value.tv_sec, aitv.it_value.tv_usec);
ls.it_interval.tv_usec = s.it_interval.tv_usec; printf("setitimer: interval: sec: %ld, usec: %ld\n",
ls.it_value.tv_sec = s.it_value.tv_sec; aitv.it_interval.tv_sec, aitv.it_interval.tv_usec);
ls.it_value.tv_usec = s.it_value.tv_usec;
error = copyout(&ls, lop, sizeof(ls));
} }
return (error); #endif
error = kern_setitimer(td, uap->which, &aitv, &oitv);
if (error != 0 || uap->oitv == NULL)
return (error);
B2L_ITIMERVAL(&ls, &oitv);
return (copyout(&ls, uap->oitv, sizeof(ls)));
} }
int int
linux_getitimer(struct thread *td, struct linux_getitimer_args *uap) linux_getitimer(struct thread *td, struct linux_getitimer_args *uap)
{ {
int error; int error;
caddr_t sg; struct l_itimerval ls;
struct l_itimerval *lp, ls; struct itimerval aitv;
struct itimerval *p = NULL, s;
#ifdef DEBUG #ifdef DEBUG
if (ldebug(getitimer)) if (ldebug(getitimer))
printf(ARGS(getitimer, "%p"), (void *)uap->itv); printf(ARGS(getitimer, "%p"), (void *)uap->itv);
#endif #endif
lp = uap->itv; error = kern_getitimer(td, uap->which, &aitv);
if (lp != NULL) {
sg = stackgap_init();
p = stackgap_alloc(&sg, sizeof(struct itimerval));
uap->itv = (struct l_itimerval *)p;
}
error = getitimer(td, (struct getitimer_args *) uap);
if (error != 0) if (error != 0)
return (error); return (error);
if (lp != NULL) { B2L_ITIMERVAL(&ls, &aitv);
error = copyin(p, &s, sizeof(s)); return (copyout(&ls, uap->itv, sizeof(ls)));
if (error != 0)
return (error);
ls.it_interval.tv_sec = s.it_interval.tv_sec;
ls.it_interval.tv_usec = s.it_interval.tv_usec;
ls.it_value.tv_sec = s.it_value.tv_sec;
ls.it_value.tv_usec = s.it_value.tv_usec;
error = copyout(&ls, lp, sizeof(ls));
}
return (error);
} }
#ifndef __alpha__ #ifndef __alpha__

View File

@ -437,14 +437,25 @@ struct getitimer_args {
int int
getitimer(struct thread *td, struct getitimer_args *uap) getitimer(struct thread *td, struct getitimer_args *uap)
{ {
struct proc *p = td->td_proc; int error;
struct timeval ctv;
struct itimerval aitv; struct itimerval aitv;
if (uap->which > ITIMER_PROF) error = kern_getitimer(td, uap->which, &aitv);
if (error != 0)
return (error);
return (copyout(&aitv, uap->itv, sizeof (struct itimerval)));
}
int
kern_getitimer(struct thread *td, u_int which, struct itimerval *aitv)
{
struct proc *p = td->td_proc;
struct timeval ctv;
if (which > ITIMER_PROF)
return (EINVAL); return (EINVAL);
if (uap->which == ITIMER_REAL) { if (which == ITIMER_REAL) {
/* /*
* Convert from absolute to relative time in .it_value * Convert from absolute to relative time in .it_value
* part of real time timer. If time for real time timer * part of real time timer. If time for real time timer
@ -452,21 +463,21 @@ getitimer(struct thread *td, struct getitimer_args *uap)
* current time and time for the timer to go off. * current time and time for the timer to go off.
*/ */
PROC_LOCK(p); PROC_LOCK(p);
aitv = p->p_realtimer; *aitv = p->p_realtimer;
PROC_UNLOCK(p); PROC_UNLOCK(p);
if (timevalisset(&aitv.it_value)) { if (timevalisset(&aitv->it_value)) {
getmicrouptime(&ctv); getmicrouptime(&ctv);
if (timevalcmp(&aitv.it_value, &ctv, <)) if (timevalcmp(&aitv->it_value, &ctv, <))
timevalclear(&aitv.it_value); timevalclear(&aitv->it_value);
else else
timevalsub(&aitv.it_value, &ctv); timevalsub(&aitv->it_value, &ctv);
} }
} else { } else {
mtx_lock_spin(&sched_lock); mtx_lock_spin(&sched_lock);
aitv = p->p_stats->p_timer[uap->which]; *aitv = p->p_stats->p_timer[which];
mtx_unlock_spin(&sched_lock); mtx_unlock_spin(&sched_lock);
} }
return (copyout(&aitv, uap->itv, sizeof (struct itimerval))); return (0);
} }
#ifndef _SYS_SYSPROTO_H_ #ifndef _SYS_SYSPROTO_H_
@ -475,61 +486,71 @@ struct setitimer_args {
struct itimerval *itv, *oitv; struct itimerval *itv, *oitv;
}; };
#endif #endif
/* /*
* MPSAFE * MPSAFE
*/ */
int int
setitimer(struct thread *td, struct setitimer_args *uap) setitimer(struct thread *td, struct setitimer_args *uap)
{ {
struct proc *p = td->td_proc;
struct itimerval aitv, oitv;
struct timeval ctv;
int error; int error;
struct itimerval aitv, oitv;
if (uap->itv == NULL) { if (uap->itv == NULL) {
uap->itv = uap->oitv; uap->itv = uap->oitv;
return (getitimer(td, (struct getitimer_args *)uap)); return (getitimer(td, (struct getitimer_args *)uap));
} }
if (uap->which > ITIMER_PROF)
return (EINVAL);
if ((error = copyin(uap->itv, &aitv, sizeof(struct itimerval)))) if ((error = copyin(uap->itv, &aitv, sizeof(struct itimerval))))
return (error); return (error);
if (itimerfix(&aitv.it_value)) error = kern_setitimer(td, uap->which, &aitv, &oitv);
if (error != 0 || uap->oitv == NULL)
return (error);
return (copyout(&oitv, uap->oitv, sizeof(struct itimerval)));
}
int
kern_setitimer(struct thread *td, u_int which, struct itimerval *aitv, struct itimerval *oitv)
{
struct proc *p = td->td_proc;
struct timeval ctv;
if (which > ITIMER_PROF)
return (EINVAL); return (EINVAL);
if (!timevalisset(&aitv.it_value)) if (itimerfix(&aitv->it_value))
timevalclear(&aitv.it_interval); return (EINVAL);
else if (itimerfix(&aitv.it_interval)) if (!timevalisset(&aitv->it_value))
timevalclear(&aitv->it_interval);
else if (itimerfix(&aitv->it_interval))
return (EINVAL); return (EINVAL);
if (uap->which == ITIMER_REAL) { if (which == ITIMER_REAL) {
PROC_LOCK(p); PROC_LOCK(p);
if (timevalisset(&p->p_realtimer.it_value)) if (timevalisset(&p->p_realtimer.it_value))
callout_stop(&p->p_itcallout); callout_stop(&p->p_itcallout);
getmicrouptime(&ctv); getmicrouptime(&ctv);
if (timevalisset(&aitv.it_value)) { if (timevalisset(&aitv->it_value)) {
callout_reset(&p->p_itcallout, tvtohz(&aitv.it_value), callout_reset(&p->p_itcallout, tvtohz(&aitv->it_value),
realitexpire, p); realitexpire, p);
timevaladd(&aitv.it_value, &ctv); timevaladd(&aitv->it_value, &ctv);
} }
oitv = p->p_realtimer; *oitv = p->p_realtimer;
p->p_realtimer = aitv; p->p_realtimer = *aitv;
PROC_UNLOCK(p); PROC_UNLOCK(p);
if (timevalisset(&oitv.it_value)) { if (timevalisset(&oitv->it_value)) {
if (timevalcmp(&oitv.it_value, &ctv, <)) if (timevalcmp(&oitv->it_value, &ctv, <))
timevalclear(&oitv.it_value); timevalclear(&oitv->it_value);
else else
timevalsub(&oitv.it_value, &ctv); timevalsub(&oitv->it_value, &ctv);
} }
} else { } else {
mtx_lock_spin(&sched_lock); mtx_lock_spin(&sched_lock);
oitv = p->p_stats->p_timer[uap->which]; *oitv = p->p_stats->p_timer[which];
p->p_stats->p_timer[uap->which] = aitv; p->p_stats->p_timer[which] = *aitv;
mtx_unlock_spin(&sched_lock); mtx_unlock_spin(&sched_lock);
} }
if (uap->oitv == NULL) return (0);
return (0);
return (copyout(&oitv, uap->oitv, sizeof(struct itimerval)));
} }
/* /*

View File

@ -115,6 +115,7 @@ struct tty;
struct ucred; struct ucred;
struct uio; struct uio;
struct _jmp_buf; struct _jmp_buf;
struct itimerval;
int setjmp(struct _jmp_buf *); int setjmp(struct _jmp_buf *);
void longjmp(struct _jmp_buf *, int) __dead2; void longjmp(struct _jmp_buf *, int) __dead2;
@ -199,6 +200,8 @@ int suword32(void *base, int32_t word);
int suword64(void *base, int64_t word); int suword64(void *base, int64_t word);
intptr_t casuptr(intptr_t *p, intptr_t old, intptr_t new); intptr_t casuptr(intptr_t *p, intptr_t old, intptr_t new);
int kern_getitimer(struct thread *, u_int, struct itimerval *);
int kern_setitimer(struct thread *, u_int, struct itimerval *, struct itimerval *);
void realitexpire(void *); void realitexpire(void *);
void hardclock(struct clockframe *frame); void hardclock(struct clockframe *frame);