How to send signal from Linux kernel space to user space in order to notify about an input hardware event
I will concentrate on sending a signal, since that is what you asked for, although sending signals to a process is quite brutal. It would be better to implement poll
and read
file operations so the user code can wait for events from the device and read them.
Anyway, for sending a signal to the processes that opened the device, the things you need are:
You need a
struct fasync_struct *
in the private data of your device:struct fasync_struct *pasync_queue;
It needs to be initialized to
NULL
by some means during initialization of your device private data. How you do that is up to you.You need a fasync file operation handler pointed to by the
fasync
member of yourstruct file_operations
. The implementation of the fasync handler is very simple as it just needs to callfasync_helper()
using supplied parameters and a pointer to your device's privatestruct fasync_struct *
:static int exer_fasync(int fd, struct file *pfile, int mode)
{
// N.B. Change this code to use the pasync_queue member from your device private data.
struct fasync_struct **fapp = &pasync_queue;
return fasync_helper(fd, pfile, mode, fapp);
}
struct file_operations exer_file_operations = {
.owner = THIS_MODULE,
.open = exer_open,
.read = exer_read,
.write = exer_write,
.release = exer_close,
.fasync = exer_fasync,
};Your device driver can send a
SIGIO
signal by callingkill_fasync()
as follows:// N.B. Change this code to use the pasync_queue member from your device private data.
struct fasync_struct **fapp = &pasync_queue;
kill_fasync(fapp, SIGIO, POLL_IN);N.B. The last parameter (value
POLL_IN
in this case) affects the value of thesi_band
member of thesiginfo_t
that your application sees in its signal handler.Your application needs to set a signal handler for the
SIGIO
signal. I recommend usingsigaction()
to set this up.Your application needs to set the
O_ASYNC
flag when it opens the device file, or set it by callingfcntl(fd, F_SETFL, O_ASYNC);
after opening the device file.
Event notification from kernel space to user space
(Had replied in the chat session but it seems like this should be in an answer so putting it here with more detail.)
What poll_wait does is add your driver to the list of file descriptors being waited for by the user space program. The pattern is:
- user program calls poll/select/epoll_ctl
- core kernel calls your driver's poll entry point
- driver calls poll_wait to add its wait queue to the list of waitqueues (unless the GPIO data is already readable, which you indicate via return value)
- later, when the device interrupts, you call wake_up on your wait queue, this unblocks the process if it's (still) waiting in a poll/select call
- user-mode program wakes up, calls read to actually obtain the data
IOW, poll_wait itself doesn't sleep (or block); it just adds your device to the list of programs that might wake the process up later. The sleep is done in the core kernel (inside the select system call, for example). That way, a user program can wait on any number of devices at once using select.
If your user-space program really doesn't have anything else to do while waiting, then you can simply have the user-program call read, and have your driver set up its wait queue and call wait_event_interruptible (or one of the other wait_event_* variants). This will block the process until your interrupt handler calls wake_up; at which time you copy from kernel buffer to user buffer.
Or you could support both methods. Typically if you support the select method, you also check the O_NONBLOCK file flag in your read function so that the user code has the option to not block in the read.
Yes, ISRs can call wake_up. It's a common pattern for device I/O: wait/block in "process context", wake-up in "interrupt context", then complete the I/O after returning to process context.
BTW, from the driver point of view, using select, poll or epoll are typically the same. From the user point of view, using select or poll is somewhat easier. It's a "one shot" deal: "here are a set of file descriptors; block until one of them is ready for read (or write etc) or until a timeout".
Whereas with epoll, you first create an epoll descriptor, then add I/O file descriptors individually. But then the "wait" call just specifies the single epoll descriptor. So if you have a large number of file descriptors to wait on, you don't have to specify all of them in each system call which leads to lower system call overhead on each epoll call.
Related Topics
Print Differences of File1 to File2 Without Deleting Anything from File2
Linux Kernel: Copy_From_User - Struct with Pointers
Is an Operating System Kernel an Interpeter for All Other Programs
"Bad Interpreter" Error Message When Trying to Run Awk Executable
Grep for String and Open at the Corresponding Line
How to Read Input from the Terminal Using /Dev/Stdin and Read.Csv()
How to Automate Measuring of Bandwidth Usage Between Two Hosts
Using Ssh to Run a Cleartool Command with Agruments on Remote a Linux MAChine
How to Get the Exit Status of the First Command in a Pipe
Using Gzip to Compress Files to Transfer with Aws Command
Stop Being Root in the Middle of a Script That Was Run with Sudo
Start Docker-Compose Automatically on Ec2 Startup
How to Configure Acpi *.Asl for a Virtual Mdio-Gpio Device Connected to a I2C Gpio Expander