点击(此处)折叠或打开
- 函数的入口定义如下:
- SYSCALL_DEFINES(select, int n,fd_set __user *,inp,fd_set __user *,outp,fd_set __user *,exp,struct timeval __user *,tvp)
- {
- struct timespec end_time,*to = NULL;
- struct timeval tv;
- int ret;
-
- if(tvp) {
- if(copy_from_user(&tv,tvp,sizeof(tv)))
- return -FAULT;
- to = &end_time;
- //获取绝对超时时间
- if(poll_select_set_timeout(to,
- tv.tv_sec + (tv.tv_usec / USEC_PER_SEC),
- (tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC))
- return -EINVAL;
- }
- ret = core_sys_select(n,inp,outp,exp,to);
- ret = poll_select_copy_remaining(&end_time,tvp,1,ret);
-
- return ret;
- }
- int poll_select_set_timeout(struct timespec *to,long sec,long nsec)
- {
- struct timespec ts = {.tv_sec = sec,.tv_nsec = nsec};
-
- if(!timespec_valid(&ts))
- return – EINVAL;
- if(!sec && !nsec) {
- to->tv_sec = to->tv_nsec = 0;
- } else {
- ktime_get_ts(to);
- *to = timespec_add_safe(*to,ts);
- }
- return 0;
- }
- //fd_set其实就是一个大小为32(32位系统)的长整性数组,这也就说明select最多只能注册32*32(1024)个fd
- int core_sys_select(int n,fd_set __user *inp,fd_set __user *outp,fd_set __user *exp,
- struct timespec *end_time)
- {
- /* typedef struct {
- unsigned long *in,*out,*ex;
- unsigned long *res_in,*res_out,*res_ex;
- }fd_set_bits;
- */
- fd_set_bits fds;
- void *bits;
- int ret,max_fds;
- unsigned int size;
- /*
- struct fdtable {
- unsigned int max_fds;
- struct file_rcu **fd; //current fd array
- fd_set *close_on_exec;
- fd_set *open_fdt;
- struct rcu_head rcu;
- struct fdtable *next;
- };
-
- **/
- struct fdtable *fdt;
- long stack_fds[SELECT_STACK_ALLOC / sizeof(long)];
-
- ret = -EINVAL;
- if(n < 0)
- goto out_nofds;
-
- rcu_read_lock();
- //获取对应进程的文件打开表
- fdt = file_fdtable(current->files);
- max_fds = fdt->max_fds;
- rcu_read_unlock();
- if(n > max_fds)
- n = max_fds;
- //通过最大的文件fd,找到总共需要的数组大小,并为指针开辟内存
- size = FDS_BYTES(n);
- bits = stack_fds;
- if(size > sizeof(stack_fds) / 6) {
- ret = -ENOMEM;
- bits = kmalloc(6 * size,GFP_KERNEL);
- if(!bits)
- goto out_nofds;
- }
- 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;
- //拷贝至内核态
- if((ret = get_fd_set(n,inp,fds.in)) ||
- (ret = get_fd_set(n,outp,fds.out)) ||
- (ret = get_fd_set(n,exp,fds.ex)))
- goto out;
-
- zero_fd_set(n,fds.res_in);
- zero_fd_set(n,fds.res_out);
- zero_fd_set(n,fds.res_ex);
- //将用户态的fd拷贝至内核态后开始进行处理
- ret = do_select(n,&fds,end_time);
-
- if(ret < 0)
- goto out;
- if(!ret) {
- ret = -ERESTARTNOHAND;
- if(signal_pending(current))
- goto out;
- ret = 0;
- }
- //将结果拷贝至用户态,只要出现错误就立即返回
- if(set_fd_set(n,inp,fds.res_in) ||
- set_fd_set(n,outp,fds.res_out) ||
- set_fd_set(n,exp,fds.res_ex))
- ret = -EFAULT;
- out:
- if(bits != stack_fds) //通过kmalloc分配所得,就进行释放
- kfree(bits);
- out_nofds:
- retun ret;
- }
点击(此处)折叠或打开
- int do_select(int n,fd_set_bits *fds,struct timespec *end_time)
- {
- ktime_t expire,*to = NULL;
- /*
- typedef struct poll_table_struct {
- poll_queue_proc qproc;
- unsigned long key;
- } poll_table;
- struct page_table_entry {
- struct file *filp;
- unsigned long key;
- wait_queue_t wait;
- wait_queue_head_t *wait_address;
- }
- struct poll_table_page {
- struct poll_table_page *next;
- struct poll_table_entry *entry;
- struct poll_table_entry entries[0];
- }
- struct poll_wqueue {
- poll_table pt;
- struct poll_table_page *table;
- struct task_struct *polling_task;
- int triggered;
- int error;
- int inline_index;
- //N_INLINE_POLL_ENTRIES 18(32位系统)
- struct poll_table_entry inline_entries[N_INLINE_POLL_ENTRIES];
- }
- **/
- struct poll_wqueue 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 && !time_out)
- slack = select_estimate_accuracy(end_time);
- retval = 0;
- for(;;) {
- unsigned long *rinp,*routp,*rexp,*inp,*oup,*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;
- //获取一个fd
- in = *inp ++; out = *oup++;ex = *exp ++;
- all_bits = in | out | ex;
- if(all_bits == 0) { //三个都没有注册,则直接进行下一个long
- i += __NFDBITS;
- continue;
- }
- for(j = 0;j < __NFDBITS;++j,++i,bit << =1) {
- int fput_needed;
- if(i >= n)
- break;
- if(!(bit & all_bits))
- continue;
- //增加对fd的引用计数,获取文件对象
- file = fget_light(i,&fput_needed);
- if(file) {
- f_op = file->f_op;
- mask = DEFAULT_POLLMASK;
- if(f_op && f_op->poll) {
- //获取用户态注册的事件
- wait_key_set(wait,in,out,bit);
- //调用对应文件系统的poll驱动,如果没有事件产生就会进行睡眠等待,
- //所有的文件poll驱动都会睡眠在同一对象wait上面
- mask = (*f_op->poll)(file,wait);
- }
- fput_light(file,fput_needed);
- if((mask & POLLIN_SET) && (in & bit)) {
- res_in |= bit;
- 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(ret_val || timed_out || signal_pending(current))
- break;
- if(table.error) {
- retal = table.error;
- break;
- }
- if(end_time && !to) { //更新剩余过期时间
- expire = timespec_to_ktime(*end_time);
- to = &expire;
- }
- //睡眠(to,to+slack)之间直到超时
- if(!poll_schedule_timeout(&table,TASK_INTERRUPTIBLE,
- to,slack))
- timed_out = 1;
- }
- poll_freewait(&table);//释放资源
- return retval;
- }
1.linux-3.3.2
2.linux 设备驱动程序