X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=linux%2Fworkqueue.c;h=0d5af3fb89fcacf0fc670ba3b69764fd40bbd72e;hb=d01f633041c50452f9e837b7cc0223e6f37d42da;hp=4dfd6cd9e2099ad4db1d7c109f07fb0f91bb40af;hpb=ff86d4722124c300c40b85b6eb8ef2d410ab303c;p=bcachefs-tools-debian diff --git a/linux/workqueue.c b/linux/workqueue.c index 4dfd6cd..0d5af3f 100644 --- a/linux/workqueue.c +++ b/linux/workqueue.c @@ -5,6 +5,7 @@ #include static pthread_mutex_t wq_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t work_finished = PTHREAD_COND_INITIALIZER; static LIST_HEAD(wq_list); struct workqueue_struct { @@ -13,8 +14,6 @@ struct workqueue_struct { struct work_struct *current_work; struct list_head pending_work; - pthread_cond_t work_finished; - struct task_struct *worker; char name[24]; }; @@ -23,6 +22,11 @@ enum { WORK_PENDING_BIT, }; +static bool work_pending(struct work_struct *work) +{ + return test_bit(WORK_PENDING_BIT, work_data_bits(work)); +} + static void clear_work_pending(struct work_struct *work) { clear_bit(WORK_PENDING_BIT, work_data_bits(work)); @@ -36,7 +40,7 @@ static bool set_work_pending(struct work_struct *work) static void __queue_work(struct workqueue_struct *wq, struct work_struct *work) { - BUG_ON(!test_bit(WORK_PENDING_BIT, work_data_bits(work))); + BUG_ON(!work_pending(work)); BUG_ON(!list_empty(&work->entry)); list_add_tail(&work->entry, &wq->pending_work); @@ -130,17 +134,39 @@ retry: goto retry; } -static bool __flush_work(struct work_struct *work) +static bool work_running(struct work_struct *work) { struct workqueue_struct *wq; - bool ret = false; -retry: + list_for_each_entry(wq, &wq_list, list) - if (wq->current_work == work) { - pthread_cond_wait(&wq->work_finished, &wq_lock); - ret = true; - goto retry; - } + if (wq->current_work == work) + return true; + + return false; +} + +bool flush_work(struct work_struct *work) +{ + bool ret = false; + + pthread_mutex_lock(&wq_lock); + while (work_pending(work) || work_running(work)) { + pthread_cond_wait(&work_finished, &wq_lock); + ret = true; + } + pthread_mutex_unlock(&wq_lock); + + return ret; +} + +static bool __flush_work(struct work_struct *work) +{ + bool ret = false; + + while (work_running(work)) { + pthread_cond_wait(&work_finished, &wq_lock); + ret = true; + } return ret; } @@ -228,7 +254,7 @@ static int worker_thread(void *arg) continue; } - BUG_ON(!test_bit(WORK_PENDING_BIT, work_data_bits(work))); + BUG_ON(!work_pending(work)); list_del_init(&work->entry); clear_work_pending(work); @@ -236,7 +262,7 @@ static int worker_thread(void *arg) work->func(work); pthread_mutex_lock(&wq_lock); - pthread_cond_broadcast(&wq->work_finished); + pthread_cond_broadcast(&work_finished); } pthread_mutex_unlock(&wq_lock); @@ -269,8 +295,6 @@ struct workqueue_struct *alloc_workqueue(const char *fmt, INIT_LIST_HEAD(&wq->list); INIT_LIST_HEAD(&wq->pending_work); - pthread_cond_init(&wq->work_finished, NULL); - va_start(args, max_active); vsnprintf(wq->name, sizeof(wq->name), fmt, args); va_end(args); @@ -307,3 +331,16 @@ static void wq_init(void) BUG_ON(!system_wq || !system_highpri_wq || !system_long_wq || !system_unbound_wq || !system_freezable_wq); } + +__attribute__((destructor(102))) +static void wq_cleanup(void) +{ + destroy_workqueue(system_freezable_wq); + destroy_workqueue(system_unbound_wq); + destroy_workqueue(system_long_wq); + destroy_workqueue(system_highpri_wq); + destroy_workqueue(system_wq); + + system_wq = system_highpri_wq = system_long_wq = system_unbound_wq = + system_freezable_wq = NULL; +}