#include #ifdef DEBUG_SUBSYSTEM #undef DEBUG_SUBSYSTEM #endif #define DEBUG_SUBSYSTEM S_TASKQ /* * 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; ASSERT(tww); ASSERT(tww->tww_func); /* 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; ENTRY; ASSERT(tq); ASSERT(func); /* Use GFP_ATOMIC since this may be called in interrupt context */ tww = (taskq_work_wrapper_t *)kmalloc(sizeof(*tww), GFP_ATOMIC); if (!tww) RETURN((taskqid_t)0); 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); RETURN((taskqid_t)0); } RETURN((taskqid_t)wq); } EXPORT_SYMBOL(__taskq_dispatch); /* 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 * 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) { taskq_t *tq; ENTRY; if (nthreads == 1) tq = create_singlethread_workqueue(name); else tq = create_workqueue(name); return tq; } EXPORT_SYMBOL(__taskq_create); void __taskq_destroy(taskq_t *tq) { ENTRY; destroy_workqueue(tq); EXIT; } EXPORT_SYMBOL(__taskq_destroy); void __taskq_wait(taskq_t *tq) { ENTRY; flush_workqueue(tq); EXIT; } EXPORT_SYMBOL(__taskq_wait);