Wednesday September 08, 2004 Kernel TODO lists (a.k.a. task queues) Solaris 10 comes with a new interface for kernel developers: task queues. This interface allows you to execute some job later in the context of completely different thread. Why would you need to do that? For example, you driver has to wait for some resource to become available but you can't wait (may be driver code is executing in interrupt context or is holding some lock). In this case you can wait and complete processing in a different context where it is safe.
The interface is fully described in the taskq(9f) man page. Here is a snippet:
#include <sys/sunddi.h>
ddi_taskq_t *ddi_taskq_create(dev_info_t *dip, const char
*name, int nthreads, pri_t pri, uint_t cflags);
void ddi_taskq_destroy(ddi_taskq_t *tq);
int ddi_taskq_dispatch(ddi_taskq_t *tq, void (*func)(void*), void *arg, uint_t dflags);
void ddi_taskq_wait(ddi_taskq_t *tq);
void ddi_taskq_suspend(ddi_taskq_t *tq);
boolean_t ddi_taskq_suspended(ddi_taskq_t *tq);
void ddi_taskq_resume(ddi_taskq_t *tq);
For example, your driver may create a task queue in its attach(9E)
routine:
static ddi_taskq_t xxx_taskq;
int xxx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
switch (cmd) {
case DDI_ATTACH:
xxx_taskq = ddi_taskq_create(dip, "xxx_useful_taskq", 1, TASKQ_DEFAULTPRI, 0);
...
break;
}
Then, somewhere in the guts of the driver code you may schedule a remote taskq:
typedef struct my_data {
kmutex_t drv_lock;
kcondvar_t drv_cv;
boolean_t drv_ready;
} my_data_t;
void xxx_complete_request(void *data)
{
my_data_t *arg = (my_data_t *)data;
mutex_enter(&arg->drv_lock);
while (!arg->drv_ready) {
cv_wait(&arg->drv_cv, &arg->drv_lock);
}
xxx_complete_request_processing(arg);
}
void xxx_intr(void *data)
{
...
if (ddi_taskq_dispatch(xxx_taskq, xxx_complete_request, data, DDI_NOSLEEP) != DDI_SUCCESS) {
recover_from_memory_shortage();
}
}
As a result, the driver interrupt routine will execute xxx_complete_request() at some later time in
a context of completely separate thread.
Note that if some task blocks waiting for something, it will block all tasks queued behind it,
so you should be careful to avoid deadlocks.
Also note that if you create a task queue with a single thread, it will guarantee that all tasks are processed sequentially in order posted. Otherwise an order is not guaranteed. How can you use it in your drier? Hint: it is a DDI-compliant (and DR-friendly) way to create threads needed by your driver code. ( Sep 08 2004, 07:13:06 PM PDT ) Permalink