主要有4个函数:
sys_select:处理时间参数,调用core_sys_select。
core_sys_select:处理三个fd_set参数,调用do_select。
do_select:做select/poll的工作。在合适的时机把自己挂起等待,调用sock_poll。
sock_poll:用函数指针分派到具体的协议层函数tcp_poll、udp_poll、datagram_poll。
层层分工明确,我也要多学习这种方式啊。
-
-
-
-
- asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp,
- fd_set __user *exp, struct timeval __user *tvp)
- {
- s64 timeout = -1;
- struct timeval tv;
- int ret;
-
- if (tvp) {
- if (copy_from_user(&tv, tvp, sizeof(tv)))
- return -EFAULT;
-
- if (tv.tv_sec < 0 || tv.tv_usec < 0)
- return -EINVAL;
-
-
- if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS)
- timeout = -1;
- else {
- timeout = DIV_ROUND_UP(tv.tv_usec, USEC_PER_SEC/HZ);
- timeout += tv.tv_sec * HZ;
- }
- }
-
-
- ret = core_sys_select(n, inp, outp, exp, &timeout);
-
- if (tvp) {
- struct timeval rtv;
-
- if (current->personality & STICKY_TIMEOUTS)
- goto sticky;
-
- rtv.tv_usec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ));
- rtv.tv_sec = timeout;
- if (timeval_compare(&rtv, &tv) >= 0)
- rtv = tv;
-
- if (copy_to_user(tvp, &rtv, sizeof(rtv))) {
- sticky:
-
-
-
-
-
-
-
-
- if (ret == -ERESTARTNOHAND)
- ret = -EINTR;
- }
- }
-
- return ret;
- }
-
-
-
-
-
-
-
-
-
- static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
- fd_set __user *exp, s64 *timeout)
- {
- fd_set_bits fds;
- void *bits;
- int ret, max_fds;
- unsigned int size;
- struct fdtable *fdt;
-
-
-
- long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];
-
- ret = -EINVAL;
- if (n < 0)
- goto out_nofds;
-
-
- rcu_read_lock();
- fdt = files_fdtable(current->files);
- max_fds = fdt->max_fds;
- rcu_read_unlock();
- if (n > max_fds)
- n = max_fds;
-
-
-
-
-
-
-
-
-
-
-
- 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);
-
-
-
-
-
- ret = do_select(n, &fds, timeout);
-
- 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)
- kfree(bits);
- out_nofds:
- return ret;
- }
-
-
-
-
-
-
-
-
-
-
-
- int do_select(int n, fd_set_bits *fds, s64 *timeout)
- {
- struct poll_wqueues table;
- poll_table *wait;
- int retval, i;
-
- 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 (!*timeout)
- wait = NULL;
- retval = 0;
-
- for (;;) {
- unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;
- long __timeout;
-
-
- set_current_state(TASK_INTERRUPTIBLE);
-
- 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);
- if (file) {
- f_op = file->f_op;
- mask = DEFAULT_POLLMASK;
-
-
-
- if (f_op && f_op->poll)
- mask = (*f_op->poll)(file, retval ? NULL : wait);
-
-
- fput_light(file, fput_needed);
-
-
-
- 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++;
- }
- }
-
-
-
-
-
-
-
-
- cond_resched();
- }
-
- if (res_in)
- *rinp = res_in;
- if (res_out)
- *routp = res_out;
- if (res_ex)
- *rexp = res_ex;
- }
- wait = NULL;
- if (retval || !*timeout || signal_pending(current))
- break;
- if(table.error) {
- retval = table.error;
- break;
- }
-
- if (*timeout < 0) {
-
- __timeout = MAX_SCHEDULE_TIMEOUT;
- } else if (unlikely(*timeout >= (s64)MAX_SCHEDULE_TIMEOUT - 1)) {
-
- __timeout = MAX_SCHEDULE_TIMEOUT - 1;
- *timeout -= __timeout;
- } else {
-
- __timeout = *timeout;
- *timeout = 0;
- }
-
-
-
-
- __timeout = schedule_timeout(__timeout);
- if (*timeout >= 0)
- *timeout += __timeout;
- }
-
-
- __set_current_state(TASK_RUNNING);
-
- poll_freewait(&table);
-
- return retval;
- }
-
-
- static unsigned int sock_poll(struct file *file, poll_table *wait)
- {
- struct socket *sock;
-
-
- sock = file->private_data;
-
-
-
- return sock->ops->poll(file, sock, wait);
- }
其他重要函数一览
static int max_select_fd(unsigned long n, fd_set_bits *fds)
返回在fd_set中已经打开的,并且小于用户指定最大值,的fd
static inline int get_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset)
从用户空间拷贝fd_set到内核
static inline void zero_fd_set(unsigned long nr, unsigned long *fdset)
把fd_set清零
static inline unsigned long __must_check set_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset)
把fd_set拷贝回用户空间
static inline int signal_pending(struct task_struct *p)
目前进程有信号需要处理
struct file *fget_light(unsigned int fd, int *fput_needed)
由fd得到其对应的file结构指针,并增加其引用计数
static inline void fput_light(struct file *file, int fput_needed)
释放由fget_light得到的file结构指针,减少其引用计数
set_current_state
设置当前进程的状态
static inline int cond_resched(void)
判断是否有进程需要抢占当前进程,如果是将立即发生调度。就是额外增加一个抢占点。
signed long __sched schedule_timeout(signed long timeout)
当前进程睡眠timeout个jiffies
rcu_read_lock
rcu_read_unlock
Linux 2.6新加入的rcu锁。读锁的加锁、解锁函数
参考http://www.ibm.com/developerworks/cn/linux/l-rcu
poll_freewait
poll_initwait
poll_wait
...
和文件IO,poll机制有关的几个函数,参考《Linux设备驱动(第三版)》6.3
tcp_poll
udp_poll
datagram_poll
协议层的poll函数