#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 {
struct work_struct *current_work;
struct list_head pending_work;
- pthread_cond_t work_finished;
-
struct task_struct *worker;
char name[24];
};
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));
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);
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);
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));
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;
}
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);
work->func(work);
pthread_mutex_lock(&wq_lock);
- pthread_cond_broadcast(&wq->work_finished);
+ pthread_cond_broadcast(&work_finished);
}
pthread_mutex_unlock(&wq_lock);
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);
struct workqueue_struct *system_long_wq;
struct workqueue_struct *system_unbound_wq;
struct workqueue_struct *system_freezable_wq;
-struct workqueue_struct *system_power_efficient_wq;
-struct workqueue_struct *system_freezable_power_efficient_wq;
__attribute__((constructor(102)))
static void wq_init(void)
WQ_UNBOUND_MAX_ACTIVE);
system_freezable_wq = alloc_workqueue("events_freezable",
WQ_FREEZABLE, 0);
- system_power_efficient_wq = alloc_workqueue("events_power_efficient",
- WQ_POWER_EFFICIENT, 0);
- system_freezable_power_efficient_wq = alloc_workqueue("events_freezable_power_efficient",
- WQ_FREEZABLE | WQ_POWER_EFFICIENT,
- 0);
BUG_ON(!system_wq || !system_highpri_wq || !system_long_wq ||
- !system_unbound_wq || !system_freezable_wq ||
- !system_power_efficient_wq ||
- !system_freezable_power_efficient_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;
}