diff options
author | Philip Guenthe <guenther@cvs.openbsd.org> | 2009-11-27 19:45:55 +0000 |
---|---|---|
committer | Philip Guenthe <guenther@cvs.openbsd.org> | 2009-11-27 19:45:55 +0000 |
commit | 1a35791f7ddc3e9de92e3c8c0e0f009aef9276d8 (patch) | |
tree | c9578afeaaa7eb6601fbc5a267fad565b61651d5 /sys | |
parent | e3f7d63389bbfad1413bfd08d7127f0af07be069 (diff) |
Convert thrsleep() to an absolute timeout with clockid to eliminate a
race condition and prep for later support of pthread_condattr_setclock()
"get it in" deraadt@, tedu@, cheers by others
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_synch.c | 50 | ||||
-rw-r--r-- | sys/kern/kern_time.c | 49 | ||||
-rw-r--r-- | sys/kern/syscalls.master | 5 | ||||
-rw-r--r-- | sys/sys/syscall.h | 4 | ||||
-rw-r--r-- | sys/sys/syscallargs.h | 4 | ||||
-rw-r--r-- | sys/sys/time.h | 6 |
6 files changed, 84 insertions, 34 deletions
diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index eb9d2f9dafa..565c4f35b95 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_synch.c,v 1.91 2009/06/04 04:26:54 beck Exp $ */ +/* $OpenBSD: kern_synch.c,v 1.92 2009/11/27 19:45:53 guenther Exp $ */ /* $NetBSD: kern_synch.c,v 1.37 1996/04/22 01:38:37 christos Exp $ */ /* @@ -407,24 +407,47 @@ sys_sched_yield(struct proc *p, void *v, register_t *retval) int sys_thrsleep(struct proc *p, void *v, register_t *revtal) { - struct sys_thrsleep_args *uap = v; + struct sys_thrsleep_args /* { + syscallarg(void *) ident; + syscallarg(clockid_t) clock_id; + syscallarg(struct timespec *) tp; + syscallarg(void *) lock; + } */ *uap = v; long ident = (long)SCARG(uap, ident); - int timo = SCARG(uap, timeout); _spinlock_lock_t *lock = SCARG(uap, lock); - _spinlock_lock_t unlocked = _SPINLOCK_UNLOCKED; + static _spinlock_lock_t unlocked = _SPINLOCK_UNLOCKED; + long long to_ticks = 0; int error; + if (SCARG(uap, tp) != NULL) { + struct timespec now, ats; + + if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0 || + (error = clock_gettime(p, SCARG(uap, clock_id), &now)) != 0) + return (error); + + if (timespeccmp(&ats, &now, <)) { + /* already passed: still do the unlock */ + if (lock) + copyout(&unlocked, lock, sizeof(unlocked)); + return (ETIMEDOUT); + } + + timespecsub(&ats, &now, &ats); + to_ticks = (long long)hz * ats.tv_sec + + ats.tv_nsec / (tick * 1000); + if (to_ticks > INT_MAX) + to_ticks = INT_MAX; + if (to_ticks == 0) + to_ticks = 1; + } + p->p_thrslpid = ident; if (lock) copyout(&unlocked, lock, sizeof(unlocked)); - if (hz > 1000) - timo = timo * (hz / 1000); - else - timo = timo / (1000 / hz); - if (timo < 0) - timo = 0; - error = tsleep(&p->p_thrslpid, PUSER | PCATCH, "thrsleep", timo); + error = tsleep(&p->p_thrslpid, PUSER | PCATCH, "thrsleep", + (int)to_ticks); if (error == ERESTART) error = EINTR; @@ -436,7 +459,10 @@ sys_thrsleep(struct proc *p, void *v, register_t *revtal) int sys_thrwakeup(struct proc *p, void *v, register_t *retval) { - struct sys_thrwakeup_args *uap = v; + struct sys_thrwakeup_args /* { + syscallarg(void *) ident; + syscallarg(int) n; + } */ *uap = v; long ident = (long)SCARG(uap, ident); int n = SCARG(uap, n); struct proc *q; diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 82a805cffd8..6cb2aa8a320 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_time.c,v 1.67 2009/10/16 19:29:41 martynas Exp $ */ +/* $OpenBSD: kern_time.c,v 1.68 2009/11/27 19:45:53 guenther Exp $ */ /* $NetBSD: kern_time.c,v 1.20 1996/02/18 11:57:06 fvdl Exp $ */ /* @@ -156,32 +156,39 @@ settime(struct timespec *ts) } #endif -/* ARGSUSED */ int -sys_clock_gettime(struct proc *p, void *v, register_t *retval) +clock_gettime(struct proc *p, clockid_t clock_id, struct timespec *tp) { - struct sys_clock_gettime_args /* { - syscallarg(clockid_t) clock_id; - syscallarg(struct timespec *) tp; - } */ *uap = v; - clockid_t clock_id; - struct timespec ats; - - clock_id = SCARG(uap, clock_id); switch (clock_id) { case CLOCK_REALTIME: - nanotime(&ats); + nanotime(tp); break; case CLOCK_MONOTONIC: - nanouptime(&ats); + nanouptime(tp); break; case CLOCK_PROF: - ats.tv_sec = p->p_rtime.tv_sec; - ats.tv_nsec = p->p_rtime.tv_usec * 1000; + tp->tv_sec = p->p_rtime.tv_sec; + tp->tv_nsec = p->p_rtime.tv_usec * 1000; break; default: return (EINVAL); } + return (0); +} + +/* ARGSUSED */ +int +sys_clock_gettime(struct proc *p, void *v, register_t *retval) +{ + struct sys_clock_gettime_args /* { + syscallarg(clockid_t) clock_id; + syscallarg(struct timespec *) tp; + } */ *uap = v; + struct timespec ats; + int error; + + if ((error = clock_gettime(p, SCARG(uap, clock_id), &ats)) != 0) + return (error); return copyout(&ats, SCARG(uap, tp), sizeof(ats)); } @@ -688,6 +695,18 @@ realitexpire(void *arg) } /* + * Check that a timespec value is legit + */ +int +timespecfix(struct timespec *ts) +{ + if (ts->tv_sec < 0 || ts->tv_sec > 100000000 || + ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000) + return (EINVAL); + return (0); +} + +/* * Check that a proposed value to load into the .it_value or * .it_interval part of an interval timer is acceptable. */ diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 7692a85edce..fba9aad506c 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -1,4 +1,4 @@ -; $OpenBSD: syscalls.master,v 1.95 2009/11/27 19:43:55 guenther Exp $ +; $OpenBSD: syscalls.master,v 1.96 2009/11/27 19:45:53 guenther Exp $ ; $NetBSD: syscalls.master,v 1.32 1996/04/23 10:24:21 mycroft Exp $ ; @(#)syscalls.master 8.2 (Berkeley) 1/13/94 @@ -597,7 +597,8 @@ 298 STD { int sys_sched_yield(void); } #ifdef RTHREADS 299 STD { pid_t sys_getthrid(void); } -300 STD { int sys_thrsleep(void *ident, int timeout, void *lock); } +300 STD { int sys_thrsleep(void *ident, clockid_t clock_id, \ + const struct timespec *tp, void *lock); } 301 STD { int sys_thrwakeup(void *ident, int n); } 302 STD { void sys_threxit(pid_t *notdead); } 303 STD { int sys_thrsigdivert(sigset_t sigmask, \ diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index 8dc92f61d30..2084589b4da 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall.h,v 1.107 2009/08/02 16:28:40 beck Exp $ */ +/* $OpenBSD: syscall.h,v 1.108 2009/11/27 19:45:53 guenther Exp $ */ /* * System call numbers. @@ -674,7 +674,7 @@ /* syscall: "thrwakeup" ret: "int" args: "void *" "int" */ #define SYS_thrwakeup 301 -/* syscall: "threxit" ret: "void" args: "int" */ +/* syscall: "threxit" ret: "void" args: "pid_t *" */ #define SYS_threxit 302 /* syscall: "thrsigdivert" ret: "int" args: "sigset_t" */ diff --git a/sys/sys/syscallargs.h b/sys/sys/syscallargs.h index ae8104b81b9..c5a252a01f6 100644 --- a/sys/sys/syscallargs.h +++ b/sys/sys/syscallargs.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscallargs.h,v 1.109 2009/08/02 16:28:40 beck Exp $ */ +/* $OpenBSD: syscallargs.h,v 1.110 2009/11/27 19:45:53 guenther Exp $ */ /* * System call argument lists. @@ -1221,7 +1221,7 @@ struct sys_thrwakeup_args { }; struct sys_threxit_args { - syscallarg(int) rval; + syscallarg(pid_t *) notdead; }; struct sys_thrsigdivert_args { diff --git a/sys/sys/time.h b/sys/sys/time.h index 2104de51506..85a3905c888 100644 --- a/sys/sys/time.h +++ b/sys/sys/time.h @@ -1,4 +1,4 @@ -/* $OpenBSD: time.h,v 1.25 2007/05/09 17:42:19 deraadt Exp $ */ +/* $OpenBSD: time.h,v 1.26 2009/11/27 19:45:54 guenther Exp $ */ /* $NetBSD: time.h,v 1.18 1996/04/23 10:29:33 mycroft Exp $ */ /* @@ -304,6 +304,10 @@ void microuptime(struct timeval *); void getnanouptime(struct timespec *); void getmicrouptime(struct timeval *); +struct proc; +int clock_gettime(struct proc *, clockid_t, struct timespec *); + +int timespecfix(struct timespec *); int itimerfix(struct timeval *); int itimerdecr(struct itimerval *itp, int usec); int settime(struct timespec *); |