Linux Device Driver - How to unblock reading thread when closing file? - linux

I am attempting to implement a character device driver for Linux and am having trouble. In short, data written to the device is buffered for reading. When no data is available, the call to read blocks via 'wait_event_interruptible'. Data received by the write handler calls 'wake_up_interruptible'. The release handler also calls 'wake_up_interruptible' to unblock the reader but sets a flag to indicate the driver is releasing.
From user space I have an executable that opens the driver via 'open' and then starts another thread. The main thread proceeds to call 'read'. As intended, no data is available for reading and the call blocks. The other thread sleeps for one second (providing sufficient time for the main thread to read and block), calls 'close' and then calls 'close' again. The first call returns '0' while the second returns '-1' (as expected). However, my driver's release handler is never called and I cannot understand how to unblock my reading thread without explicitly sending it a signal or writing some data to the device. My understanding is that when the last handle to the driver closes that its release handler is invoked. I am trying to implement what I believe is standard user space behavior- a thread blocked reading from a file will become unblocked and receive an end-of-file return value when asynchronously closed.
Do I have the correct understanding of read/close at the file level in user space? Do I have the correct device driver understanding? Am I missing something else? I looked through 'Linux Device Drivers 3rd Edition' and couldn't quite find an answer to this question. I have also searched Google but cannot seem to find the answer either. Any help you can provide is appreciated. My kernel version is 3.0.15.

Unfortunately the read syscall keeps a reference on the file itself and not the file descriptor. So closing the file descriptor will not abort the read.
In all cases you must be careful about races conditions between unblocking and closing, you don't want the thread (or another one) to re-enter the syscall between ;)

Related

Restoring Keyboard IRQ

I'm very new to the Linux Kernel Module development and trying to write a simple kernel module which can later be extended as the keyboard driver.
I tried following two approaches:
Interrupt Based Approach
I started writing the code after following the guide given here. But the only problem is that the machine freezes when I run rmmod because it is not able to restore the IRQ to the original keyboard driver.
Is there any way to save the device name & device id of the original keyboard driver before requesting the IRQ in init() and then restore everything back to normal once the exit() i.e. cleanup_module() is fired?
void cleanup_module() {
/* Something to restore everything back to normal */
free_irq(1, NULL);
}
Polling Approach
In this approach, I am continuously polling for the Key Pressed & Released by using a while loop and then copying the input back to the user.
while(!(inb(0x64) & 0x1) || (input = inb(0x60)) & 0x80);
The problem I'm facing here is that it never comes out of the while loop. I'm assuming that is because the original keyboard driver serves the request.
Is there any way to get the request forwarded from the original keyboard driver?
I appreciate any help/pointers on this.
Thanks!
I'm afraid that I do not see how this can work as long as the normal kernel keyboard driver is also controlling the keyboard, since both drivers will be attempting to control the device. The kernel i8042 driver (I assume that is the relevant one for you) registers its interrupt as shared, and if your driver managed to register for the same interrupt then it will also have registered its handler as shared, so that both got notified on interrupts and would race to access the device.
If you registered a shared handler, this might also explain the crash when you unload it: unregistering a shared interrupt handler only works when the second parameter contains a valid dev_id; so unregistering would fail when called with NULL as you did, but the handler code would still be unloaded from memory. This would leading to a crash on a future interrupt.
Regarding your polling approach, yes, since the normal driver is notified on interrupts it is rather likely to beat you to reading the keyboard.

Are epoll events being watched when not epoll_waiting

