Skip to content

Commit 28fdd65

Browse files
pcercueiQuzarDC
authored andcommitted
workqueue: Fix workqueue_cancel() not waiting for job to finish
Previously, workqueue_cancel() would remove the job from the work queue. However, when returning it gave absolutely no guarantee that the cancelled job was done processing. This is a problem, as if the job has been dynamically allocated, we have no indication about when it is safe to free it. Address this issue by waiting for the workqueue's thread to be done if trying to cancel the job that's currently being processed. Signed-off-by: Paul Cercueil <paul@crapouillou.net>
1 parent 0074f4d commit 28fdd65

1 file changed

Lines changed: 14 additions & 0 deletions

File tree

kernel/thread/workqueue.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
typedef struct workqueue {
1919
STAILQ_HEAD(workqueue_jobs, workqueue_job) jobs;
20+
workqueue_job_t *curr_job;
2021
kthread_t *thd;
2122
mutex_t lock;
2223
condvar_t cond;
@@ -32,6 +33,10 @@ static void *workqueue_thread(void *d) {
3233
while(!wq->quit) {
3334
mutex_lock(&wq->lock);
3435

36+
/* Signal that we're done with the previous job */
37+
wq->curr_job = NULL;
38+
cond_signal(&wq->cond);
39+
3540
job = STAILQ_FIRST(&wq->jobs);
3641
if(job)
3742
now = timer_ms_gettime64();
@@ -50,6 +55,7 @@ static void *workqueue_thread(void *d) {
5055
/* Remove the job from the queue */
5156
STAILQ_REMOVE(&wq->jobs, job, workqueue_job, entry);
5257

58+
wq->curr_job = job;
5359
mutex_unlock(&wq->lock);
5460

5561
job->cb(d, job);
@@ -112,6 +118,14 @@ void workqueue_cancel(workqueue_t *wq, workqueue_job_t *job) {
112118
mutex_lock_scoped(&wq->lock);
113119

114120
STAILQ_REMOVE(&wq->jobs, job, workqueue_job, entry);
121+
122+
if(wq->curr_job == job) {
123+
/* The job's callback is being executed. Wait until it's done. */
124+
cond_wait(&wq->cond, &wq->lock);
125+
}
126+
127+
/* We modified the queue, so notify the thread that it should parse the
128+
* list once again. */
115129
cond_signal(&wq->cond);
116130
}
117131

0 commit comments

Comments
 (0)