Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 30 Apr 2010 16:29:05 +0000 (UTC)
From:      Zachary Loafman <zml@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r207439 - in head/sys: kern sys
Message-ID:  <201004301629.o3UGT5ln018762@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: zml
Date: Fri Apr 30 16:29:05 2010
New Revision: 207439
URL: http://svn.freebsd.org/changeset/base/207439

Log:
  Handle taskqueue_drain(9) correctly on a threaded taskqueue:
  
  taskqueue_drain(9) will not correctly detect whether a task is
  currently running.  The check is against a field in the taskqueue
  struct, but for a threaded queue with more than one thread, multiple
  threads can simultaneously be running a task, thus stomping over the
  tq_running field.
  
  Submitted by:       Matthew Fleming <matthew.fleming@isilon.com>
  Reviewed by:        jhb
  Approved by:        dfr (mentor)

Modified:
  head/sys/kern/subr_taskqueue.c
  head/sys/sys/_task.h
  head/sys/sys/taskqueue.h

Modified: head/sys/kern/subr_taskqueue.c
==============================================================================
--- head/sys/kern/subr_taskqueue.c	Fri Apr 30 16:20:14 2010	(r207438)
+++ head/sys/kern/subr_taskqueue.c	Fri Apr 30 16:29:05 2010	(r207439)
@@ -51,7 +51,6 @@ struct taskqueue {
 	const char		*tq_name;
 	taskqueue_enqueue_fn	tq_enqueue;
 	void			*tq_context;
-	struct task		*tq_running;
 	struct mtx		tq_mutex;
 	struct thread		**tq_threads;
 	int			tq_tcount;
@@ -233,13 +232,13 @@ taskqueue_run(struct taskqueue *queue)
 		STAILQ_REMOVE_HEAD(&queue->tq_queue, ta_link);
 		pending = task->ta_pending;
 		task->ta_pending = 0;
-		queue->tq_running = task;
+		task->ta_flags |= TA_FLAGS_RUNNING;
 		TQ_UNLOCK(queue);
 
 		task->ta_func(task->ta_context, pending);
 
 		TQ_LOCK(queue);
-		queue->tq_running = NULL;
+		task->ta_flags &= ~TA_FLAGS_RUNNING;
 		wakeup(task);
 	}
 
@@ -256,14 +255,16 @@ taskqueue_drain(struct taskqueue *queue,
 {
 	if (queue->tq_spin) {		/* XXX */
 		mtx_lock_spin(&queue->tq_mutex);
-		while (task->ta_pending != 0 || task == queue->tq_running)
+		while (task->ta_pending != 0 ||
+		    (task->ta_flags & TA_FLAGS_RUNNING) != 0)
 			msleep_spin(task, &queue->tq_mutex, "-", 0);
 		mtx_unlock_spin(&queue->tq_mutex);
 	} else {
 		WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__);
 
 		mtx_lock(&queue->tq_mutex);
-		while (task->ta_pending != 0 || task == queue->tq_running)
+		while (task->ta_pending != 0 ||
+		    (task->ta_flags & TA_FLAGS_RUNNING) != 0)
 			msleep(task, &queue->tq_mutex, PWAIT, "-", 0);
 		mtx_unlock(&queue->tq_mutex);
 	}

Modified: head/sys/sys/_task.h
==============================================================================
--- head/sys/sys/_task.h	Fri Apr 30 16:20:14 2010	(r207438)
+++ head/sys/sys/_task.h	Fri Apr 30 16:29:05 2010	(r207439)
@@ -36,15 +36,21 @@
  * taskqueue_run().  The first argument is taken from the 'ta_context'
  * field of struct task and the second argument is a count of how many
  * times the task was enqueued before the call to taskqueue_run().
+ *
+ * List of locks
+ * (c)	const after init
+ * (q)	taskqueue lock
  */
 typedef void task_fn_t(void *context, int pending);
 
 struct task {
-	STAILQ_ENTRY(task) ta_link;	/* link for queue */
-	u_short	ta_pending;		/* count times queued */
-	u_short	ta_priority;		/* Priority */
-	task_fn_t *ta_func;		/* task handler */
-	void	*ta_context;		/* argument for handler */
+	STAILQ_ENTRY(task) ta_link;	/* (q) link for queue */
+	u_int	ta_flags;		/* (q) state of this task */
+#define	TA_FLAGS_RUNNING	0x01
+	u_short	ta_pending;		/* (q) count times queued */
+	u_short	ta_priority;		/* (c) Priority */
+	task_fn_t *ta_func;		/* (c) task handler */
+	void	*ta_context;		/* (c) argument for handler */
 };
 
 #endif /* !_SYS__TASK_H_ */

Modified: head/sys/sys/taskqueue.h
==============================================================================
--- head/sys/sys/taskqueue.h	Fri Apr 30 16:20:14 2010	(r207438)
+++ head/sys/sys/taskqueue.h	Fri Apr 30 16:29:05 2010	(r207439)
@@ -75,6 +75,7 @@ void	taskqueue_thread_enqueue(void *cont
 	(task)->ta_priority = (priority);		\
 	(task)->ta_func = (func);			\
 	(task)->ta_context = (context);			\
+	(task)->ta_flags = 0;				\
 } while (0)
 
 /*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201004301629.o3UGT5ln018762>