当系统启动时,epoll进行初始化:
- static int __init eventpoll_init(void)
-
{
-
mutex_init(&pmutex);
-
ep_poll_safewake_init(&psw);
-
epi_cache = kmem_cache_create(“eventpoll_epi”,sizeof(struct epitem),
-
0,SLAB_HWCACHE_ALIGN|EPI_SLAB_DEBUG|
-
SLAB_PANIC,NULL);
-
pwq_cache = kmem_cache_create(“eventpoll_pwq”,sizeof(struct
-
eppoll_entry),0,EPI_SLAB_DEBUG|SLAB_PANIC,NULL);
-
-
return 0;
-
}
上面的代码实现一些数据结构的初始化,通过fs/eventpoll.c中的注释可以看出,有三种类型的锁机制使用场景:
1.epmutex(mutex):用户关闭文件描述符,但是没有调用EPOLL_CTL_DEL
2.ep->mtx(mutex):用户态与内核态的转换可能会睡眠
3.ep->lock(spinlock):内核态与具体设备中断过程中的转换,poll回调
接下来就是使用slab分配器动态分配内存,第一个结构为当系统中添加一个fd时,就创建一epitem结构体,内核管理的基本数据结构:
- struct epitem
-
{
-
struct rb_node rbn;//用于主结构管理的红黑树
-
struct list_head rdllink;//事件就绪队列
-
struct epitem *next;//用于主结构体中的链表
-
struct epoll_filefd ffd;//每个fd生成的一个结构
-
int nwait;//
-
struct list_head pwqlist;//poll等待队列
-
struct eventpoll *ep;//该项属于哪个主结构体
-
struct list_head fllink;//链接fd对应的file链表
-
struct epoll_event event;//注册的感兴趣的事件,也就是用户空间的epoll_event
-
}
而每个epoll
fd对应的主要数据结构为:
- struct eventpoll {
-
spin_lock_t lock;//对本数据结构的访问
-
struct mutex mtx;//防止使用时被删除
-
wait_queue_head_t wq;//sys_epoll_wait() 使用的等待队列
-
wait_queue_head_t poll_wait;//file->poll()使用的等待队列
-
struct list_head rdllist;//事件满足条件的链表
-
struct rb_root rbr;//用于管理所有fd的红黑树
-
struct epitem *ovflist;//将事件到达的fd进行链接起来发送至用户空间
-
}
该结构主要在epoll_create时进行创建:
- //原来使用的是hash表,所以有size,现在改为红黑树,故不使用.
-
long sys_epoll_create(int size)
-
{
-
int error,fd = -1;
-
struct eventpoll *ep;
-
struct inode *inode;
-
struct file *file;
-
-
….
-
error = -EINVAL;
-
//分配空间
-
if(size <= 0 || (error = ep_alloc(&ep)!=0))
-
goto errror_return;
-
//创建一个struct file结构,由于没有任何文件系统,为匿名文件,
-
并将主结构体放入file->private项中进行保存
-
error = anon_inode_getfd(&fd,&inode,&file,”[eventpoll]”,
-
&eventpoll_fops,ep);
-
if(error)
-
goto error_free;
-
return fd;
-
...
-
}
上面注册的操作eventpoll_fops定义如下:
- static const struct file_operations eventpoll_fops = {
-
.release = ep_eventpoll_release;
-
.poll = ep_eventpoll_poll,
-
}
这样说来,内核中维护了一棵红黑树,大致的结构如下:
阅读(593) | 评论(0) | 转发(0) |