From f37b7fc2d40a3d953bc12aa81d2ce68945bc1742 Mon Sep 17 00:00:00 2001
From: Ian Lepore <ian@FreeBSD.org>
Date: Mon, 31 Jul 2017 00:54:50 +0000
Subject: [PATCH] Add taskqueue_enqueue_timeout_sbt(), because sometimes you
 want more control over the scheduling precision than 'ticks' can offer, and
 because sometimes you're already working with sbintime_t units and it's dumb
 to convert them to ticks just so they can get converted back to sbintime_t
 under the hood.

---
 share/man/man9/taskqueue.9 | 16 ++++++++++++++--
 sys/kern/subr_taskqueue.c  | 25 +++++++++++++++++--------
 sys/sys/taskqueue.h        |  3 +++
 3 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/share/man/man9/taskqueue.9 b/share/man/man9/taskqueue.9
index d06b0e1ec02b..2b04ba91f284 100644
--- a/share/man/man9/taskqueue.9
+++ b/share/man/man9/taskqueue.9
@@ -28,7 +28,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 1, 2016
+.Dd July 30, 2017
 .Dt TASKQUEUE 9
 .Os
 .Sh NAME
@@ -82,6 +82,8 @@ struct timeout_task;
 .Ft int
 .Fn taskqueue_enqueue_timeout "struct taskqueue *queue" "struct timeout_task *timeout_task" "int ticks"
 .Ft int
+.Fn taskqueue_enqueue_timeout_sbt "struct taskqueue *queue" "struct timeout_task *timeout_task" "sbintime_t sbt" "sbintime_t pr" "int flags"
+.Ft int
 .Fn taskqueue_cancel "struct taskqueue *queue" "struct task *task" "u_int *pendp"
 .Ft int
 .Fn taskqueue_cancel_timeout "struct taskqueue *queue" "struct timeout_task *timeout_task" "u_int *pendp"
@@ -211,8 +213,17 @@ is called on the task pointer passed to
 .Pp
 The
 .Fn taskqueue_enqueue_timeout
-is used to schedule the enqueue after the specified amount of
+function is used to schedule the enqueue after the specified number of
 .Va ticks .
+The
+.Fn taskqueue_enqueue_timeout_sbt
+function provides finer control over the scheduling based on
+.Va sbt ,
+.Va pr ,
+and
+.Va flags ,
+as detailed in
+.Xr timeout 9 .
 Only non-fast task queues can be used for
 .Va timeout_task
 scheduling.
@@ -483,6 +494,7 @@ be created with a dedicated processing thread.
 .Xr ithread 9 ,
 .Xr kthread 9 ,
 .Xr swi 9
+.Xr timeout 9
 .Sh HISTORY
 This interface first appeared in
 .Fx 5.0 .
diff --git a/sys/kern/subr_taskqueue.c b/sys/kern/subr_taskqueue.c
index 5d43ac6ca94c..0ec519df0d46 100644
--- a/sys/kern/subr_taskqueue.c
+++ b/sys/kern/subr_taskqueue.c
@@ -289,8 +289,8 @@ taskqueue_timeout_func(void *arg)
 }
 
 int
-taskqueue_enqueue_timeout(struct taskqueue *queue,
-    struct timeout_task *timeout_task, int ticks)
+taskqueue_enqueue_timeout_sbt(struct taskqueue *queue,
+    struct timeout_task *timeout_task, sbintime_t sbt, sbintime_t pr, int flags)
 {
 	int res;
 
@@ -304,7 +304,7 @@ taskqueue_enqueue_timeout(struct taskqueue *queue,
 		/* Do nothing */
 		TQ_UNLOCK(queue);
 		res = -1;
-	} else if (ticks == 0) {
+	} else if (sbt == 0) {
 		taskqueue_enqueue_locked(queue, &timeout_task->t);
 		/* The lock is released inside. */
 	} else {
@@ -313,18 +313,27 @@ taskqueue_enqueue_timeout(struct taskqueue *queue,
 		} else {
 			queue->tq_callouts++;
 			timeout_task->f |= DT_CALLOUT_ARMED;
-			if (ticks < 0)
-				ticks = -ticks; /* Ignore overflow. */
+			if (sbt < 0)
+				sbt = -sbt; /* Ignore overflow. */
 		}
-		if (ticks > 0) {
-			callout_reset(&timeout_task->c, ticks,
-			    taskqueue_timeout_func, timeout_task);
+		if (sbt > 0) {
+			callout_reset_sbt(&timeout_task->c, sbt, pr,
+			    taskqueue_timeout_func, timeout_task, flags);
 		}
 		TQ_UNLOCK(queue);
 	}
 	return (res);
 }
 
+int
+taskqueue_enqueue_timeout(struct taskqueue *queue,
+    struct timeout_task *ttask, int ticks)
+{
+
+	return (taskqueue_enqueue_timeout_sbt(queue, ttask, ticks * tick_sbt,
+	    0, 0));
+}
+
 static void
 taskqueue_task_nop_fn(void *context, int pending)
 {
diff --git a/sys/sys/taskqueue.h b/sys/sys/taskqueue.h
index 583f796e2ac1..7db75c6d0ee9 100644
--- a/sys/sys/taskqueue.h
+++ b/sys/sys/taskqueue.h
@@ -79,6 +79,9 @@ int	taskqueue_start_threads_cpuset(struct taskqueue **tqp, int count,
 int	taskqueue_enqueue(struct taskqueue *queue, struct task *task);
 int	taskqueue_enqueue_timeout(struct taskqueue *queue,
 	    struct timeout_task *timeout_task, int ticks);
+int	taskqueue_enqueue_timeout_sbt(struct taskqueue *queue,
+	    struct timeout_task *timeout_task, sbintime_t sbt, sbintime_t pr,
+	    int flags);
 int	taskqueue_poll_is_busy(struct taskqueue *queue, struct task *task);
 int	taskqueue_cancel(struct taskqueue *queue, struct task *task,
 	    u_int *pendp);