
文章插图
函数调用关系epoll_create每个eventpoll通过epoll_create()创建:
asmlinkage long sys_epoll_create(int size){int error, fd = -1;struct eventpoll *ep;DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)n",current, size));/** Sanity check on the size parameter, and create the internal data* structure ( "struct eventpoll" ).*/error = -EINVAL;/*为ep分配内存并进行初始化*/if (size <= 0 || (error = ep_alloc(&ep)) < 0) {fd = error;goto error_return;}/** Creates all the items needed to setup an eventpoll file. That is,* a file structure and a free file descriptor.*//*调用anon_inode_getfd新建一个struct file,也就是epoll可以看成一个文件(由* 于没有任何文件系统,为匿名文件) 。并且将主结构体struct eventpoll *ep放入* file->private项中进行保存(sys_epoll_ctl会取用)*/fd = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep);if (fd < 0)ep_free(ep);error_return:DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %dn",current, size, fd));return fd;}epoll_ctlasmlinkage long sys_epoll_ctl(int epfd, int op, int fd,struct epoll_event __user *event){int error;struct file *file, *tfile;struct eventpoll *ep;struct epitem *epi;struct epoll_event epds;DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p)n",current, epfd, op, fd, event));error = -EFAULT;/*判断参数合法性,将__user *event 复制给epds*/if (ep_op_has_event(op) &©_from_user(&epds, event, sizeof(struct epoll_event)))goto error_return;/* Get the "struct file *" for the eventpoll file */error = -EBADF;file = fget(epfd); /*epoll fd对应的文件对象*/if (!file)goto error_return;/* Get the "struct file *" for the target file */tfile = fget(fd); /*fd对应的文件对象*/if (!tfile)goto error_fput;/* The target file descriptor must support poll */error = -EPERM;if (!tfile->f_op || !tfile->f_op->poll)goto error_tgt_fput;.../** At this point it is safe to assume that the "private_data" contains* our own data structure.*/ep = file->private_data; /*在create时存入进去的(anon_inode_getfd),现在取用 。*/mutex_lock(&ep->mtx);/** Try to lookup the file inside our RB tree, Since we grabbed "mtx"* above, we can be sure to be able to use the item looked up by* ep_find() till we release the mutex.*/epi = ep_find(ep, tfile, fd); /*防止重复添加(在ep的红黑树中查找是否已经存在这个fd)*/switch (op) {case EPOLL_CTL_ADD: /*新增一个监听fd*/if (!epi) {epds.events |= POLLERR | POLLHUP; /*默认包含POLLERR和POLLHUP事件*/error = ep_insert(ep, &epds, tfile, fd); /*在ep的红黑树中插入这个fd对应的epitm结构体 。*/} else /*重复添加(在ep的红黑树中查找已经存在这个fd) 。*/error = -EEXIST;break;...}...return error;}其中ep_insert的实现如下:```cstatic int ep_insert(struct eventpoll *ep, struct epoll_event *event,struct file *tfile, int fd){int error, revents, pwake = 0;unsigned long flags;struct epitem *epi;struct ep_pqueue epq;error = -ENOMEM;/*分配一个epitem结构体来保存每个存入的fd*/if (!(epi = kmem_cache_alloc(epi_cache, GFP_KERNEL)))goto error_return;/* Item initialization follow here ... *//*初始化该结构体*/INIT_LIST_HEAD(&epi->rdllink);INIT_LIST_HEAD(&epi->fllink);INIT_LIST_HEAD(&epi->pwqlist);epi->ep = ep;ep_set_ffd(&epi->ffd, tfile, fd);epi->event = *event;epi->nwait = 0;epi->next = EP_UNACTIVE_PTR;/* Initialize the poll table using the queue callback */epq.epi = epi;/*安装poll回调函数*/init_poll_funcptr(&epq.pt, ep_ptable_queue_proc);/** Attach the item to the poll hooks and get current event bits.* We can safely use the file* here because its usage count has* been increased by the caller of this function. Note that after* this operation completes, the poll callback can start hitting* the new item.*//** 调用poll函数来获取当前事件位,其实是利用它来调用注册函数ep_ptable_queue_proc(poll_wait中调用) 。* 如果fd是套接字,f_op为socket_file_ops,poll函数是sock_poll() 。* 如果是TCP套接字的话,进而会调用到tcp_poll()函数 。此处调用poll函数查看当前文件描述符的状态,存储在revents中 。* 在poll的处理函数(tcp_poll())中,会调用sock_poll_wait(),*在sock_poll_wait()中会调用到epq.pt.qproc指向的函数,也就是ep_ptable_queue_proc() 。*/revents = tfile->f_op->poll(tfile, &epq.pt);/* Add the current item to the list of active epoll hook for this file */spin_lock(&tfile->f_ep_lock);list_add_tail(&epi->fllink, &tfile->f_ep_links);spin_unlock(&tfile->f_ep_lock);/** Add the current item to the RB tree. All RB tree operations are* protected by "mtx", and ep_insert() is called with "mtx" held.*/ep_rbtree_insert(ep, epi); /*将该epi插入到ep的红黑树中*//* We have to drop the new item inside our item list to keep track of it */spin_lock_irqsave(&ep->lock, flags);/* If the file is already "ready" we drop it inside the ready list *//** revents & event->events:刚才fop->poll的返回值中标识的事件有用户event关心的事件发生 。* !ep_is_linked(&epi->rdllink):epi的ready队列中有数据 。ep_is_linked用于判断队列是否为空 。*//* 如果要监视的文件状态已经就绪并且还没有加入到就绪队列中,则将当前的epitem加入到就绪队列中.如果有进程正在等待该文件的状态就绪,则唤醒一个等待的进程 。*/if ((revents & event->events) && !ep_is_linked(&epi->rdllink)) {/*将当前epi插入到ep->ready队列中 。*/list_add_tail(&epi->rdllink, &ep->rdllist);/* Notify waiting tasks that events are available *//* 如果有进程正在等待文件的状态就绪,也就是调用epoll_wait睡眠的进程正在等待,则唤醒一个等待进程 。waitqueue_active(q) 等待队列q中有等待的进程返回1,否则返回0 。*/if (waitqueue_active(&ep->wq))wake_up_locked(&ep->wq);/*如果有进程等待eventpoll文件本身(???)的事件就绪,则增加临时变量pwake的值,pwake的值不为0时,在释放lock后,会唤醒等待进程 。*/if (waitqueue_active(&ep->poll_wait))pwake++;}spin_unlock_irqrestore(&ep->lock, flags);/* We have to call this outside the lock */if (pwake)/*唤醒等待eventpoll文件状态就绪的进程*/ep_poll_safewake(&psw, &ep->poll_wait);DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_insert(%p, %p, %d)n",current, ep, tfile, fd));return 0;...}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Linux eBPF解析
- linux 国产操作系统deepin系统从安装到惊喜
- linux服务器垃圾清理记
- 2021 专业人士 Linux 系统 TOP 5
- linux中的makefile编写规则
- Linux服务器打造一个简单的文件共享系统
- 手相判断你的桃花从哪里来
- 求职|简历撰写最新指南
- 让额头变饱满有什么窍门
- Linux上使用tinyproxy快速搭建HTTP/HTTPS代理器