I'm rather new to event based programming. I'm experimenting with epoll's edge-mode which apparently only signals files which have become ready for read/write (as opposed to level-mode which signals all ready files, regardless of whether there were already ready, or just became ready).
What's not clear to me, is: in edge-mode, am I informed of readiness events that happen while I'm not epoll_waiting ? What about events on one-shot files that haven't been rearmed yet ?
To illustrate why I'm asking that, consider the following scenario:
have 10 non-blocking sockets connected
configure epoll_ctl to react when the sockets are ready for read, in edge-mode + oneshot : EPOLLET | EPOLLONESHOT | EPOLLIN
epoll_wait for something to happen (reports max 10 events)
linux wakes my process and reports sockets #1 and #2 are ready
I read and process data socket #1 (until E_AGAIN)
I read and process data socket #2 (until E_AGAIN)
While I'm doing that, a socket S receives data
I processed all events, so I rearm the triggered files with epoll_ctl in EPOLL_CTL_MOD mode, because of oneshot
my loop goes back to epoll_waiting the next batch of events
Ok, so will the last epoll_wait always be notified of the readiness of socket S ? Event if S is #1 (i.e. it's not rearmed) ?
I'm experimenting with epoll's edge-mode which apparently only signals
files which have become ready for read/write (as opposed to level-mode
which signals all ready files, regardless of whether there were
already ready, or just became ready)
First let's get a clear view of the system, you need an accurate mental model of how the system works. Your view of epoll(7) is not really accurate.
The difference between edge-triggered and level-triggered is the definition of what exactly makes an event. The former generates one event for each action that has been subscribed on the file descriptor; once you consume the event, it is gone - even if you didn't consume all the data that generated such an event. OTOH, the latter keeps generating the same event over and over until you consume all the data that generated the event.
Here's an example that puts these concepts in action, blatantly stolen from man 7 epoll:
The file descriptor that represents the read side of a pipe (rfd) is registered on the epoll instance.
A pipe writer writes 2 kB of data on the write side of the pipe.
A call to epoll_wait(2) is done that will return rfd as a ready file descriptor.
The pipe reader reads 1 kB of data from rfd.
A call to epoll_wait(2) is done.
If the rfd file descriptor has been added to the epoll interface using
the EPOLLET (edge-triggered) flag, the call to epoll_wait(2) done in
step 5 will probably hang despite the available data still present in
the file input buffer; meanwhile the remote peer might be expecting a
response based on the data it already sent. The reason for this is
that edge-triggered mode delivers events only when changes occur on
the monitored file descriptor. So, in step 5 the caller might end up
waiting for some data that is already present inside the input buffer.
In the above example, an event on rfd will be generated because of the
write done in 2 and the event is consumed in 3. Since the read
operation done in 4 does not consume the whole buffer data, the call
to epoll_wait(2) done in step 5 might block indefinitely.
In short, the fundamental difference is in the definition of "event": edge-triggered treats events as a single unit that you consume once; level-triggered defines the consumption of an event as being equivalent to consuming all of the data belonging to that event.
Now, with that out of the way, let's address your specific questions.
in edge-mode, am I informed of readiness events that happen while I'm
not epoll_waiting
Yes, you are. Internally, the kernel queues up the interesting events that happened on each file descriptor. They are returned on the next call to epoll_wait(2), so you can rest assured that you won't lose events. Well, maybe not exactly on the next call if there are other events pending and the events buffer passed to epoll_wait(2) can't accommodate them all, but the point is, eventually these events will be reported.
What about events on one-shot files that haven't been rearmed yet?
Again, you never lose events. If the file descriptor hasn't been rearmed yet, should any interesting event arise, it is simply queued in memory until the file descriptor is rearmed. Once it is rearmed, any pending events - including those that happened before the descriptor was rearmed - will be reported in the next call to epoll_wait(2) (again, maybe not exactly the next one, but they will be reported). In other words, EPOLLONESHOT does not disable event monitoring, it simply disables event notification temporarily.
Ok, so will the last epoll_wait always be notified of the readiness of
socket S? Event if S is #1 (i.e. it's not rearmed)?
Given what I said above, by now it should be pretty clear: yes, it will. You won't lose any event. epoll offers strong guarantees, it's awesome. It's also thread-safe and you can wait on the same epoll fd in different threads and update event subscription concurrently. epoll is very powerful, and it is well worth taking the time to learn it!

Track user thread life in kernel space

I'm trying to track the life span of a user thread in a kernel module. I want to detect when a user thread is no longer executing (exit() has been called). How would I go about doing that? I'm digging into the kernel source code as I write this, but there's a lot to take in!
I did find task_struct.vfork_done, and it looks like something I can hook into. Am I on the right track?
Before anything, let me confirm that by 'no longer executing' you mean the process has been signaled to die and will soon expire. If I were you, I would register a notification chain within a simple misc driver module.
I would then trigger the notification from within the signal handling code of the kernel when the process under question has been signalled with a fatal signal. I would specifically tinker with the function get_signal_to_deliver (kernel/signal.c). I've recently answered a similar query here

getting notified on flock/lockf/fcntl changes without polling

Is there a way (in Linux) of getting updates on the lockedness status of a file without polling?
I know that the status can be polled via a lockf(fd, F_TEST) or speculative LOCK_NB|LOCK_SH, but polling is bad(tm).
Of course, finding out when a file is NOT locked can be done with a simple lock attempt, but I want to sample the other edge too (use-case: a (large) program uses lockf to synchronize between instances - I can probably get it changed to flock, and I want to add a GUI that displays when the lock is acquirable, of course while not hogging the lock).
Note that inotify does not work in this case, at least on linux 3.9.1.

In Delphi, is OutputDebugString thread safe?

Is
OutputDebugString(PAnsiChar(''));
thread safe?
I/we have been using it in threads for debugging, and it never occurred to me if I should be doing it a different way.
(Delphi 7)
Well, not that it isn't true, it is, but just so that you don't have to just take Lieven word for it:
Passing of data between the
application and the debugger is done
via a 4kbyte chunk of shared memory,
with a Mutex and two Event objects
protecting access to it. These are the
four kernel objects involved.
Understanding Win32 OutputDebugString is an excellent article on the matter.
Don't worry, it is.
When OutputDebugString() is called by an application, it takes these
steps. Note that a failure at any point abandons the whole thing and
treats the debugging request as a no-op (the string isn't sent
anywhere).
Open DBWinMutex and wait until we have exclusive access to it.
Map the DBWIN_BUFFER segment into memory: if it's not found,
there is no debugger running so the entire request is ignored.
Open the DBWIN_BUFFER_READY and DBWIN_DATA_READY events. As with
the shared memory segment, missing objects mean that no debugger is
available.
Wait for the DBWIN_BUFFER_READY event to be signaled: this says
that the memory buffer is no longer in use. Most of the time, this
event will be signaled immediately when it's examined, but it won't
wait longer than 10 seconds for the buffer to become ready (a timeout
abandons the request).
Copy up to about 4kbytes of data to the memory buffer, and store
the current process ID there as well. Always put a NUL byte at the end
of the string.
Tell the debugger that the buffer is ready by setting the
DBWIN_DATA_READY event. The debugger takes it from there.
Release the mutex
Close the Event and Section objects, though we keep the handle to
the mutex around for later.
I've had trouble once, though, with strings in an ISAPI DLL. For some odd reason the IsMultiThread boolean defined in System.pas was not set!
It was causing weird AccessViolations, once the thread was running more than one thread... A simple "IsMultiThread:=true;" in a unit initialization fixed it.

Resources