Workaround: Pending signal making wait_event_interruptible() return prematurely
It all starts with this: I’m not ready to return from my character device’s release() method before I know that the underlying hardware has acknowledged the shutdown. It is actually expected to do so quickly, so I relied on a wait_event_interruptible() call within the release method to do the short wait for the acknowledge.
And it actually worked well, until specific cases where I hit CTRL-C while a read() was blocking. I’m not exactly sure of why, but if the signal arrived while a blocking on wait_event_interruptible() within read(), the signal wouldn’t be cleared, so release() was called with the signal pending. As was quite evident with this little snippet in the release() code.
if (signal_pending(current)) printk(KERN_WARNING "Signal is pending on release()...\n");
… which ended up with the wait_event_interruptible() in the release() method returning immediately, yelling that the hardware didn’t respond.
Blocking indefinitely is out of the question, so the simple workaround is to sleep another 100ms if wait_event_interruptible() returns prematurely, and then check if the hardware is done. That should be far more than needed for the hardware, and a fairly small time penalty for the user.
So the waiting part in release() now goes:
if (wait_event_interruptible(fstr->wait, (!fstr->flag))) msleep(100);
The cute trick here is that the sleep takes place only in the event of an interrupt, so in a normal release() call we quit much faster.