Explain in more detail, please, how this method works. I did not understand the description in English. The only thing I understand why polling is needed is getting information, for example, whether reading or writing is available. But how poll_wait works. I do not understand who and why he adds to the waiting queue. Could you explain in more detail the purpose of this function. Thanks in advance
- In what context did you meet this function? - Fat-Zer
- Kernel modules For example, when we open a device file in a program in the address space and call select, poll. What is being done at the core level? Specifically in the module - Ayrat Arifullin
- Here: stackoverflow.com/questions/30234496/… - the answer is given. But since I am absolutely not in the development thread in the kernel, I realized only that with this call the driver itself adds to the list of entities that can wake up the poll () process. I can not judge how true this is, so with a comment, not an answer. Suddenly help. - Alexander Prokoshev
- ibm.com/developerworks/ru/library/l-linux_kernel_22/index.html - 0-Level UNIX Monk
1 answer
tl; dr
poll_wait () adds the current process to the list ( waiting queue ) of those that need to be awakened when data arrives / the recording is available in the device. To do this, the driver must call wake_up_interruptible() for the same queue at the desired event, which will awaken all the processes added to the queue.
How poll () works
For example, when we open a device file in a program in the address space and call select, poll. What is being done at the core level?
Called system call. Let it be poll() (c select everything is the same). It leads the data to the internal format of the kernel and calls do_poll() , which starts a wait cycle . First, it passes through all the file descriptors passed by poll , calling do_pollfd() .
do_pollfd() is essentially just a wrapper over a call (via vfs_poll() for the latest kernels) of a specific poll method for a particular file specified in .poll in its struct file_operations . A file can be either a device file, a socket, a pipe, or a simple file (although the latter doesn’t make much sense, except for /proc/kmsg or something like that).
As written in LDD3 (see chapter 6 / poll and select ), .poll() usually consists of two steps:
- Call poll_wait for one or more wait queues and add process to them.
- The return of a bit mask describing what operations (read / write) can be performed with a handle at a given moment .
Waiting queues are essentially a simple, doubly linked list of processes. But all operations with it are carried out as with an opaque structure through its API . Usually each device has its own independent one or two queues (for reading and writing).
Using the example of /dev/random , random_poll() calls the notorious poll_wait() for both of its queues, and then checks if there is any read / write data available, and sets the corresponding flags.
For poll / select poll_wait() expanded to __pollwait() , which copies the queue address to the structure associated with the current call, and then adds the current process to this queue using init_waitqueue_func_entry() / add_wait_queue() .
As already mentioned, after the completion of the .poll() method, the bit mask of the available flags is returned, which do_pollfd() analyzes, and if it notices the event requested by the user, it will return a non-zero value to do_poll() . Then do_poll() will continue to traverse the remaining descriptors.
If for one descriptor the desired event did not occur, then do_poll() checks if the timeout has expired. And then starts the alarm and goes to sleep .
One of three things can wake him up from sleep: either the damn alarm clock rang out of timeout, or the process received some kind of signal, or from the waiting queue. The latter occurs by an explicit call from the wake_up_interruptible() driver (which wakes up all the processes added to the queue) associated with the queue, for example for /dev/random here . After that, do_poll () again bypasses all the descriptors via do_pollfd() → .poll() (of course, without again adding the descriptor to the queue).
If do_poll() for the desired event / signal / timeout, then it returns a poll control that prepares data for the user and calls poll_freewait() , which, in addition to freeing memory for the internal poll structures, deletes the process from all associated queues.