Reputation: 155
I was learning the workqueue mechanism of linux.
I meet this codes:
When user want to queue a work to a workqueue, they call __queue_work
, at the beginning of this function, it first check if the workqueue is at destroying or draining state by reading a flag
variable. But it doesn't use mutex_lock
to guard the read.
// linux-src-code/kernel/workqueue.c
static void __queue_work(int cpu, struct workqueue_struct *wq,
struct work_struct *work)
{
struct pool_workqueue *pwq;
struct worker_pool *last_pool, *pool;
unsigned int work_flags;
unsigned int req_cpu = cpu;
lockdep_assert_irqs_disabled();
if (unlikely(wq->flags & (__WQ_DESTROYING | __WQ_DRAINING) &&
WARN_ON_ONCE(!is_chained_work(wq))))
return;
...
}
But in the drain_workqueue
and destroy_workqueue
, they guard the flags
variable with mutex lock, this confuse me. I think there could be a race between reading and writing to the flags
:
// linux-src-code/kernel/workqueue.c
void drain_workqueue(struct workqueue_struct *wq)
{
unsigned int flush_cnt = 0;
struct pool_workqueue *pwq;
mutex_lock(&wq->mutex);
if (!wq->nr_drainers++)
wq->flags |= __WQ_DRAINING;
mutex_unlock(&wq->mutex);
reflush:
__flush_workqueue(wq);
...
}
My question is: why the read access of wq->flags
in queue_work
function is not guarded by mutex but the write access in destroy_workqueue
does.
Add this function for more information:
this means the mutex is not only protecting the combination of flags
and nr_drainers
, but also applies to single flags
variable.
void destroy_workqueue(struct workqueue_struct *wq)
{
struct pool_workqueue *pwq;
int cpu;
workqueue_sysfs_unregister(wq);
/* mark the workqueue destruction is in progress */
mutex_lock(&wq->mutex);
wq->flags |= __WQ_DESTROYING;
mutex_unlock(&wq->mutex);
}
Upvotes: 1
Views: 66