There are many ways to schedule work in the linux kernel: timers, tasklets, work queues, and kernel threads. What are the guidelines for when to use one vs another?
There are the obvious factors: timer functions and tasklets cannot sleep, so they cannot wait on mutexes, condition variables, etc.
What are the other factors in choosing which mechanism to us in a driver?
Which are the preferred mechanisms?
As you said, it depends on the task at hand:
Work queues defer work into a kernel thread – your work will always run in process
context. They are schedulable and can therefore sleep.
Normally, there is no debate between work queues or sotftirqs/tasklets; if the deferred work needs to sleep, work queues are used, otherwise softirqs or tasklets are used. Tasklets are also more suitable for interrupt handling (they are given certain assurances such as: a tasklet is never ran later than on the next tick, it’s always serialized with regard to itself, etc.).
Kernel timers are good when you know exactly when you want something to happen, and do not want to interrupt/block a process in the meantime. They run outside process context, and they are also asynchronous with regard to other code, so they’re the source of race conditions if you’re not careful.
Hope this helps.