I'm new to Linux device drivers writing and I'm trying to make a device driver that handles an UART chip. For this I decided to use work ques as my bottom half processing because I have to use some semaphores when handling the data that I get from the UART chip.
A work queue handler that was scheduled earlier in an interrupt now gets executed and during it's execution it will sleep at a semaphore. During this time the interrupt handler is called again and schedules the same work queue handler. Will the work queue handler be executed again before the first execution of it finishes ?
Thanks.
The default behavior of work queues is to allow concurrent execution on different CPUs. There is a flag WQ_NON_REENTRANT that changes this behavior. More information can be found in this post http://lwn.net/Articles/403891/
But it seems that in recent kernels work queues are non-reentrant by default - see
http://lwn.net/Articles/511190
Related
I need to use workqueue-like feature on Mac OSX (kernel mode driver) and am looking for a way to add work into a queue to be processed by a kernel thread later. Conceptually this is the same thing as workqueue feature available in Linux kernel. Is there something similar on XNU kernel as well?
I don't think there's a direct equivalent as such, although I admit I'm not intimately familiar with the Linux side, so I'll avoid comparing and just tell you about what's available on macOS/xnu.
I/O Kit IOWorkLoops
If you're building an I/O Kit driver, and especially if you're writing a secondary interrupt handler, you'll be using IOWorkLoops. Interrupts are abstracted by IOEventSource objects, which schedule secondary interrupt handlers to run on the driver's IOWorkLoop.
Each IOWorkLoop wraps one kernel thread and also provides a serialisation/locking mechanism for resources shared with that thread. All jobs submitted to a workloop either explicitly through an IOCommandGate or the workloop object directly, or as a result of an IOEventSource event will be serialised. Note that IOCommandGate jobs will run synchronously on the calling thread, not the workloop thread.
As always with macOS/OSX internals, you will want to look at the header file comments and possibly the implementation in the xnu source for details. I personally find IOWorkLoops a bit clumsy for some tasks, but if you're dealing with PCI devices, etc. you don't really have a choice.
thread_call
A more lightweight background work mechanism is the thread_call API. It's defined in <kern/thread_call.h> and supports running functions on an OS-managed background thread, optionally after a delay or with a specific priority. This is probably closer to what you know from Linux, has a fairly straightforward API, but is not suitable for secondary interrupt handlers.
I'm working on a virtual audio/midi driver and although its already working, I'm wondering whether my implementation is ... proper..
Usually, the midi hardware triggers interrupts in the driver to send / receive / process data, however as my driver is virtual, there is no hardware that could trigger the interrupts.
The way I handled this is that I set up a DPC timer for 100ms that calls the processing / sending routines, data received is still handles via interrupt from the OS.
Now that obviously isn't quite what DPCs are for, are they. However I cannot think of another implementation that works as well.
So.. any suggestions would be greatly appreciated :)
Regards,
Xaser
Every device driver book talks about not using functions that sleep in interrupt routines.
What issues occur by calling these functions from ISRs ?
A total lockdown of the kernel is the issue here. The kernel is in interrupt context when executing interrupt handlers, that is, the interrupt handler is not associated with any process (the current macro cannot be used).
If you are able to sleep, you would never be able to get back to the interrupted code, since the scheduler would not know how to get back to it.
Holding a lock in the interrupt handler, and then sleeping, allowing another process to run and then entering the interrupt handler again and trying to re-acquire the lock would deadlock the kernel.
If you try to read more about how the scheduling in the kernel works, you will soon realize why sleeping is a no go in certain contexts.
I am spawning few threads inside ioctl call to my driver. I am also assigning kernel affinity to my driver. I want to ensure one of the thread does not get scheduled out till a particular event is flagged by the other thread. Is there any way to not allow windows scheduler to context out my thread. Using _disable() may hang the system as event may take couple of seconds.
Environment is windows 7,64bit
Thanks,
What you are probably after is a spin lock. However this is probably a bad idea unless you can guarantee that your driver/application is always run on a multi-processor system, even then it is still very bad practice. On a single processor system if a thread spin locks then the other thread signalling the spin locked thread will never be scheduled and so can't signal your event. Spin locks are meant to be used sparingly and only when the lock is for a very short time, never a couple of seconds.
It sounds like you need to use an event or other signally mechanism to synchronise your threads and let the windows scheduler do its job. If you need to respond to an event very quickly then interrupts or a Deferred Procedure Call (DPC) could be used instead.
What is Windows' best I/O event notification facility?
By best I mean something that ...
doesn't have a limit on number of input file descriptors
works on all file descriptors (disk files, sockets, ...)
provides various notification modes (edge triggered, limit triggered)
In Windows, async operations are done by file operation, not by descriptor. There are several ways to wait on file operations to complete asynchronously.
For example, if you want to know when data is available on a network socket, issue an async read request on the socket and when it completes, the data was available and was retrieved.
In Win32, async operations use the OVERLAPPED structure to contain state about an outstanding IO operation.
Associate the files with an IO Completion Port and dispatch async IO requests. When an operation completes, it will put a completion message on the queue which your worker thread(s) can wait on and retrieve as they arrive. You can also put user defined messages into the queue. There is no limit to how many files or queued messages can be used with a completion port
Dispatch each IO operation with an event. The event associated with an operation will become signaled (satisfy a wait) when it completes. Use WaitForMultipleObjects to wait on all the events at once. This has the disadvantage of only being able to wait on MAXIMUM_WAIT_OBJECTS objects at once (64). You can also wait on other types of events at the same time (process/thread termination, mutexes, events, semaphores)
Use a thread pool. The thread pool can take an unlimited number of objects and file operations to wait on and execute a user defined function upon completion each.
Use ReadFileEx and WriteFileEx to queue Asynchronous Procedure Calls (APCs) to the calling thread and SleepEx (or WaitFor{Single|Multiple}ObjectsEx) with Alertable TRUE to receive a notification message for each operation when it completes. This method is similar to an IO completion port, but only works for one thread.
The Windows NT kernel makes no distinction between socket, disk file, pipe, etc. file operations internally: all of these options will work with all the file types.
libuv
libuv offers evented I/O for Unix and Windows and has support for socket, files and pipes. It is the platform layer of Node.js.
More details are at: http://nikhilm.github.io/uvbook/introduction.html
There isn't one yet, as far as I am aware. A friend and I are working on an open source Windows epoll implementation (link below) but we're running into issues figuring out how to make it act the same as the Linux implementation.
Current obstacles:
In Linux, file descriptors and socket descriptors are interchangeable, but in Windows they are not. Both must be compatible with an epoll implementation.
In Windows it's quite tricky to get kernel events... which is how epoll works in Linux. We're guessing that a program using our cross-platform epoll library will run noticeably slower in Windows than Linux.
I'll try to come back and update this post as we make progress with the project.
http://sourceforge.net/projects/cpoll
select() function is POSIX and usable on windows including "winsock.h" or "winsock2.h".