2008-03-01 03:45:59 +03:00
|
|
|
#include <sys/taskq.h>
|
2008-02-26 23:36:04 +03:00
|
|
|
|
2008-04-21 21:29:47 +04:00
|
|
|
#ifdef DEBUG_SUBSYSTEM
|
|
|
|
#undef DEBUG_SUBSYSTEM
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define DEBUG_SUBSYSTEM S_TASKQ
|
|
|
|
|
2008-02-26 23:36:04 +03:00
|
|
|
/*
|
|
|
|
* Task queue interface
|
|
|
|
*
|
|
|
|
* The taskq_work_wrapper functions are used to manage the work_structs
|
|
|
|
* which must be submitted to linux. The shim layer allocates a wrapper
|
|
|
|
* structure for all items which contains a pointer to itself as well as
|
|
|
|
* the real work to be performed. When the work item run the generic
|
|
|
|
* handle is called which calls the real work function and then using
|
|
|
|
* the self pointer frees the work_struct.
|
|
|
|
*/
|
|
|
|
typedef struct taskq_work_wrapper {
|
|
|
|
struct work_struct tww_work;
|
|
|
|
task_func_t tww_func;
|
|
|
|
void * tww_priv;
|
|
|
|
} taskq_work_wrapper_t;
|
|
|
|
|
|
|
|
static void
|
|
|
|
taskq_work_handler(void *priv)
|
|
|
|
{
|
|
|
|
taskq_work_wrapper_t *tww = priv;
|
|
|
|
|
2008-04-21 21:29:47 +04:00
|
|
|
ASSERT(tww);
|
|
|
|
ASSERT(tww->tww_func);
|
2008-02-26 23:36:04 +03:00
|
|
|
|
|
|
|
/* Call the real function and free the wrapper */
|
|
|
|
tww->tww_func(tww->tww_priv);
|
|
|
|
kfree(tww);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX - All flags currently ignored */
|
|
|
|
taskqid_t
|
|
|
|
__taskq_dispatch(taskq_t *tq, task_func_t func, void *priv, uint_t flags)
|
|
|
|
{
|
|
|
|
struct workqueue_struct *wq = tq;
|
|
|
|
taskq_work_wrapper_t *tww;
|
|
|
|
int rc;
|
2008-04-21 21:29:47 +04:00
|
|
|
ENTRY;
|
2008-02-26 23:36:04 +03:00
|
|
|
|
2008-04-21 21:29:47 +04:00
|
|
|
ASSERT(tq);
|
|
|
|
ASSERT(func);
|
2008-02-26 23:36:04 +03:00
|
|
|
|
2008-04-03 20:33:31 +04:00
|
|
|
/* Use GFP_ATOMIC since this may be called in interrupt context */
|
|
|
|
tww = (taskq_work_wrapper_t *)kmalloc(sizeof(*tww), GFP_ATOMIC);
|
2008-02-26 23:36:04 +03:00
|
|
|
if (!tww)
|
2008-04-21 21:29:47 +04:00
|
|
|
RETURN((taskqid_t)0);
|
2008-02-26 23:36:04 +03:00
|
|
|
|
|
|
|
INIT_WORK(&(tww->tww_work), taskq_work_handler, tww);
|
|
|
|
tww->tww_func = func;
|
|
|
|
tww->tww_priv = priv;
|
|
|
|
|
|
|
|
rc = queue_work(wq, &(tww->tww_work));
|
|
|
|
if (!rc) {
|
|
|
|
kfree(tww);
|
2008-04-21 21:29:47 +04:00
|
|
|
RETURN((taskqid_t)0);
|
2008-02-26 23:36:04 +03:00
|
|
|
}
|
|
|
|
|
2008-04-21 21:29:47 +04:00
|
|
|
RETURN((taskqid_t)wq);
|
2008-02-26 23:36:04 +03:00
|
|
|
}
|
2008-02-27 22:09:51 +03:00
|
|
|
EXPORT_SYMBOL(__taskq_dispatch);
|
2008-02-26 23:36:04 +03:00
|
|
|
|
2008-04-24 01:19:47 +04:00
|
|
|
/* XXX - We must fully implement dynamic workqueues since they make a
|
|
|
|
* significant impact in terms of performance. For now I've made
|
|
|
|
* a trivial compromise. If you ask for one thread you get one
|
|
|
|
* thread, if you ask for more than that you get one per core.
|
|
|
|
* It's unclear if you ever really need/want more than one per-core
|
|
|
|
* anyway. More analysis is required.
|
|
|
|
*
|
|
|
|
* name - Workqueue names are limited to 10 chars
|
2008-02-26 23:36:04 +03:00
|
|
|
* pri - Ignore priority
|
|
|
|
* min - Ignored until this is a dynamic thread pool
|
|
|
|
* max - Ignored until this is a dynamic thread pool
|
|
|
|
* flags - Ignored until this is a dynamic thread_pool
|
|
|
|
*/
|
|
|
|
taskq_t *
|
|
|
|
__taskq_create(const char *name, int nthreads, pri_t pri,
|
|
|
|
int minalloc, int maxalloc, uint_t flags)
|
|
|
|
{
|
2008-04-24 01:19:47 +04:00
|
|
|
taskq_t *tq;
|
2008-04-21 21:29:47 +04:00
|
|
|
ENTRY;
|
2008-04-24 01:19:47 +04:00
|
|
|
|
|
|
|
if (nthreads == 1)
|
|
|
|
tq = create_singlethread_workqueue(name);
|
|
|
|
else
|
|
|
|
tq = create_workqueue(name);
|
|
|
|
|
|
|
|
return tq;
|
2008-02-26 23:36:04 +03:00
|
|
|
}
|
2008-02-27 22:09:51 +03:00
|
|
|
EXPORT_SYMBOL(__taskq_create);
|
2008-03-11 05:08:57 +03:00
|
|
|
|
|
|
|
void
|
|
|
|
__taskq_destroy(taskq_t *tq)
|
|
|
|
{
|
2008-04-21 21:29:47 +04:00
|
|
|
ENTRY;
|
2008-03-11 05:08:57 +03:00
|
|
|
destroy_workqueue(tq);
|
2008-04-21 21:29:47 +04:00
|
|
|
EXIT;
|
2008-03-11 05:08:57 +03:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(__taskq_destroy);
|
|
|
|
|
|
|
|
void
|
|
|
|
__taskq_wait(taskq_t *tq)
|
|
|
|
{
|
2008-04-21 21:29:47 +04:00
|
|
|
ENTRY;
|
2008-03-11 05:08:57 +03:00
|
|
|
flush_workqueue(tq);
|
2008-04-21 21:29:47 +04:00
|
|
|
EXIT;
|
2008-03-11 05:08:57 +03:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(__taskq_wait);
|