`
sunzixun
  • 浏览: 76052 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

<Linux Kernel>eventepoll

阅读更多

首先介绍一下Epoll 主要需要3个级别的锁

 

 * 1) epmutex   互斥锁mutex

 * 2) ep->mtx   互斥锁mutex

 * 3) ep->lock   自旋锁spinlock

 

需要的顺序是从1-3 . 

 

1 ) 需要自旋锁 : 是因为我们掌管着 poll 回调方法内部的资源 这些资源的触发可能发生在中断上下文 的wake_up 中 所以呢我们不能再poll 回调方法里面睡眠 因此自旋吧~

 

 

2 ) 在事件传输的循环中(内核空间--> 用户空间我们可以中断睡眠由通过一个 copy_to_user, 所以我们需要一个允许我们睡眠的锁 ,这就是mutex啦 

 

3 ) 他在事件传输的循环中被需要epoll_ctl(EPOLL_CTL_DEL) and during eventpoll_release_file()

 

然后呢,我们需要一个全局的mutex锁 ,来序列化 eventpoll_release_file()

 

 

举个例子 比如: ep_free().

ep_free() 需要这个锁 在epoll  file 清除的过程中 同样 eventpoll_release_file()也需要 比如以下情况

如果一个file 已经被压入 epoll 的集合里面 然后直接close 却没有通过poll_ctl(EPOLL_CTL_DEL).

 

 

 

最后放弃 ep->mux 而使用全局的 epmutex(ep->lock 一起工作 也是可能的

 

但是 使用 ep->mtx 将使接口具有可扩展性 需要持有epmutex 的事件往往很稀少 然而 

对于一个一个普通的操作  ep->mutex 将保证良好的扩展性

 

 

 

 

 

* Maximum number of nesting allowed inside epoll sets */\
Epoll 集合允许的最大嵌套数
#define EP_MAX_NESTS 4
Epoll 监听的最多事件 (庞大到可以忽视)
#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
 

 

 

 

 

 

我打算从系统调用入口开始分析 

 

/*
*这里的 SYSCALL_DEFINEx(name ,__VA_ARGS__)  其实就是通过一系列的宏变化 
*最后变成  asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__));
*这样是不是很眼熟了, 没错  "sys_xxx" linux Syscalls.h系统调用函数名的标准格式 直接
*对应unistd,h 中的调用号 , 直接对于 syscall(xx,xx) .. 不解释..
*/
SYSCALL_DEFINE1(epoll_create1, int, flags)
{
int error;
struct eventpoll *ep = NULL;
/*这里通过一个小技巧 ,能让编译的时候就发现代码开发过程中潜在的问题,而不是坐等*crash ,具体使用有各种不同的校验, 
*比如#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))  如果条件*满足就直接char[-1] 哈哈*/
BUILD_BUG_ON(EPOLL_CLOEXEC != O_CLOEXEC);
/*如果没有设置 EPOLL_CLOEXEC)  就直接返回 -EINVAL给上层 */
if (flags & ~EPOLL_CLOEXEC)
return -EINVAL;
/*
 *创建一个内部用的数据结构 struct eventpoll 
 */
error = ep_alloc(&ep);
if (error < 0)
return error;
/*开始前的准备 建立一个struct file 和file  fd	 */
error = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep,
 O_RDWR | (flags & O_CLOEXEC));
if (error < 0)
ep_free(ep);
return error;
}
 

 

 

 

 

然后就开始看看上面2个没讲到的函数 和一个重要的数据结构

 

 

/*还记得struct file里面那个神奇的 private_data么, 现在它就用来指向eventpoll 不用我说就知道, 这个结构是整个epoll操作的外部接口*/
struct eventpoll {
/* Protect the this structure access 自旋锁保护这个内部数据结构*/
spinlock_t lock;
/*
 *这个互斥锁用来确保 file fd 在epoll 使用他们的时候不能被移出, 在
 *1 event 集合循环的时候 2 file fd清除过程中 3 epoll fd 退出和epoll_ctl操作
 */
struct mutex mtx;
/* sys_epoll_wait() 用的等待队列 */
wait_queue_head_t wq;
/* file->poll() [驱动层接口] 用的等待队列*/
wait_queue_head_t poll_wait;
/* List of ready file descriptors 已经准备好的file fd链表 */
struct list_head rdllist;
/* RB tree root used to store monitored fd structs 
 *用来储存所有file fd 的红黑树的根*/
struct rb_root rbr;
/*
 * This is a single linked list that chains all the "struct epitem" that
 * happened while transfering ready events to userspace w/out
 * holding ->lock. 这是一个伟大复杂的结构。。。 形成一个包含 struct epitem  结构的单链表 , 在传输就绪事件到用户空间用到	 */
struct epitem *ovflist;
/* The user that created the eventpoll descriptor 
 	 *存放了建立这个 epoll fd用户的信息(进程数 挂起信号等等 总有一天会是成熟的跟踪系统) <看了很多代码不得不佩服老外,他们在正常的开发中 ,往往能为以后的调试 统计 分析留下接口,这才是做系统的人,而我们国内公司很多功能完成后 想增加点外围接口  想扩展一下,东改西改  本来性能就不高的代码 最后惨不忍睹>*/
struct user_struct *user;
};




/*然后就来先简单说一下 struct epitem *ovflist; 这个核心的和存储位置有关的数据结构*/
struct epitem {
/* RB tree node used to link this structure to the eventpoll RB tree 
    *在 eventpoll 红黑树种的节点*/
struct rb_node rbn;
/* List header used to link this structure to the eventpoll ready list 
     *用来连接本结构体到 eventpoll 中的就绪链表 ,没错就是上面的rdllist */
struct list_head rdllink;
/*
 * Works together "struct eventpoll"->ovflist in keeping the
 * single linked chain of items. 构成上面说的 ovflist  单链表
 */
struct epitem *next;
/* The file descriptor information this item refers to 除了来本身的file fd 还指向了对应的内核file 结构
* 后面会看到这个结构很有用
*/
struct epoll_filefd ffd;
/*   依附于 file()->poll 操作的活跃 eppoll_entry数目*/
int nwait;
/* List containing poll wait queues 把上面的队列串成链表*/
struct list_head pwqlist;
/* The "container" of this item  互相保留引用 */
struct eventpoll *ep;
/* List header used to link this item to the "struct file" items list  连接自身到struct file链表*/
struct list_head fllink;
/* The structure that describe the interested events and the source fd 描述这个file fd感兴趣的事件 */
struct epoll_event event;
};
 

 

 

 

好了先说简单说了说几个主要结构, 下面就来看  ep_alloc 用来创建内部用的数据结构 struct eventpoll 

 

 

static int ep_alloc(struct eventpoll **pep)
{
int error;
struct user_struct *user;
struct eventpoll *ep;
/*给当前 task_struct -> cred -> struct user_struct 增加引用计数*/
user = get_current_user();
error = -ENOMEM;
    /*内核缓冲池中 分配一个ep结果*/
ep = kzalloc(sizeof(*ep), GFP_KERNEL);
    /*当然一般情况下不会失败*/
if (unlikely(!ep))
goto free_uid;
    /*初始化 自旋锁 互斥锁 2条等待队列 一个就绪链表*/
spin_lock_init(&ep->lock);
mutex_init(&ep->mtx);
init_waitqueue_head(&ep->wq);
init_waitqueue_head(&ep->poll_wait);
INIT_LIST_HEAD(&ep->rdllist);
/*当然是根了*/
ep->rbr = RB_ROOT;
    /*表明没激活 但以初始化 惯用伎俩*/
ep->ovflist = EP_UNACTIVE_PTR;
ep->user = user;
    /*成功返回吧 ~*/
*pep = ep;
return 0;
free_uid:
free_uid(user); /*当然是减少引用基数 (原子的)*/
eturn error;
}
 

 

 

 

 

 

 

 

 

下面就是epoll_create里的最后一个关键函数了 anno_inode_getfd


这里传入了4个参数,最主要是


2 fops file fd 对应的文件操作结构

3 priv : struct  file 结构中的 private_data

 

其实 这里返回的不是一个传统意义上的inode节点 自然没有那么成熟和强大的功能

所有通过 annon_inode_getfd 创建的 file fd  都共享一个简单的inode 节点

这样就可以节省内核的内存 避免代码 在 file indoe dentry这些结构直接的复制 挂接

 

 

int anon_inode_getfd(const char *name, const struct file_operations *fops,
		     void *priv, int flags)
{
	int error, fd;
	struct file *file;

	error = get_unused_fd_flags(flags);
	if (error < 0)
		return error;
	fd = error;
/*只要知道这里创建了一个fild fd 依附上了一个匿名的static inode 节点 就可以了*/
	file = anon_inode_getfile(name, fops, priv, flags);
	if (IS_ERR(file)) {
		error = PTR_ERR(file);
		goto err_put_unused_fd;
	}
/*这里用了rcu 锁 就为了把file结构安装在fdtable表上 */
	fd_install(fd, file);

	return fd;

err_put_unused_fd:
	put_unused_fd(fd);
	return error;
}

 

 

 

 

好了 相信大家看了上面的有点晕,  其实很明显因为 epoll_create的 描述符 是epoll自己用的并没有任何实体对应 ,所以呢 就用了anon_inode_getfd ,所以大家会发现在 proc fd里面会看到一个 


 annon_inode:[eventpoll]  是不是和上面的入参  很像呢, 哈哈   proc 文件系统就是这个德性

 

里面的目录阿 ,名字啊  都是跟着内核层次 名字来了 你会越看越熟悉.... (是不是有点废话) 

 

 

 

待续..... 

 

 

 

分享到:
评论

相关推荐

    itext 7.rar

    &lt;artifactId&gt;kernel&lt;/artifactId&gt; &lt;version&gt;7.0.4&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;com.itextpdf&lt;/groupId&gt; &lt;artifactId&gt;io&lt;/artifactId&gt; &lt;version&gt;7.0.4&lt;/version&gt; &lt;/dependency&gt; ...

    Self.Service.Linux.Mastering.the.Art.of.Problem.Determination

    &lt;br/&gt;如果你想了解如何使用strace, gdb, how to compiling kernel, gdb, kdb等工具解决从应用层服务问题到核心级故障问题的话,成为处理linux问题的专家,这是一个很好的起点。&lt;br/&gt;&lt;br/&gt;If you use Linux ...

    Linux.Certification.in.a.Nutshell.2nd.Edition

    Major topics include:&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;GNU and Unix commands&lt;br&gt;&lt;br&gt;Linux installation and package management&lt;br&gt;&lt;br&gt;Devices, filesystems, and kernel configuration&lt;br&gt;&lt;br&gt;Text editing, processing, and ...

    linux howto中文合集

    html&lt;br&gt;ISP-Connectivity-html&lt;br&gt;ISP-Hookup-HOWTO-html&lt;br&gt;Java-CGI-HOWTO-html&lt;br&gt;Kerneld&lt;br&gt;Kernel-HOWTO-html&lt;br&gt;Large-Disk-html&lt;br&gt;LinuxDoc+Emacs+Ispell-HOWTO-html&lt;br&gt;Linux+DOS+Win95&lt;br&gt;Linux+FreeBSD...

    9500m gs mac os x 显卡 kext

    &lt;key&gt;Kernel&lt;/key&gt; &lt;string&gt;mach_kernel&lt;/string&gt; &lt;key&gt;VBIOS&lt;/key&gt; &lt;string&gt;y&lt;/string&gt; &lt;key&gt;VideoROM&lt;/key&gt; &lt;string&gt;/Extra/nvidia.rom&lt;/string&gt; &lt;/dict&gt; &lt;/plist&gt; 将显卡的bios文件名修改为nvidia.rom,...

    GNU Linux Application Programming

    including useful shell commands &lt;br/&gt;Introduces developers to GNU/Linux from the lowest layers (kernel, device drivers, modules) to the user layer (applications, libraries, tools) &lt;br/&gt;Explores the ...

    Linux 可卸载内核模块完全指南

    第一部分 基础知识 &lt;br&gt;1.1 什么是LKMs &lt;br&gt;1.2 什么是系统调用 &lt;br&gt;1.3 什么是内核符号表(Kernel-Symbol-Table) &lt;br&gt;1.4 如何实现从用户空间到内核空间的转换 &lt;br&gt;1.5 使用用户空间函数的方法 &lt;br&gt;1.6 常用内核空间...

    Sams.Ubuntu.Unleashed.Aug.2006.part2

    &lt;br&gt;Part V: Ubuntu Housekeeping&lt;br&gt; Chapter 31 Securing your Machines&lt;br&gt; Chapter 32 Performance Tuning&lt;br&gt; Chapter 33 Command Line Masterclass&lt;br&gt; Chapter 34 Advanced apt&lt;br&gt; Chapter 35 Kernel and ...

    linux双网卡驱动源码(enc28j60).zip

    #include &lt;linux/kernel.h&gt; #include &lt;linux/types.h&gt; #include &lt;linux/fcntl.h&gt; #include &lt;linux/interrupt.h&gt; #include &lt;linux/slab.h&gt; #include &lt;linux/string.h&gt; #include &lt;linux/errno.h&gt; #include &lt;linux/init...

    CSharp操作ini文件完美版_附带ini介绍

    /// &lt;param name="retVal"&gt;key所对应的值,如果该key不存在则返回空值&lt;/param&gt; /// &lt;param name="size"&gt;返回值允许的大小&lt;/param&gt; /// &lt;param name="filePath"&gt;INI文件的完整路径和文件名&lt;/param&gt; /// &lt;returns&gt;...

    Source code for "µC/OS-II 2.52"

    µC/OS-II can manage up to 255 tasks and provides the following services:&lt;br&gt;&lt;br&gt;Semaphores &lt;br&gt;Mutual Exclusion Semaphores (to reduce priority inversions) &lt;br&gt;Event Flags &lt;br&gt;Message Mailboxes &lt;br&gt;...

    基于C的firewall

    这是一个简单的基于C语言的防火墙,#include &lt;linux/kernel.h&gt; #include &lt;linux/ip.h&gt; #include &lt;linux/module.h&gt; #include &lt;linux/netdevice.h&gt; #include &lt;linux/netfilter.h&gt; #include &lt;linux/netfilter_ipv4.h&gt; #...

    WinDBG(微软开发的免费源码级调试工具) zkacb汉化版(8.16 update!)

    WinDbg是微软开发的免费源码级调试工具。Windbg可以用于Kernel模式调试和...各取所需吧&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;http://www.microsoft.com/whdc/DevTools/Debugging/default.mspx&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;安装文件下载地址...

    Embedded Linux Primer

    Book Description&lt;br&gt;&lt;br&gt;Comprehensive Real-World Guidance for Every Embedded Developer and Engineer&lt;br&gt;&lt;br&gt;This book brings together indispensable knowledge for building efficient, high-value, Linux-...

    麒麟Linux kernel本地权限提升漏洞(CVE-2022-0847)漏洞补丁及相关依赖包1

    Linux kernel本地权限提升漏洞(CVE-2022-0847)漏洞补丁及相关依赖包1Linux kernel本地权限提升漏洞(CVE-2022-0847)漏洞补丁及相关依赖包1Linux kernel本地权限提升漏洞(CVE-2022-0847)漏洞补丁及相关依赖包1Linux ...

    Understanding the Linux Kernel pdf

    4. 《UnderStanding The Linux Kernel 3rd Edition V413HAV.pdf》:这正是标题中提到的《理解Linux内核》第三版,书中详尽介绍了Linux 2.6.x版本内核的设计和实现,包括调度程序、内存管理、文件系统、网络协议栈等...

    linux目录架构

    / 根目录 &lt;br&gt;/bin 常用的命令 binary file 的目錄 &lt;br&gt;/boot 存放系统启动时必须读取的档案,包括核心 (kernel) 在内 &lt;br&gt; /boot/grub/menu.lst GRUB设置 &lt;br&gt; /boot/vmlinuz 内核 &lt;br&gt; /boot/initrd 核心解壓縮所...

    fastboot-LT18i

    boot &lt;kernel&gt; [ &lt;ramdisk&gt; ] download and boot kernel flash:raw boot &lt;kernel&gt; [ &lt;ramdisk&gt; ] create bootimage and flash it devices list all connected devices reboot reboot device normally reboot-...

    outpost firewall4 win2003 sp2 补丁(x86)

    &lt;br&gt;Click Browse and browse to the folder &lt;br&gt;\Program Files\Agnitum\Outpost Firewall\Kernel\&lt;br&gt;&lt;br&gt;Click Next and click "Yes" to replace the file. &lt;br&gt;Click Finish and reboot your PC in Normal mode...

Global site tag (gtag.js) - Google Analytics