Wei Dongshan uboot_kernel_root file system study notes 5.9-Lesson 005_Character device driver_Section 009_The poll mechanism of character device driver

Foreword: The introduction of the POLL mechanism
Purpose: The driver program written in the Linux-driven button driver writing (interrupt mode) before, if no button is pressed. The read function never returns a value, and now I want to achieve a return value after a certain period of time even if no key is pressed. To achieve this function, you can use the poll mechanism. The poll mechanism is introduced in the following parts

1. Use the poll mechanism and write test programs

2. Analysis of the calling process of the poll mechanism

3. Drive writing of poll mechanism For
more detailed analysis of the code, please refer to: Understanding and simple use of poll mechanism driven by Linux

1. Driver poll mechanism related code

static unsigned forth_drv_poll(struct file *file, poll_table *wait)
{
	unsigned int mask = 0;
	poll_wait(file, &button_waitq, wait); // 不会立即休眠

	if (ev_press)
		mask |= POLLIN | POLLRDNORM;

	return mask;
}

static struct file_operations sencod_drv_fops = {
    .owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open    =  forth_drv_open,     
	.read	 =	forth_drv_read,	   
	.release =  forth_drv_close,
	.poll    =  forth_drv_poll,
};

2. Analysis of the calling process of the poll mechanism-kernel

Calling framework:
Insert picture description here
Summarize the above calling process: The
app program calls the poll function, and the kernel calls the do_poll function. There is an infinite loop inside the function. Calling the do_pollfd function is to execute the poll function in the driver.
If the return value of the poll function of the driver is not 0, then count++, if count is not 0, the app function is returned.
If the poll function of the driver returns a value of 0, and it has not timed out and there is no signal waiting to be processed, it will sleep. Continue to execute in an endless loop after sleep timeout.
If the poll function of the driver returns 0, and it times out or there is a signal waiting to be processed, it returns.

The following content is excerpted from "Analysis of the Poll Mechanism" written by Wei Dongshan
Insert picture description here

asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
	struct timespec __user *tsp, const sigset_t __user *sigmask,
	size_t sigsetsize)
{
	...

	ret = do_sys_poll(ufds, nfds, &timeout);
	...
}

This function is executed after processing the timeout parameter slightly do_sys_poll.

  1. The do_sys_poll function is also located in the fs/select.c file, we ignore other codes
int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout)
{
...
	poll_initwait(&table);
...
	fdcount = do_poll(nfds, head, &table, timeout);
...
}

Among them, poll_initwaitfunction: initialize a poll_wqueues type variable table

poll_initwait() -> init_poll_funcptr(&pwq->pt, __pollwait); -> pt->qproc = qproc;

which istable->pt->table.qproc = __pollwait.

  1. Among them, the do_poll(nfds, head, &table, timeout);function:

Insert picture description here
Analyzing the code, it can be found that its function is as follows: ①From line
02, it is known that this is a loop, and its exit condition is: a.
One of the three conditions of line 09 (count is not 0, timeout/signal waiting for processing)
A non-zero count means that at least one of do_pollfd on line 04 was successful.
b.11 lines and 12 lines: an error occurs.
②The focus is on the do_pollfd function, and the
third line will be analyzed later . Let the process sleep for a period of time. Note: After the application executes the poll call, if the conditions ①②are not met, the process will go to sleep . So, who wakes up? In addition to being awakened by the system from sleep to a specified time, it can also be awakened by the driver-remember this, this is the reason why poll_wait is called in the poll of the driver, which will be analyzed later.

  1. The do_pollfd function is located in the fs/select.c file, the code is as follows:
static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
{
...
			if (file->f_op && file->f_op->poll)
				mask = file->f_op->poll(file, pwait);
...
}

Among them, it const struct file_operations *f_op;can be seen that the poll function registered in the driver is called.

3. Analysis of the calling process of the poll mechanism-driver

There are two places related to poll in the driver:

  1. When constructing the file_opration structure, you must define your own poll function. Call poll_wait(file, &button_waitq, wait);function in poll function;
  2. The __pollwait function mentioned above is called through poll_wait. The pollwait code is as follows:
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);
}

p->qprocFunction is a __pollwaitfunction so the calling relationship becomes: the __poll_wait(file, &button_waitq, wait)
function code is as follows:

