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:
parent
e20e8c1558
commit
1dac222419
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=207439
@ -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);
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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)
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user