summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormpi <mpi@openbsd.org>2016-09-22 12:55:24 +0000
committermpi <mpi@openbsd.org>2016-09-22 12:55:24 +0000
commitdd41d61928386cd56a5d680f436dda4efd9154e0 (patch)
tree0825b0a015b5a2dba83e0c57be0d7366d804a5dc
parentPeriodically call mii_tick() like all our other ethernet drivers that use (diff)
downloadwireguard-openbsd-dd41d61928386cd56a5d680f436dda4efd9154e0.tar.xz
wireguard-openbsd-dd41d61928386cd56a5d680f436dda4efd9154e0.zip
Introduce a new 'softclock' thread that will be used to execute timeout
callbacks needing a process context. The function timeout_set_proc(9) has to be used instead of timeout_set(9) when a timeout callback needs a process context. Note that if such a timeout is waiting, understand sleeping, for a non negligible amount of time it might delay other timeouts needing a process context. dlg@ agrees with this as a temporary solution. Manpage tweaks from jmc@ ok kettenis@, bluhm@, mikeb@
-rw-r--r--share/man/man9/timeout.924
-rw-r--r--sys/kern/init_main.c6
-rw-r--r--sys/kern/kern_timeout.c93
-rw-r--r--sys/sys/timeout.h4
4 files changed, 108 insertions, 19 deletions
diff --git a/share/man/man9/timeout.9 b/share/man/man9/timeout.9
index 8701c920a2c..ec0c96d086f 100644
--- a/share/man/man9/timeout.9
+++ b/share/man/man9/timeout.9
@@ -1,4 +1,4 @@
-.\" $OpenBSD: timeout.9,v 1.43 2016/06/14 15:58:03 bluhm Exp $
+.\" $OpenBSD: timeout.9,v 1.44 2016/09/22 12:55:24 mpi Exp $
.\"
.\" Copyright (c) 2000 Artur Grabowski <art@openbsd.org>
.\" All rights reserved.
@@ -23,11 +23,12 @@
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd $Mdocdate: June 14 2016 $
+.Dd $Mdocdate: September 22 2016 $
.Dt TIMEOUT_SET 9
.Os
.Sh NAME
.Nm timeout_set ,
+.Nm timeout_set_proc ,
.Nm timeout_add ,
.Nm timeout_add_sec ,
.Nm timeout_add_msec ,
@@ -47,6 +48,8 @@
.In sys/timeout.h
.Ft void
.Fn timeout_set "struct timeout *to" "void (*fn)(void *)" "void *arg"
+.Ft void
+.Fn timeout_set_proc "struct timeout *to" "void (*fn)(void *)" "void *arg"
.Ft int
.Fn timeout_add "struct timeout *to" "int ticks"
.Ft int
@@ -85,9 +88,11 @@ times a second.
It is the responsibility of the caller to provide these functions with
pre-allocated timeout structures.
.Pp
-The function
+The functions
.Fn timeout_set
-prepares the timeout structure
+and
+.Fn timeout_set_proc
+prepare the timeout structure
.Fa to
to be used in future calls to
.Fn timeout_add
@@ -128,8 +133,12 @@ The timeout in the
.Fa to
argument must be already initialized by
.Fn timeout_set
+or
+.Fn timeout_set_proc
and may not be used in calls to
.Fn timeout_set
+or
+.Fn timeout_set_proc
until it has timed out or been removed with
.Fn timeout_del .
If the timeout in the
@@ -188,6 +197,8 @@ argument given in
.Fa arg .
.Sh CONTEXT
.Fn timeout_set
+and
+.Fn timeout_set_proc
can be called during autoconf, from process context, or from interrupt
context.
.Pp
@@ -211,8 +222,11 @@ When the timeout runs, the
.Fa fn
argument to
.Fn timeout_set
+or
+.Fn timeout_set_proc
will be called in an interrupt context at
-.Dv IPL_SOFTCLOCK .
+.Dv IPL_SOFTCLOCK
+or a process context, respectively.
.Sh RETURN VALUES
.Fn timeout_add ,
.Fn timeout_add_sec ,
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index f64a945a97c..f781069a92e 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: init_main.c,v 1.258 2016/09/18 12:36:28 jasper Exp $ */
+/* $OpenBSD: init_main.c,v 1.259 2016/09/22 12:55:24 mpi Exp $ */
/* $NetBSD: init_main.c,v 1.84.4.1 1996/06/02 09:08:06 mrg Exp $ */
/*
@@ -144,6 +144,7 @@ void prof_init(void);
void init_exec(void);
void kqueue_init(void);
void taskq_init(void);
+void timeout_proc_init(void);
void pool_gc_pages(void *);
extern char sigcode[], esigcode[], sigcoderet[];
@@ -336,6 +337,9 @@ main(void *framep)
sched_init_cpu(curcpu());
p->p_cpu->ci_randseed = (arc4random() & 0x7fffffff) + 1;
+ /* Initialize timeouts in process context. */
+ timeout_proc_init();
+
/* Initialize task queues */
taskq_init();
diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c
index b4ec8cdb4b2..6c6477e00a9 100644
--- a/sys/kern/kern_timeout.c
+++ b/sys/kern/kern_timeout.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_timeout.c,v 1.48 2016/07/06 15:53:01 tedu Exp $ */
+/* $OpenBSD: kern_timeout.c,v 1.49 2016/09/22 12:55:24 mpi Exp $ */
/*
* Copyright (c) 2001 Thomas Nordin <nordin@openbsd.org>
* Copyright (c) 2000-2001 Artur Grabowski <art@openbsd.org>
@@ -27,7 +27,7 @@
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/lock.h>
+#include <sys/kthread.h>
#include <sys/timeout.h>
#include <sys/mutex.h>
#include <sys/kernel.h>
@@ -54,6 +54,7 @@
struct circq timeout_wheel[BUCKETS]; /* Queues of timeouts */
struct circq timeout_todo; /* Worklist */
+struct circq timeout_proc; /* Due timeouts needing proc. context */
#define MASKWHEEL(wheel, time) (((time) >> ((wheel)*WHEELBITS)) & WHEELMASK)
@@ -127,6 +128,9 @@ struct mutex timeout_mutex = MUTEX_INITIALIZER(IPL_HIGH);
#define CIRCQ_EMPTY(elem) (CIRCQ_FIRST(elem) == (elem))
+void softclock_thread(void *);
+void softclock_create_thread(void *);
+
/*
* Some of the "math" in here is a bit tricky.
*
@@ -147,11 +151,18 @@ timeout_startup(void)
int b;
CIRCQ_INIT(&timeout_todo);
+ CIRCQ_INIT(&timeout_proc);
for (b = 0; b < nitems(timeout_wheel); b++)
CIRCQ_INIT(&timeout_wheel[b]);
}
void
+timeout_proc_init(void)
+{
+ kthread_create_deferred(softclock_create_thread, NULL);
+}
+
+void
timeout_set(struct timeout *new, void (*fn)(void *), void *arg)
{
new->to_func = fn;
@@ -159,6 +170,12 @@ timeout_set(struct timeout *new, void (*fn)(void *), void *arg)
new->to_flags = TIMEOUT_INITIALIZED;
}
+void
+timeout_set_proc(struct timeout *new, void (*fn)(void *), void *arg)
+{
+ timeout_set(new, fn, arg);
+ new->to_flags |= TIMEOUT_NEEDPROCCTX;
+}
int
timeout_add(struct timeout *new, int to_ticks)
@@ -334,38 +351,90 @@ timeout_hardclock_update(void)
}
void
+timeout_run(struct timeout *to)
+{
+ void (*fn)(void *);
+ void *arg;
+
+ MUTEX_ASSERT_LOCKED(&timeout_mutex);
+
+ to->to_flags &= ~TIMEOUT_ONQUEUE;
+ to->to_flags |= TIMEOUT_TRIGGERED;
+
+ fn = to->to_func;
+ arg = to->to_arg;
+
+ mtx_leave(&timeout_mutex);
+ fn(arg);
+ mtx_enter(&timeout_mutex);
+}
+
+void
softclock(void *arg)
{
int delta;
struct circq *bucket;
struct timeout *to;
- void (*fn)(void *);
mtx_enter(&timeout_mutex);
while (!CIRCQ_EMPTY(&timeout_todo)) {
to = timeout_from_circq(CIRCQ_FIRST(&timeout_todo));
CIRCQ_REMOVE(&to->to_list);
- /* If due run it, otherwise insert it into the right bucket. */
+ /*
+ * If due run it or defer execution to the thread,
+ * otherwise insert it into the right bucket.
+ */
delta = to->to_time - ticks;
if (delta > 0) {
bucket = &BUCKET(delta, to->to_time);
CIRCQ_INSERT(&to->to_list, bucket);
+ } else if (to->to_flags & TIMEOUT_NEEDPROCCTX) {
+ CIRCQ_INSERT(&to->to_list, &timeout_proc);
+ wakeup(&timeout_proc);
} else {
#ifdef DEBUG
if (delta < 0)
printf("timeout delayed %d\n", delta);
#endif
- to->to_flags &= ~TIMEOUT_ONQUEUE;
- to->to_flags |= TIMEOUT_TRIGGERED;
+ timeout_run(to);
+ }
+ }
+ mtx_leave(&timeout_mutex);
+}
- fn = to->to_func;
- arg = to->to_arg;
+void
+softclock_create_thread(void *arg)
+{
+ if (kthread_create(softclock_thread, NULL, NULL, "softclock"))
+ panic("fork softclock");
+}
- mtx_leave(&timeout_mutex);
- fn(arg);
- mtx_enter(&timeout_mutex);
- }
+void
+softclock_thread(void *arg)
+{
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+ struct timeout *to;
+
+ KERNEL_ASSERT_LOCKED();
+
+ /* Be conservative for the moment */
+ CPU_INFO_FOREACH(cii, ci) {
+ if (CPU_IS_PRIMARY(ci))
+ break;
+ }
+ KASSERT(ci != NULL);
+ sched_peg_curproc(ci);
+
+ mtx_enter(&timeout_mutex);
+ for (;;) {
+ while (CIRCQ_EMPTY(&timeout_proc))
+ msleep(&timeout_proc, &timeout_mutex, PSWP, "bored", 0);
+
+ to = timeout_from_circq(CIRCQ_FIRST(&timeout_proc));
+ CIRCQ_REMOVE(&to->to_list);
+ timeout_run(to);
}
mtx_leave(&timeout_mutex);
}
diff --git a/sys/sys/timeout.h b/sys/sys/timeout.h
index 8f25af17e81..a00c62058a1 100644
--- a/sys/sys/timeout.h
+++ b/sys/sys/timeout.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: timeout.h,v 1.25 2014/12/22 04:43:38 dlg Exp $ */
+/* $OpenBSD: timeout.h,v 1.26 2016/09/22 12:55:24 mpi Exp $ */
/*
* Copyright (c) 2000-2001 Artur Grabowski <art@openbsd.org>
* All rights reserved.
@@ -67,6 +67,7 @@ struct timeout {
/*
* flags in the to_flags field.
*/
+#define TIMEOUT_NEEDPROCCTX 1 /* timeout needs a process context */
#define TIMEOUT_ONQUEUE 2 /* timeout is on the todo queue */
#define TIMEOUT_INITIALIZED 4 /* timeout is initialized */
#define TIMEOUT_TRIGGERED 8 /* timeout is running or ran */
@@ -88,6 +89,7 @@ struct timeout {
struct bintime;
void timeout_set(struct timeout *, void (*)(void *), void *);
+void timeout_set_proc(struct timeout *, void (*)(void *), void *);
int timeout_add(struct timeout *, int);
int timeout_add_tv(struct timeout *, const struct timeval *);
int timeout_add_ts(struct timeout *, const struct timespec *);