kolibrios/drivers/ddk/linux/workqueue.c

203 lines
4.9 KiB
C

/*
* kernel/workqueue.c - generic async execution with shared worker pool
*
* Copyright (C) 2002 Ingo Molnar
*
* Derived from the taskqueue/keventd code by:
* David Woodhouse <dwmw2@infradead.org>
* Andrew Morton
* Kai Petzke <wpp@marie.physik.tu-berlin.de>
* Theodore Ts'o <tytso@mit.edu>
*
* Made to use alloc_percpu by Christoph Lameter.
*
* Copyright (C) 2010 SUSE Linux Products GmbH
* Copyright (C) 2010 Tejun Heo <tj@kernel.org>
*
* This is the generic async execution mechanism. Work items as are
* executed in process context. The worker pool is shared and
* automatically managed. There are two worker pools for each CPU (one for
* normal work items and the other for high priority ones) and some extra
* pools for workqueues which are not bound to any specific CPU - the
* number of these backing pools is dynamic.
*
* Please read Documentation/workqueue.txt for details.
*/
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/lockdep.h>
#include <linux/idr.h>
#include <ddk.h>
extern int driver_wq_state;
struct workqueue_struct *alloc_workqueue(const char *fmt,
unsigned int flags,
int max_active)
{
struct workqueue_struct *wq;
wq = kzalloc(sizeof(*wq),0);
if (!wq)
goto err;
INIT_LIST_HEAD(&wq->worklist);
INIT_LIST_HEAD(&wq->delayed_worklist);
return wq;
err:
return NULL;
}
void run_workqueue(struct workqueue_struct *cwq)
{
unsigned long irqflags;
// dbgprintf("wq: %x head %x, next %x\n",
// cwq, &cwq->worklist, cwq->worklist.next);
while(driver_wq_state != 0)
{
spin_lock_irqsave(&cwq->lock, irqflags);
while (!list_empty(&cwq->worklist))
{
struct work_struct *work = list_entry(cwq->worklist.next,
struct work_struct, entry);
work_func_t f = work->func;
list_del_init(cwq->worklist.next);
// printf("work %p, func %p\n",
// work, f);
spin_unlock_irqrestore(&cwq->lock, irqflags);
f(work);
spin_lock_irqsave(&cwq->lock, irqflags);
}
spin_unlock_irqrestore(&cwq->lock, irqflags);
delay(1);
};
}
bool queue_work(struct workqueue_struct *wq, struct work_struct *work)
{
unsigned long flags;
if(!list_empty(&work->entry))
return 0;
// dbgprintf("%s %p queue: %p\n", __FUNCTION__, work, wq);
spin_lock_irqsave(&wq->lock, flags);
list_add_tail(&work->entry, &wq->worklist);
spin_unlock_irqrestore(&wq->lock, flags);
return 1;
};
void __stdcall delayed_work_timer_fn(unsigned long __data)
{
struct delayed_work *dwork = (struct delayed_work *)__data;
struct workqueue_struct *wq = dwork->work.data;
queue_work(wq, &dwork->work);
}
bool queue_delayed_work(struct workqueue_struct *wq,
struct delayed_work *dwork, unsigned long delay)
{
struct work_struct *work = &dwork->work;
if (delay == 0)
return queue_work(wq, &dwork->work);
// dbgprintf("%s %p queue: %p\n", __FUNCTION__, &dwork->work, wq);
work->data = wq;
TimerHS(delay,0, delayed_work_timer_fn, dwork);
return 1;
}
bool schedule_delayed_work(struct delayed_work *dwork, unsigned long delay)
{
return queue_delayed_work(system_wq, dwork, delay);
}
//bool mod_delayed_work(struct workqueue_struct *wq,
// struct delayed_work *dwork,
// unsigned long delay)
//{
// return queue_delayed_work(wq, dwork, delay);
//}
int del_timer(struct timer_list *timer)
{
int ret = 0;
if(timer->handle)
{
CancelTimerHS(timer->handle);
timer->handle = 0;
ret = 1;
};
return ret;
};
bool cancel_work_sync(struct work_struct *work)
{
unsigned long flags;
int ret = 0;
spin_lock_irqsave(&system_wq->lock, flags);
if(!list_empty(&work->entry))
{
list_del(&work->entry);
ret = 1;
};
spin_unlock_irqrestore(&system_wq->lock, flags);
return ret;
}
bool cancel_delayed_work(struct delayed_work *dwork)
{
return cancel_work_sync(&dwork->work);
}
bool cancel_delayed_work_sync(struct delayed_work *dwork)
{
return cancel_work_sync(&dwork->work);
}
int mod_timer(struct timer_list *timer, unsigned long expires)
{
int ret = 0;
expires - GetTimerTicks();
if(timer->handle)
{
CancelTimerHS(timer->handle);
timer->handle = 0;
ret = 1;
};
timer->handle = TimerHS(expires, 0, timer->function, (void*)timer->data);
return ret;
}