timeout_barrier(9), timeout_del_barrier(9): remove kernel lock
authorcheloha <cheloha@openbsd.org>
Tue, 11 May 2021 13:29:25 +0000 (13:29 +0000)
committercheloha <cheloha@openbsd.org>
Tue, 11 May 2021 13:29:25 +0000 (13:29 +0000)
In timeout_barrier(9) we take/release the kernel lock to ensure that the
given timeout has finished running (if it had been running at all).

This approach is inefficient.  If we put a barrier timeout on the
queue and wait for it to run in cond_wait(9) we can block instead of
spinning for the kernel lock.  We already do this for process-context
timeouts in timeout_barrier(9) anyway.

Discussed with dlg@, visa@, and mpi@.

ok dlg@

share/man/man9/timeout.9
sys/kern/kern_timeout.c

index 6706bed..b2836bd 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: timeout.9,v 1.52 2021/04/26 20:32:30 mvs Exp $
+.\"    $OpenBSD: timeout.9,v 1.53 2021/05/11 13:29:25 cheloha Exp $
 .\"
 .\" Copyright (c) 2000 Artur Grabowski <art@openbsd.org>
 .\" All rights reserved.
@@ -23,7 +23,7 @@
 .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: April 26 2021 $
+.Dd $Mdocdate: May 11 2021 $
 .Dt TIMEOUT_SET 9
 .Os
 .Sh NAME
@@ -194,11 +194,6 @@ but it will wait until any current execution of the timeout has completed.
 ensures that any current execution of the timeout in the argument
 .Fa to
 has completed before returning.
-If the timeout
-.Fa to
-has been initialised with
-.Fn timeout_set
-it will take the kernel lock.
 .Pp
 The
 .Fn timeout_pending
index acf752a..882560f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_timeout.c,v 1.83 2021/02/08 08:18:45 mpi Exp $   */
+/*     $OpenBSD: kern_timeout.c,v 1.84 2021/05/11 13:29:25 cheloha Exp $       */
 /*
  * Copyright (c) 2001 Thomas Nordin <nordin@openbsd.org>
  * Copyright (c) 2000-2001 Artur Grabowski <art@openbsd.org>
@@ -172,10 +172,10 @@ void softclock_create_thread(void *);
 void softclock_process_kclock_timeout(struct timeout *, int);
 void softclock_process_tick_timeout(struct timeout *, int);
 void softclock_thread(void *);
+void timeout_barrier_timeout(void *);
 uint32_t timeout_bucket(const struct timeout *);
 uint32_t timeout_maskwheel(uint32_t, const struct timespec *);
 void timeout_run(struct timeout *);
-void timeout_proc_barrier(void *);
 
 /*
  * The first thing in a struct timeout is its struct circq, so we
@@ -490,34 +490,38 @@ timeout_del_barrier(struct timeout *to)
 void
 timeout_barrier(struct timeout *to)
 {
-       int needsproc = ISSET(to->to_flags, TIMEOUT_PROC);
+       struct timeout barrier;
+       struct cond c;
+       int procflag;
 
-       timeout_sync_order(needsproc);
+       procflag = (to->to_flags & TIMEOUT_PROC);
+       timeout_sync_order(procflag);
 
-       if (!needsproc) {
-               KERNEL_LOCK();
-               splx(splsoftclock());
-               KERNEL_UNLOCK();
-       } else {
-               struct cond c = COND_INITIALIZER();
-               struct timeout barrier;
+       timeout_set_flags(&barrier, timeout_barrier_timeout, &c, procflag);
+       barrier.to_process = curproc->p_p;
+       cond_init(&c);
 
-               timeout_set_proc(&barrier, timeout_proc_barrier, &c);
-               barrier.to_process = curproc->p_p;
+       mtx_enter(&timeout_mutex);
 
-               mtx_enter(&timeout_mutex);
-               SET(barrier.to_flags, TIMEOUT_ONQUEUE);
+       barrier.to_time = ticks;
+       SET(barrier.to_flags, TIMEOUT_ONQUEUE);
+       if (procflag)
                CIRCQ_INSERT_TAIL(&timeout_proc, &barrier.to_list);
-               mtx_leave(&timeout_mutex);
+       else
+               CIRCQ_INSERT_TAIL(&timeout_todo, &barrier.to_list);
 
+       mtx_leave(&timeout_mutex);
+
+       if (procflag)
                wakeup_one(&timeout_proc);
+       else
+               softintr_schedule(softclock_si);
 
-               cond_wait(&c, "tmobar");
-       }
+       cond_wait(&c, "tmobar");
 }
 
 void
-timeout_proc_barrier(void *arg)
+timeout_barrier_timeout(void *arg)
 {
        struct cond *c = arg;