出处: http://blog.csdn.net/luotuo44/article/details/38424173
相关结构体:
因为event_signal_map结构体实在太简单了,所以不像event_io_map那样,有一个专门的文件。由于没有专门的文件,那么只能从蛛丝马迹上探索这个event_signal_map结构了。
通过一些搜索,可以得到与event_signal_map相关联的一些结构体有下面这些:
相对于event_io_map是一个哈希表,event_signal_map是一个数组。并且entries虽然是void**,但实际它是一个structevmap_signal指针数组。而evmap_signal成员只有一个TAILQ_HEAD (event_list, event);
由上面这些结构配合得到的结构如下所示:
从上图可以看到,event_signal_map结构体指向了一个evmap_signal指针数组,而evmap_signal结构体可以说就是一个TAILQ_QUEUE队列的队列头。通过TAILQ_QUEUE队列和图中的结构,event_signal_map就可以把event结构体都关联并管理起来。
上图中会有一个event结构体队列,原因和前一篇博文是一样的。因为同一个文件描述符fd或者信号值sig是可以多次调用event_new、event_add函数的。即存在一对多。这个队列就是把同一个fd或者sig的event连起来,方便管理。
操作函数:
虽然从上图看到event_signal_map结构是比较简单,现在还是要看一下与event_signal_map相关联的函数。先看一个内存分配函数。
在非Windows系统中,event_io_map被定义成event_signal_map,此时slot将是文件描述符fd。但对于这些遵循POSIX标准的OS来说,fd都是从0递增的比较小的值。所以代码中的while( nentrie <= slot ) nentries <<= 1; 并不会很大。对于slot为一个信号值,最大也就只有32。所以总得来说,nentries的值并不会太大。
从上面的代码也可以想到,对于参数slot,它要么是信号值sig,要么是文件描述符fd。而event_signal_map要求的数组长度一定要大于slot。那么之后给定一个sig或者fd,就可以直接通过下标操作快速定位了。这是因为一个sig或者fd就对应在数组中占有一个位置,并且sig或者fd的值等于其在数组位置的下标值。这种方式无论是管理还是代码复杂度都要比前一篇博文说到的哈希表要简单。
在Libevent中的应用:
同event_io_map一样,event_signal_map同样也是有event_signal_add函数的。不过后者比前者简单了很多。
同样,GET_SIGNAL_SLOT_AND_CTOR宏的作用就是让ctx指向structevmap_signal结构体中的TAILQ_HEAD。这样就可以使用TAILQ_INSERT_TAIL宏,把ev变量插入到队列中。如果有现成的struct evmap_signal就直接使用,没有的话就新建一个。
有一点要提出,虽然前一篇博文提到在非Windows系统中,event_io_map也被定义成了event_signal_map,但实际上他们并不会由链表连在一起。因为在event_base结构体中,分别有struct event_io_map变量io和event_signal_map变量sigmap。所有的io类型的event结构体会被放到io中,而信号类型的event则会被放到sigmap变量中。