1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-20 11:11:24 +00:00

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)
This commit is contained in:
Zachary Loafman 2010-04-30 16:29:05 +00:00
parent e20e8c1558
commit 1dac222419
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=207439
3 changed files with 18 additions and 10 deletions

View File

@ -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, struct task *task)
{
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);
}

View File

@ -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_ */

View File

@ -75,6 +75,7 @@ void taskqueue_thread_enqueue(void *context);
(task)->ta_priority = (priority); \
(task)->ta_func = (func); \
(task)->ta_context = (context); \
(task)->ta_flags = 0; \
} while (0)
/*