高级字符设备驱动-Poll设备方法笔记

 

POLL方法

什么是POLL方法,功能是什么?

系统调用(用户空间)

驱动(内核空间)

Open

Open

Close

Release

Read

Read

Write

Write

Ioctl

ioctl

Lseek

Llseek

Select

poll

Select系统调用(功能)

Select系统调用用于多路监控,当没有一个文件满足要求时,select将阻塞调用进程

 

Int select(int maxfd, fd_set *readfds, fd_set *writefds, fe_set *exceptfds, const struct timeval *timeout)

 

Maxfd

文件描述符的范围,比待检测的最大文件描述符大1

Readfds

被读监控的文件描述符集

Writefds

被写监控的文件描述符集

Exceptfds

被异常监控的文件描述符集

Timeout

定时器

 

Timeout 取不同的值,该调用有不同的表现

 

1Timeout0,不管是否有文件满足要求,都立即返回,无文件满足要求返回0,有文件满足要求返回一个正值。

2Timeout nullselect将阻塞进程,直到某个文件满足要求。

3Timeout 值为正整数,就是等待的最长时间,即selecttimeout 时间内阻塞进程。

 

Select调用返回时,返回值有如下情况:

 

1正常情况下返回满足要求的文件描述符个数

2经过了timeout等待后仍无文件满足要求,返回值为0

3如果select被某个信号中断,它将返回-1并设置errnoEINTR

4如果出错,返回-1并设置相应的errno

Select系统调用(使用方法)

1)将要监控的文件添加到文件描述符集

2)调用select开始监控

3)判断文件是否发生变化

系统提供了4个宏对描述符集进行操作:

#include<sys/select.h>

Void FD_SET(int fd, fd_set *fdset)

Void FD_CLR(int fd, fd_set *fdset)

Void FD_ZERO(fd_set *fdset)

Void FD_ISSET(int fd, fd_set *fdset)

FD_SET将文件描述符fd添加到文件描述符fdset

FD_CLR从文件描述符集fdset中清除文件描述符fd

FD_ZERO清空文件描述符集fdset

在调用select后使用FD_ISSET来检测文件描述符集fdset中的文件fd发生了变化 

 

使用例子(对两个文件进行读监控)

FD_ZERO(&fds);//清空集合

FD_SET(fd1,&fds);//设置描述符

FD_SET(fd2,&fds);//设置描述符

Maxfdp = fd1+1;//描述符最大值加1,假设fd1>fd2

Switch(select(maxfdp,&fds,NULL,NULL,&timeout))//读监控

Case -1: exit(-1);break;//select错误,退出程序

Case 0:break;

Default:

If(FD_ISSET(fd1,&fds)) //测试fd1是否可读


 


POLL方法

原型:unsigned int (*poll)(struct file *filp, poll_table *wait)

负责完成:

1)使用poll_wait将等待队列添加到poll_table 

2)返回描述设备是否可读或者可写的掩码 

位掩码:

POLLIN

设备可读

POLLRDNORM

数据可读

POLLOUT

设备可写

POLLWRNORM

设备可写

例子:

Static unsigned int mem_poll(struct file *filp, poll_table *wait)

{

Struct scull_pipe *dev = filp->private_data;

Unsigned int mask = 0;

Poll_wait(filp,&dev->inq,wait);  //把等待队列添加到poll-table

If(有数据可读)

Mask = PONNIN | POLLRDNORM; //设备可读

Return mask;  //返回掩码

}


 

工作原理:

POLL方法只是做一个登记,真正的阻塞发生在select.c中的do_select函数

内核代码分析:

do_selectselect系统调用所对应的内核函数,do_select完成select的功能。

int do_select(int n, fd_set_bits *fds, struct timespec *end_time)

{

ktime_t expire, *to = NULL;

struct poll_wqueues table;

poll_table *wait;

int retval, i, timed_out = 0;

unsigned long slack = 0;

rcu_read_lock();

retval = max_select_fd(n, fds);

rcu_read_unlock();

if (retval < 0)

return retval;

n = retval;

poll_initwait(&table);

wait = &table.pt;

if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {

wait = NULL;

timed_out = 1;

}

if (end_time && !timed_out)

slack = estimate_accuracy(end_time);

retval = 0;

for (;;) {

unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;

inp = fds->in; outp = fds->out; exp = fds->ex;

rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex;

for (i = 0; i < n; ++rinp, ++routp, ++rexp) {

unsigned long in, out, ex, all_bits, bit = 1, mask, j;

unsigned long res_in = 0, res_out = 0, res_ex = 0;

const struct file_operations *f_op = NULL;

struct file *file = NULL;

in = *inp++; out = *outp++; ex = *exp++;

all_bits = in | out | ex;

if (all_bits == 0) {

i += __NFDBITS;

continue;

}

for (j = 0; j < __NFDBITS; ++j, ++i, bit <<= 1) {

int fput_needed;

if (i >= n)

break;

if (!(bit & all_bits))

continue;

file = fget_light(i, &fput_needed); //把file拿到,但不懂fget_light()

if (file) {

f_op = file->f_op;//拿到方法指针

mask = DEFAULT_POLLMASK;

if (f_op && f_op->poll) {

wait_key_set(wait, in, out, bit);

mask = (*f_op->poll)(file, wait);//调用poll,把掩码拿到

}

fput_light(file, fput_needed);

if ((mask & POLLIN_SET) && (in & bit)) {//判断是否在读监控集合里

res_in |= bit;                     //POLLIN_SET是一个集合

retval++;                        //判断文件是否可读

wait = NULL;

}

if ((mask & POLLOUT_SET) && (out & bit)) {//输出

res_out |= bit;

retval++;

wait = NULL;

}

if ((mask & POLLEX_SET) && (ex & bit)) {//异常

res_ex |= bit;

retval++;

wait = NULL;

}

}

}

if (res_in)

*rinp = res_in;

if (res_out)

*routp = res_out;

if (res_ex)

*rexp = res_ex;

cond_resched();

}

wait = NULL;

if (retval || timed_out || signal_pending(current))//判断超时、有信号、有文件满足?跳出大循环

break;

if (table.error) {

retval = table.error;

break;

}

/*

 * If this is the first loop and we have a timeout

 * given, then we convert to ktime_t and set the to

 * pointer to the expiry value.

 */

if (end_time && !to) {

expire = timespec_to_ktime(*end_time);

to = &expire;

}

if (!poll_schedule_timeout(&table, TASK_INTERRUPTIBLE,//带有限时的调度,进入TASK_INTERRUPTIBLE的睡眠,相当于阻塞了

   to, slack))

timed_out = 1;

}

poll_freewait(&table);

return retval;

}

你可能感兴趣的:(struct,File,table,null,Signal,代码分析)