svn commit: r306948 - in stable/9: share/man/man9 sys/kern

Hans Petter Selasky hselasky at FreeBSD.org
Mon Oct 10 11:28:00 UTC 2016


Author: hselasky
Date: Mon Oct 10 11:27:59 2016
New Revision: 306948
URL: https://svnweb.freebsd.org/changeset/base/306948

Log:
  MFC r306441 and r306634:
  While draining a timeout task prevent the taskqueue_enqueue_timeout()
  function from restarting the timer.
  
  Commonly taskqueue_enqueue_timeout() is called from within the task
  function itself without any checks for teardown. Then it can happen
  the timer stays active after the return of taskqueue_drain_timeout(),
  because the timeout and task is drained separately.
  
  This patch factors out the teardown flag into the timeout task itself,
  allowing existing code to stay as-is instead of applying a teardown
  flag to each and every of the timeout task consumers.
  
  Add assert to taskqueue_drain_timeout() which prevents parallel
  execution on the same timeout task.
  
  Update manual page documenting the return value of
  taskqueue_enqueue_timeout().
  
  Differential Revision:	https://reviews.freebsd.org/D8012
  Reviewed by:	kib, trasz

Modified:
  stable/9/share/man/man9/taskqueue.9
  stable/9/sys/kern/subr_taskqueue.c
Directory Properties:
  stable/9/share/   (props changed)
  stable/9/share/man/   (props changed)
  stable/9/share/man/man9/   (props changed)
  stable/9/sys/   (props changed)

Modified: stable/9/share/man/man9/taskqueue.9
==============================================================================
--- stable/9/share/man/man9/taskqueue.9	Mon Oct 10 11:25:11 2016	(r306947)
+++ stable/9/share/man/man9/taskqueue.9	Mon Oct 10 11:27:59 2016	(r306948)
@@ -193,6 +193,8 @@ Otherwise, the task is scheduled for enq
 after the absolute value of
 .Va ticks
 is passed.
+This function returns -1 if the task is being drained.
+Otherwise, the number of pending calls is returned.
 .Pp
 The
 .Fn taskqueue_cancel

Modified: stable/9/sys/kern/subr_taskqueue.c
==============================================================================
--- stable/9/sys/kern/subr_taskqueue.c	Mon Oct 10 11:25:11 2016	(r306947)
+++ stable/9/sys/kern/subr_taskqueue.c	Mon Oct 10 11:27:59 2016	(r306948)
@@ -70,6 +70,7 @@ struct taskqueue {
 #define	TQ_FLAGS_PENDING	(1 << 2)
 
 #define	DT_CALLOUT_ARMED	(1 << 0)
+#define	DT_DRAIN_IN_PROGRESS	(1 << 1)
 
 #define	TQ_LOCK(tq)							\
 	do {								\
@@ -244,7 +245,11 @@ taskqueue_enqueue_timeout(struct taskque
 	KASSERT(!queue->tq_spin, ("Timeout for spin-queue"));
 	timeout_task->q = queue;
 	res = timeout_task->t.ta_pending;
-	if (ticks == 0) {
+	if (timeout_task->f & DT_DRAIN_IN_PROGRESS) {
+		/* Do nothing */
+		TQ_UNLOCK(queue);
+		res = -1;
+	} else if (ticks == 0) {
 		taskqueue_enqueue_locked(queue, &timeout_task->t);
 	} else {
 		if ((timeout_task->f & DT_CALLOUT_ARMED) != 0) {
@@ -434,8 +439,24 @@ taskqueue_drain_timeout(struct taskqueue
     struct timeout_task *timeout_task)
 {
 
+	/*
+	 * Set flag to prevent timer from re-starting during drain:
+	 */
+	TQ_LOCK(queue);
+	KASSERT((timeout_task->f & DT_DRAIN_IN_PROGRESS) == 0,
+	    ("Drain already in progress"));
+	timeout_task->f |= DT_DRAIN_IN_PROGRESS;
+	TQ_UNLOCK(queue);
+
 	callout_drain(&timeout_task->c);
 	taskqueue_drain(queue, &timeout_task->t);
+
+	/*
+	 * Clear flag to allow timer to re-start:
+	 */
+	TQ_LOCK(queue);
+	timeout_task->f &= ~DT_DRAIN_IN_PROGRESS;
+	TQ_UNLOCK(queue);
 }
 
 static void


More information about the svn-src-stable-9 mailing list