驱动IO模型select

编程

新人学习,欢迎指正

selectc代码">部分select.c代码

		    应用层

select(maxfd+1,&rfds,NULL,NULL,NULL);

-------------------(系统调用)------------------------------

kernel-3.4.39/arch/arm/kernel$ vi calls.S

//系统调用相关的汇编文件

CALL(sys_select)

VFS:vi -t sys_select

->SYSCALL_DEFINE5宏,5代表有五个参数,替换得到sys_select

SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp,

fd_set __user *, outp,fd_set __user *, exp,

struct timeval __user *, tvp)

->

#define SYSCALL_DEFINE5(select, ...)

SYSCALL_DEFINEx(5, _select, __VA_ARGS__)

->

#define SYSCALL_DEFINEx(x,_select, ...)

__SYSCALL_DEFINEx(x, _select, __VA_ARGS__)

->

#define __SYSCALL_DEFINEx(x, _select, ...)

long sys_select(int n, fd_set __user * inp,

fd_set __user *outp,fd_set __user *exp,

struct timeval __user * tvp)

{

ret = core_sys_select(n, inp, outp, exp, to);

}

--------------------------------------------------------------

core_sys_select(n, inp, outp, exp, to);

//1.校验最大的文件描述符

struct fdtable *fdt;

fdt = files_fdtable(current->files);

max_fds = fdt->max_fds;

if (n > max_fds)

n = max_fds;

//2.分配文件描述符的内存

bits = kmalloc(6 * size, GFP_KERNEL);

fds.in = bits;

fds.out = bits + size;

fds.ex = bits + 2*size;

//在内核空间分配的读表,写表,其他表的首地址

fds.res_in = bits + 3*size;

fds.res_out = bits + 4*size;

fds.res_ex = bits + 5*size;

//在内核空间分配的准备好的读表,写表,其他表的首地址

//3.将用户空间的读表,写表,其他的表拷贝到内核空间

if ((ret = get_fd_set(n, inp, fds.in)) ===>copy_from_user

(ret = get_fd_set(n, outp, fds.out))

(ret = get_fd_set(n, exp, fds.ex)))

//4.文件描述符的检查,如果所有的文件描述符的数据

都没有准备好,进程休眠,否则将准备好的文件描

述符放入到fds.res_in,fds.res_out,fds.res_ex

ret = do_select(n, &fds, end_time);

//5.判断是否是信号唤醒的进程

ret = -ERESTARTNOHAND;

if (signal_pending(current))

goto out; ====>信号唤醒的就跳过拷贝

ret = 0;

//6.如果不是信号唤醒的休眠,将文件描述符拷贝到用户空间

if (set_fd_set(n, inp, fds.res_in) ||

set_fd_set(n, outp, fds.res_out) || ====>copy_to_user

set_fd_set(n, exp, fds.res_ex))

ret = -EFAULT;

---------------------------------------------------------------------

驱动:

unsigned int (*poll) (struct file *file,

struct poll_table_struct *wait);

部分do_select代码

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

{

struct poll_wqueues table;

poll_table *wait;

int retval, i;

unsigned long slack = 0;

retval = max_select_fd(n, fds);

//通过文件描述符表中的对应的被设置

//为1的位来校验最大的文件描述符的值

n = retval;

//将校验完的文件描述符赋值给n

poll_initwait(&table);

//poll相关结构体的初始化

//只需要关心函数指针的初始化过程就行了

//函数指针,执行的是__pollwait

//在__pollwait会拿到你提交的等待队列头,然后

//在等待队列头后面添加当前进程的等待队列项

retval = 0;

//retval是用来判断是否需要退出文件描述符遍历

//的循环的。

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;

//定义6个指针,将结构体中的6个指针

//赋值给这6个指针变量

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

{

//用来取第几个unsigned long类型的数据

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 += BITS_PER_LONG;

continue;

}

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

{

//用来unsigned long类型中的第几位的

file = fget_light(i, &fput_needed);

//这里的i就是获取到的文件描述符,fget_light

//通过文件描述符找到file结构体

//fd->fd_array[fd]->struct file

//POLLIN

if (file)

{

f_op = file->f_op;

if (f_op && f_op->poll)

{

mask = (*f_op->poll)(file, wait);

}

//如果file存在,并且fops存在,并且fops中的

//poll函数存在,就调用这个存在的poll函数

//就会得到mask

if ((mask & POLLIN_SET) && (in & bit))

{

res_in |= bit;

//将当前的文件描述符放到

//要返回的文件描述符表中

retval++;

}

if ((mask & POLLOUT_SET) && (out & bit))

{

res_out |= bit;

retval++;

}

if ((mask & POLLEX_SET) && (ex & bit))

{

res_ex |= bit;

retval++;

}

//如果mask中的POLLIN/POLLOUT/POLLEX被置位了

//将这些文件描述符放到准备好的文件描述表中

//并且将retval这个变量加1,只要retval不为0,

//死循环就会被退出

}

}

}

if (retval || timed_out || signal_pending(current))

break;

//如果retval不为0,或者超时时间到了或者信号到来了

//这个死循环就会被退出

if (!poll_schedule_timeout(&table, TASK_INTERRUPTIBLE,

to, slack))

//如果上述的条件都不满足,循环没有退出,进程

//就进入休眠状态

}

return retval;

}

}

以上是 驱动IO模型select 的全部内容, 来源链接: utcz.com/z/519702.html

回到顶部