diff options
Diffstat (limited to 'linux/workqueue.c')
-rw-r--r-- | linux/workqueue.c | 346 |
1 files changed, 0 insertions, 346 deletions
diff --git a/linux/workqueue.c b/linux/workqueue.c deleted file mode 100644 index 0d5af3fb..00000000 --- a/linux/workqueue.c +++ /dev/null @@ -1,346 +0,0 @@ -#include <pthread.h> - -#include <linux/kthread.h> -#include <linux/slab.h> -#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 list_head list; - - struct work_struct *current_work; - struct list_head pending_work; - - struct task_struct *worker; - char name[24]; -}; - -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)); -} - -static bool set_work_pending(struct work_struct *work) -{ - return !test_and_set_bit(WORK_PENDING_BIT, work_data_bits(work)); -} - -static void __queue_work(struct workqueue_struct *wq, - struct work_struct *work) -{ - BUG_ON(!work_pending(work)); - BUG_ON(!list_empty(&work->entry)); - - list_add_tail(&work->entry, &wq->pending_work); - wake_up_process(wq->worker); -} - -bool queue_work(struct workqueue_struct *wq, struct work_struct *work) -{ - bool ret; - - pthread_mutex_lock(&wq_lock); - if ((ret = set_work_pending(work))) - __queue_work(wq, work); - pthread_mutex_unlock(&wq_lock); - - return ret; -} - -void delayed_work_timer_fn(struct timer_list *timer) -{ - struct delayed_work *dwork = - container_of(timer, struct delayed_work, timer); - - pthread_mutex_lock(&wq_lock); - __queue_work(dwork->wq, &dwork->work); - pthread_mutex_unlock(&wq_lock); -} - -static void __queue_delayed_work(struct workqueue_struct *wq, - struct delayed_work *dwork, - unsigned long delay) -{ - struct timer_list *timer = &dwork->timer; - struct work_struct *work = &dwork->work; - - BUG_ON(timer->function != delayed_work_timer_fn); - BUG_ON(timer_pending(timer)); - BUG_ON(!list_empty(&work->entry)); - - if (!delay) { - __queue_work(wq, &dwork->work); - } else { - dwork->wq = wq; - timer->expires = jiffies + delay; - add_timer(timer); - } -} - -bool queue_delayed_work(struct workqueue_struct *wq, - struct delayed_work *dwork, - unsigned long delay) -{ - struct work_struct *work = &dwork->work; - bool ret; - - pthread_mutex_lock(&wq_lock); - if ((ret = set_work_pending(work))) - __queue_delayed_work(wq, dwork, delay); - pthread_mutex_unlock(&wq_lock); - - return ret; -} - -static bool grab_pending(struct work_struct *work, bool is_dwork) -{ -retry: - if (set_work_pending(work)) { - BUG_ON(!list_empty(&work->entry)); - return false; - } - - if (is_dwork) { - struct delayed_work *dwork = to_delayed_work(work); - - if (likely(del_timer(&dwork->timer))) { - BUG_ON(!list_empty(&work->entry)); - return true; - } - } - - if (!list_empty(&work->entry)) { - list_del_init(&work->entry); - return true; - } - - BUG_ON(!is_dwork); - - pthread_mutex_unlock(&wq_lock); - flush_timers(); - pthread_mutex_lock(&wq_lock); - goto retry; -} - -static bool work_running(struct work_struct *work) -{ - struct workqueue_struct *wq; - - list_for_each_entry(wq, &wq_list, list) - 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; -} - -bool cancel_work_sync(struct work_struct *work) -{ - bool ret; - - pthread_mutex_lock(&wq_lock); - ret = grab_pending(work, false); - - __flush_work(work); - clear_work_pending(work); - pthread_mutex_unlock(&wq_lock); - - return ret; -} - -bool mod_delayed_work(struct workqueue_struct *wq, - struct delayed_work *dwork, - unsigned long delay) -{ - struct work_struct *work = &dwork->work; - bool ret; - - pthread_mutex_lock(&wq_lock); - ret = grab_pending(work, true); - - __queue_delayed_work(wq, dwork, delay); - pthread_mutex_unlock(&wq_lock); - - return ret; -} - -bool cancel_delayed_work(struct delayed_work *dwork) -{ - struct work_struct *work = &dwork->work; - bool ret; - - pthread_mutex_lock(&wq_lock); - ret = grab_pending(work, true); - - clear_work_pending(&dwork->work); - pthread_mutex_unlock(&wq_lock); - - return ret; -} - -bool cancel_delayed_work_sync(struct delayed_work *dwork) -{ - struct work_struct *work = &dwork->work; - bool ret; - - pthread_mutex_lock(&wq_lock); - ret = grab_pending(work, true); - - __flush_work(work); - clear_work_pending(work); - pthread_mutex_unlock(&wq_lock); - - return ret; -} - -static int worker_thread(void *arg) -{ - struct workqueue_struct *wq = arg; - struct work_struct *work; - - pthread_mutex_lock(&wq_lock); - while (1) { - __set_current_state(TASK_INTERRUPTIBLE); - work = list_first_entry_or_null(&wq->pending_work, - struct work_struct, entry); - wq->current_work = work; - - if (kthread_should_stop()) { - BUG_ON(wq->current_work); - break; - } - - if (!work) { - pthread_mutex_unlock(&wq_lock); - schedule(); - pthread_mutex_lock(&wq_lock); - continue; - } - - BUG_ON(!work_pending(work)); - list_del_init(&work->entry); - clear_work_pending(work); - - pthread_mutex_unlock(&wq_lock); - work->func(work); - pthread_mutex_lock(&wq_lock); - - pthread_cond_broadcast(&work_finished); - } - pthread_mutex_unlock(&wq_lock); - - return 0; -} - -void destroy_workqueue(struct workqueue_struct *wq) -{ - kthread_stop(wq->worker); - - pthread_mutex_lock(&wq_lock); - list_del(&wq->list); - pthread_mutex_unlock(&wq_lock); - - kfree(wq); -} - -struct workqueue_struct *alloc_workqueue(const char *fmt, - unsigned flags, - int max_active, - ...) -{ - va_list args; - struct workqueue_struct *wq; - - wq = kzalloc(sizeof(*wq), GFP_KERNEL); - if (!wq) - return NULL; - - INIT_LIST_HEAD(&wq->list); - INIT_LIST_HEAD(&wq->pending_work); - - va_start(args, max_active); - vsnprintf(wq->name, sizeof(wq->name), fmt, args); - va_end(args); - - wq->worker = kthread_run(worker_thread, wq, "%s", wq->name); - if (IS_ERR(wq->worker)) { - kfree(wq); - return NULL; - } - - pthread_mutex_lock(&wq_lock); - list_add(&wq->list, &wq_list); - pthread_mutex_unlock(&wq_lock); - - return wq; -} - -struct workqueue_struct *system_wq; -struct workqueue_struct *system_highpri_wq; -struct workqueue_struct *system_long_wq; -struct workqueue_struct *system_unbound_wq; -struct workqueue_struct *system_freezable_wq; - -__attribute__((constructor(102))) -static void wq_init(void) -{ - system_wq = alloc_workqueue("events", 0, 0); - system_highpri_wq = alloc_workqueue("events_highpri", WQ_HIGHPRI, 0); - system_long_wq = alloc_workqueue("events_long", 0, 0); - system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND, - WQ_UNBOUND_MAX_ACTIVE); - system_freezable_wq = alloc_workqueue("events_freezable", - WQ_FREEZABLE, 0); - 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; -} |