Description: Linux version 2.6.37.1
Combined with the summary of relevant data and summarized, to make a record, the wrong place please correct, thank you.
1.poll mechanism and wait queue
The application layer enters the kernel through the system call poll function, and the kernel executes the corresponding Sys_poll function. Call the Do_sys_poll function in the Sys_poll function. Do_sys_poll function by calling the Poll_initwait
Function initializes the Poll_wqueues variable table and assigns the __POLLWAIT function to the table. The __pollwait function here will be executed by calling the Poll_wait function in the driven poll method.
When the poll_initwait function is done, the Do_sys_poll function calls the Do_poll function.
There is a for Dead loop in the Do_poll function, the exit condition is count or timeout is Non-zero.
Count is not 0 identifies the mask returned by the DO_POLLFD function as true, and the timeout indicates a timed time.
The poll method in the drive is invoked by mask = File->f_op->poll in the DO_POLLFD function, and the poll value after the operation mask in the drive is obtained.
In the For Dead loop, the entire poll_list is polled first. Find out if there are any operations that have met the conditions in all pending poll operations, then jump out of the loop
No, continue down execution.
The wake operation in the figure above is implemented by invoking the WAKE_UP function in the driver. The example on the LDD3 is not complete,
You can learn how to drive poll using other blogs.
Summarize the mechanism of poll:
1.poll->sys_poll->do_sys_poll->poll_initwait
void poll_initwait (struct poll_wqueues *pwq)
{
Init_poll_funcptr (&pwq->pt, __pollwait);
Pwq->polling_task = current;
pwq->triggered = 0;
Pwq->error = 0;
pwq->table = NULL;
Pwq->inline_index = 0;
}
Attention should be paid here to Init_poll_funcptr (&pwq->pt, __pollwait)
Assign a function __pollwait function to a function pointer in the pooll_table structure that &pwq->pt points to.
The secondary function is called by calling the Poll_wait function in a later drive.
static inline void poll_wait (struct file * Filp, wait_queue_head_t * wait_address, poll_table *p)
{
if (P && wait_address)
P->qproc (Filp, wait_address, p);
}
Here the P->qproc operation is pointing to the __pollwait function
2.do_sys_poll->do_polll
static int do_poll (unsigned int nfds, struct poll_list *list,
struct poll_wqueues *wait, struct timespec *end_time)
{
for (;;) {
DO_POLLFD (PFD, PT)
if (count | | timed_out)
Break
Poll_schedule_timeout (Wait, task_interruptible, to, Slack)
}
}
After the poll_initwait function is initialized, the Do_sys_poll function invokes the Do_poll function.
First call the DO_POLLFD (PFD, PT) function in the Do_poll function
static inline unsigned int do_pollfd (struct POLLFD *pollfd, poll_table *pwait)
{
Mask = file->f_op->poll (file, pwait);
}
The poll method in the drive is invoked by File->f_op->poll, and the poll method in the drive invokes the Poll_wait function
poll_wait function calls the __pollwait function registered by the POLL_INITWAIT function
static void __pollwait (struct file *filp, wait_queue_head_t *wait_address,
Poll_table *p)
{
struct Poll_wqueues *pwq = container_of (p, struct poll_wqueues, PT);
struct Poll_table_entry *entry = poll_get_entry (PWQ);
if (!entry)
Return
Get_file (FILP);
Entry->filp = FILP;
entry->wait_address = wait_address;
Entry->key = p->key;
Init_waitqueue_func_entry (&entry->wait, Pollwake);
Entry->wait.private = Pwq;
Add_wait_queue (wait_address, &entry->wait);
}
You can see that this function completes the task of adding queues.
Then proceed down to execute poll_schedule_timeout ()
After this function is executed, the process enters hibernation until it is wake_up or dormant.
So summarize the poll operation: First call the poll function to register the __POLLWAIT function into the system, and then pass F_ops->poll
Call the driven poll method, poll->poll_wait to invoke the previously registered __pollwait function,
Add a wait queue in the __pollwait function and call the Poll_schedule_timeout () function
Hibernate it, waiting for other threads to wake up. So using polll and using a wait queue for simple hibernation is as needed elsewhere
wake_up function to notify
3. Waiting for the queue to hibernate
Driver call Wait_event can put functions into hibernation, look at the specific operation
#define Wait_event (Wq, condition) \
do {\
if (condition) \
Break \
__wait_event (Wq, condition); \
} while (0)
#define __wait_event (Wq, condition) \
do {\
Define_wait (__wait); \
\
for (;;) { \
Prepare_to_wait (&wq, &__wait, task_uninterruptible); \
if (condition) \
Break \
Schedule (); \
} \
Finish_wait (&wq, &__wait); \
} while (0)
Through the __wait_event for (;;) After the loop, the queue enters hibernation. Wait for wake_up after hibernation