203 lines
4.9 KiB
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;
|
|
}
|
|
|