]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - linux/workqueue.c
Disable pristine-tar option in gbp.conf, since there is no pristine-tar branch.
[bcachefs-tools-debian] / linux / workqueue.c
index f5942772dda67adf02723b2dd6620ec868c3a0b3..0d5af3fb89fcacf0fc670ba3b69764fd40bbd72e 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/workqueue.h>
 
 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);
@@ -55,9 +59,10 @@ bool queue_work(struct workqueue_struct *wq, struct work_struct *work)
        return ret;
 }
 
-void delayed_work_timer_fn(unsigned long __data)
+void delayed_work_timer_fn(struct timer_list *timer)
 {
-       struct delayed_work *dwork = (struct delayed_work *) __data;
+       struct delayed_work *dwork =
+               container_of(timer, struct delayed_work, timer);
 
        pthread_mutex_lock(&wq_lock);
        __queue_work(dwork->wq, &dwork->work);
@@ -71,8 +76,7 @@ static void __queue_delayed_work(struct workqueue_struct *wq,
        struct timer_list *timer = &dwork->timer;
        struct work_struct *work = &dwork->work;
 
-       BUG_ON(timer->function != delayed_work_timer_fn ||
-              timer->data != (unsigned long)dwork);
+       BUG_ON(timer->function != delayed_work_timer_fn);
        BUG_ON(timer_pending(timer));
        BUG_ON(!list_empty(&work->entry));
 
@@ -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;
+}