运用了static函数实现文件封装
提升变量访问效率的关键字register,该关键字暗示该变量可能被频繁访问,如果可能,请将值存放在寄存器中
内存集中管理,每个节点在取消后并没有立即释放内存,而是调用cleanup时统一释放
定时器的hash函数是异或结果求余生成key
static unsigned int
hash( Timer* t )
{
/* We can hash on the trigger time, even though it can change over
** the life of a timer via either the periodic bit or the tmr_reset()
** call. This is because both of those guys call l_resort(), which
** recomputes the hash and moves the timer to the appropriate list.
*/
return (
(unsigned int) t->time.tv_sec ^
(unsigned int) t->time.tv_usec ) % HASH_SIZE;
}
hash( Timer* t )
{
/* We can hash on the trigger time, even though it can change over
** the life of a timer via either the periodic bit or the tmr_reset()
** call. This is because both of those guys call l_resort(), which
** recomputes the hash and moves the timer to the appropriate list.
*/
return (
(unsigned int) t->time.tv_sec ^
(unsigned int) t->time.tv_usec ) % HASH_SIZE;
}
定时器的hash结构
定时器的数据结构是一个链式寻址的hash表,通过定时器的秒和微秒hash出相应的key,再遍历key下的双向链表进行查找、插入、删除。为什么采用链式寻址而不是数组存储的开放定址法,猜测是节点链表是有序链表,遍历/修改元素的效率已经很高,空间占用也会低于开放寻址。
定时器的插入:时间越早的定时器节点位置越靠前,新插入的节点可以追加在最前面、中间、也有可能是最后。
定时器的删除:如果是hashkey对应的首节点,将hash表key的首节点指向下一个节点。
定时器的重新排序:指定的定时器可以进行排序,删除该节点后计算hash值并插入hash表
定时器的初始化:hash表key的首节点重置,free_timers、alloc_count、active_count、free_count重置
定时器的创建:创建一个定时器节点,指定定时器的回调函数和回调函数的参数以及定时器的时间,获得一个初始化完成的定时器指针
定时器的超时:传入一个时间,如果没有供触发的定时器,返回一个NULL指针;如果在时间内有定时器被触发,那么返回一个时间为0的时间指针;如果有定时器,但没有到触发的时间点,返回剩余触发时间的时间指针
查找第一个超时的优化,hash表key下面的超时节点都是从早到晚排序的,因此查找超时只需要判断hash表key下的首节点是否超时,并从所有超时的首节点中找到最小的节点。
定时器的运行:hash表的所有链表都是有序的,因此遍历每个链表查找已经超时的定时器并调用定时器回调函数,链表下找到未触发的定时器就继续搜索下一个链表。如果已经触发的定时器是周期定时器,那么增加一定时间后重新排序该定时器链表;如果已经触发的定时器是非周期定时器,触发后取消该定时器。
定时器的重置:对一个已经存在的定时器节点重新设置定时器时间并调用定时器排序
定时器的取消:调用hash节点的删除方法,将该定时器删除并将激活的定时器数量-1。
定时器的清理:调用取消方法取消的定时器节点清理内存,每个取消的定时器都会从hash表中移除并保存在一个free_timers列队中,但没有当场清理内存,而是在调用清理方法时统一清理,能够提升程序效率。
定时器的销毁:彻底清理定时器队列,遍历hash节点和链表,取消所有的定时器后调用清理方法删除已申请的内存
定时器的状态报告:打印定时器hash的状况,生效的、空闲的、总的定时器数量,如果生效的+空闲的!=总的定时器数量,还会打印一条错误信息。