http://liu1227787871.blog.163.com/blog/static/205363197201281215457217/
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINEx(x, sname, ...) __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#define __SYSCALL_DEFINEx(x, name, ...) asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))
所以:
SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds , int, timeout_msecs)
就相当于:
asmlinkage long sys_poll( poll, struct pollfd __user *, ufds, unsigned int, nfds , int, timeout_msecs)
在用户空间执行poll函数的时候,会调用系统函数sys_poll,也就是
SYSCALL_DEFINE3,于是我们开始内核分析:
SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds , int, timeout_msecs)
//设置超时时间
poll_select_set_timeout(to, timeout_msecs / MSEC_PER_SEC, NSEC_PER_MSEC * (timeout_msecs % MSEC_PER_SEC));
do_sys_poll(ufds, nfds, to);
poll_initwait(&table);
init_poll_funcptr(&pwq->pt, __pollwait);
//也就是说:pwq->pt->_qproc=__pollwait,__pollwait用于将当前进程加入等待队列
//__pollwait函数在我们注册的poll函数里面会调用
pt->_qproc = qproc;
do_poll(nfds, head, &table, end_time);
我们贴出do_poll的部分内核代码:
static int do_poll(unsigned int nfds, struct poll_list *list, struct poll_wqueues *wait, struct timespec *end_time)
{
for (;;) {
struct poll_list *walk;
for (walk = list; walk != NULL; walk = walk->next) {
struct pollfd * pfd, * pfd_end;
pfd = walk->entries;
pfd_end = pfd + walk->len;
//这个循环是针对多个进程的
for (; pfd != pfd_end; pfd++) {
//这个函数就是调用我们在驱动里面实现的poll函数,我们下面会贴出部分代码
//只要有一个进程的返回值不为0,count就不为0
if (do_pollfd(pfd, pt)) {
count++;
pt->_qproc = NULL;
}
}
} //end of for (walk = list; walk != NULL; walk = walk->next)
pt->_qproc = NULL;
if (!count) {
count = wait->error;
if (signal_pending(current))
count = -EINTR;
}
//一旦count不为0或者超时就会跳出循环,也就是应用程序返回了
if (count || timed_out)
break;
if (end_time && !to) {
expire = timespec_to_ktime(*end_time);
to = &expire;
}
//如过count仍是0的话,就会在这里休眠一段时间,然后再次循环
if (!poll_schedule_timeout(wait, TASK_INTERRUPTIBLE, to, slack))
timed_out = 1;
}//end of for (;;)
return count;
}
static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
{
unsigned int mask;
mask = file->f_op->poll(file, pwait);
//这就是调用我们注册的poll函数
//如果mask 与pollfd->events相同就能保证mask不为0
mask &= pollfd->events | POLLERR | POLLHUP;
return mask;
}
下面我们总结一下poll机制:
在用户空间调用poll函数,然后会跳转进内核;之后会指向我们注册的poll函数,在poll函数里面我们会放一条指令:poll_wait,poll_wait里面会调用__pollwait函数将当前进程放入等待队列,但是这是并没有休眠,只是加入队列;如果没有发生我们想要的事件的话,我们要使返回值为0,这时就会进入休眠状态;一旦发生了我们想要的时间的话,我们可以唤醒进程!比如我们下一节要写的按键驱动程序,如果发生了按键按下,就会在中断函数里面唤醒进程!