static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,poll_table *p)
{
	struct poll_table_entry *entry = poll_get_entry(p);//当前进程file对应的一个入口点entry
	if (!entry)
		return;
	get_file(filp);
	entry->filp = filp;														//
	entry->wait_address = wait_address;						//wait_address=button_waitq函数
	init_waitqueue_entry(&entry->wait, current);
	add_wait_queue(wait_address, &entry->wait);		//把button_waitq函数加入到
}

The function of the function is to hang the current process into a queue defined by the driver (not to sleep). Putting the process to sleep is the do_pollfunction analyzed earlier LINE30 __timeout=schedule_timeout(__timeout).
__poll_waitThe function just hangs the process into a certain queue, and the application calls poll -> sys_poll -> do_sys_poll -> poll_initwait and do_poll -> do_pollfd -> poll functions registered by the driver, and then calls schedule_timeout to enter sleep.
If the driver finds that the situation is ready (for example, the interrupt processing is completed and the app needs to respond), it can wake up the hanging process on the queue (in the buttons_irqfunction wake_up_interruptible(&button_waitq);). It can be seen that the role of poll_wait is only to allow the driver to find the process to be awakened.
Even without poll_wait, our program has a chance to be awakened:, chedule_timeout(__timeout)it just needs to sleep for __timeoutso long.

4. Summarize the poll mechanism:

1.`poll > sys_poll > do_sys_poll > poll_initwait`,poll_initwait函数注册一下回调函数__pollwait,它就是我们的驱动程序执行poll_wait时,真正被调用的函数。
2.接下来执行` do_sys_poll > do_poll > do_pollfd > file > f_op > poll`,即驱动程序里自己实现的poll函数。该函数会调用`poll_wait`把自己挂入某个队列,这个队列也是驱动自己定义的:
它还判断设备是否就绪。
3.如果设备未就绪,`do_sys_poll  > do_poll`里会让进程休眠一段时间。
4.进程被唤醒的条件有2:一是上面说的“一定时间”到了,二是被驱动程序唤醒。驱动程序发现条件就绪时,就把2.中提到的“某个队列”上挂着的进程唤醒。(例如有外部中断出现时,中断服务程序会唤醒进程)
5.如果驱动程序没有去唤醒进程,那么`chedule_timeout(__timeout)`超时后,会在`do_poll`函数中由于`for(;;)`存在死循环代码,所以重复执行2. 3.动作。直到应用程序的poll调用传入的时间到达?
这里不理解,应用程序传入的超时参数是如何实现的?不是通过`chedule_timeout(__timeout)`实现的吗.......?

Note: The poll mechanism can query the status of multiple drivers, such as the following do_pollfunction codes:

for (; pfd != pfd_end; pfd++) {
	/*
	 * Fish for events. If we found one, record it
	 * and kill the poll_table, so we don't
	 * needlessly register any other waiters after
	 * this. They'll get immediately deregistered
	 * when we break out and return.
	 */
	if (do_pollfd(pfd, pt)) {
		count++;
		pt = NULL;
	}
}

5. Usage of test program-poll

  1. The header file contains#include <poll.h>
  2. Function call:ret = poll(fds, 1, 5000);

Parameter 1: do_pollThe file used to specify the function code of the kernel to query is the current file

 struct pollfd {
               int   fd;         /* file descriptor */
               short events;     /* requested events */
               short revents;    /* returned events */
           };

struct pollfd fds[1];
fds[0].fd     = fd;//用于指定内核的`do_poll`函数代码查询的文件是当前文件
fds[0].events = POLLIN;//POLLIN表示有数据等待读取

Parameter 2: How many files to query? 1 means a file.
Parameter 3: timeout period? Unit: ms, 5000 means 5000ms
Return value: 0 means timeout return.

6. Implementation effect:

Insert picture description here
If we do nothing, the poll function in the app will return a value every 5s to continue executing the following program; otherwise, the process will go to sleep. Unlike the interrupt mechanism, it will always sleep if there is no key press. (Bare metal understanding: similar to the introduction of timer + external interrupt mechanism)

Guess you like

Origin blog.csdn.net/xiaoaojianghu09/article/details/104323187