summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorPhilip Guenthe <guenther@cvs.openbsd.org>2009-11-27 19:45:55 +0000
committerPhilip Guenthe <guenther@cvs.openbsd.org>2009-11-27 19:45:55 +0000
commit1a35791f7ddc3e9de92e3c8c0e0f009aef9276d8 (patch)
treec9578afeaaa7eb6601fbc5a267fad565b61651d5 /sys
parente3f7d63389bbfad1413bfd08d7127f0af07be069 (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.c50
-rw-r--r--sys/kern/kern_time.c49
-rw-r--r--sys/kern/syscalls.master5
-rw-r--r--sys/sys/syscall.h4
-rw-r--r--sys/sys/syscallargs.h4
-rw-r--r--sys/sys/time.h6
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 *);