I am writing a device driver that must serialize access to driver data and
registers on the device across file operations (open, close, ioctl, etc) and
interrupt handling operations.
I use a sempahore [ down_interruptable() and up() ] when enterring and leaving
the file operations but, as I have discovered, these cannot be used in the
For the time being I have added the use of spin locks. I must still use the
sempahore for file operations because spin_lock_irqsave doesn't seem to do
anything else but disable interrupts one a single processor system.
Some of the file operations are rather long and I would prefer not to have the
CPU's interrupts diabled all the time. Also some of the interrupt handler's
tasks are involved and I would like to delegate them to a tasklet or BH
mechanism. However, from what I understand, those cannot use sempahores
either. Is this true? Or can a BH use semaphores?
Here is what I would like to do but I don't know if Linux supports it:
I would like to use something like a kernel thread - a task I can start up
when my module loads and kill when it unloads. The task would perform all of
the interrupt handler functions but not at the interrupt level so it could use
the sempahore to sleep and protect the data it needs to access. The task
would start off sleeping in wait_event(). The actual interrupt level handler
function would then wake it up. Upon waking the task would obtain the
semaphore, perform the actions to service the interrupt, release the semaphone
then go back to sleep with wait_event() unless the interrupt level handler has
incremented an interrupt count signifying there may be more work to do.
The driver's unload routine would also wake up the interrupt service thread
after setting a flag that says it should exit.
I thought of using a user-mode daemon that would use a special ioctl command
that does the interrupt service loop. But I would prefer to keep everything
within the driver code and managed by the driver. I don't like the prospect
of having to maintain the separate daemon - checking to see if it dies for
some reason or even having to provide a mechanism to stop and restart it if
the driver module is unloaded and reloaded.
Can a tasklet be used in such a way? Is it possible to start a tasklet in the
module initialization function and can that tasklet use semaphores?
Is there a kernel thread mechanism in Linux?