免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3670 | 回复: 3
打印 上一主题 下一主题

[C] 分享自己最新改写的超时检查代码evtimer [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-11-04 13:18 |只看该作者 |倒序浏览
本帖最后由 redor 于 2010-11-04 13:31 编辑

后续的改进会更新在 https://sbase.googlecode.com/svn/trunk/devel/libsbase/
使用例子在evtimer.c main函数里, 在多线程使用中就只需要在主线程里或者独立的线程里作evtimer_check()就好了, 
超时的事件通过evtimer_add()添加的handler和arg返回, 
evtimer_add()注册的时候会返回一个evtimer_id 记住这个id 可以通过这个id更新timeout时间和删除超时检查.
最后evtimer_clean() 清理一下就OK, C++使用自行加C++兼容那个头就好了;
windows下使用在 把xmm_new() 改成 calloc() xmm_free() 改成free()
另外换掉那个mutex_lock() mutex_unlock() 就可以了. 我没写过windows的代码.
有bug的话请提交给我邮箱.sounos@gmail.com

  1. #ifndef _EVTIMER_H
  2. #define _EVTIMER_H
  3. typedef void (EVTCALLBACK)(void *);
  4. typedef struct _EVTNODE
  5. {
  6.     int id;
  7.     int ison;
  8.     off_t evusec;
  9.     void *arg;
  10.     EVTCALLBACK *handler;
  11.     struct _EVTNODE *prev;
  12.     struct _EVTNODE *next;
  13. }EVTNODE;
  14. #define  EVTNODE_LINE_NUM   1024
  15. #define  EVTNODE_LINE_MAX   102400
  16. typedef struct _EVTIMER
  17. {
  18.    int nevlist;
  19.    int ntimeout;
  20.    EVTNODE *evlist[EVTNODE_LINE_MAX];
  21.    EVTNODE *timeouts[EVTNODE_LINE_MAX];
  22.    EVTNODE *left;
  23.    EVTNODE *head;
  24.    EVTNODE *tail;
  25.    void *mutex;
  26. }EVTIMER;

  27. /* initialize evtimer */
  28. EVTIMER *evtimer_init();
  29. /* add event timer */
  30. int evtimer_add(EVTIMER *evtimer, off_t timeout, EVTCALLBACK *handler, void *arg);
  31. /* update event timer */
  32. int evtimer_update(EVTIMER *evtimer, int evid, off_t timeout, EVTCALLBACK *handler, void *arg);
  33. /* delete event timer */
  34. int evtimer_delete(EVTIMER *evtimer, int evid);
  35. /* check timeout */
  36. void evtimer_check(EVTIMER *evtimer);
  37. /* reset evtimer */
  38. void evtimer_reset(EVTIMER *evtimer);
  39. /* clean evtimer */
  40. void evtimer_clean(EVTIMER *evtimer);
  41. #define PEVTIMER(ptr) ((EVTIMER *)ptr)
  42. #define EVTIMER_INIT() evtimer_init()
  43. #define EVTIMER_ADD(ptr, timeout, evhandler, evarg) \
  44.     evtimer_add(PEVTIMER(ptr), (off_t)timeout, evhandler, evarg)
  45. #define EVTIMER_UPDATE(ptr, evid, timeout, evhandler, evarg) \
  46.     evtimer_update(PEVTIMER(ptr), evid, (off_t)timeout, evhandler, evarg)
  47. #define EVTIMER_DEL(ptr, evid) evtimer_delete(PEVTIMER(ptr), evid)
  48. #define EVTIMER_CHECK(ptr) evtimer_check(PEVTIMER(ptr))
  49. #define EVTIMER_RESET(ptr) evtimer_reset(PEVTIMER(ptr))
  50. #define EVTIMER_CLEAN(ptr) evtimer_clean(PEVTIMER(ptr))
  51. #endif
复制代码
evtimer.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <sys/time.h>
  6. #include "xmm.h"
  7. #include "evtimer.h"
  8. #include "mutex.h"
  9. /* evtimer push */
  10. void evtimer_push(EVTIMER *evtimer, EVTNODE *node)
  11. {
  12.     EVTNODE *tmp = NULL;
  13.     int evid = 0;

  14.     if(evtimer && node)
  15.     {
  16.         evid = node->id;
  17.         node->next = node->prev = NULL;
  18.         if(evtimer->tail  == NULL || evtimer->head == NULL)
  19.             evtimer->head = evtimer->tail = node;
  20.         else
  21.         {
  22.             if(node->evusec >= evtimer->tail->evusec)
  23.             {
  24.                 node->prev = evtimer->tail;
  25.                 evtimer->tail->next = node;
  26.                 evtimer->tail = node;
  27.             }
  28.             else if(node->evusec < evtimer->head->evusec)
  29.             {
  30.                 node->next = evtimer->head;
  31.                 evtimer->head->prev = node;
  32.                 evtimer->head = node;
  33.             }
  34.             else
  35.             {
  36.                 tmp = evtimer->tail->prev;
  37.                 while(tmp && tmp->evusec > node->evusec)
  38.                     tmp = tmp->prev;
  39.                 if(tmp)
  40.                 {
  41.                     node->next = tmp->next;
  42.                     node->prev = tmp;
  43.                     tmp->next = node;
  44.                     node->next->prev = node;
  45.                 }
  46.             }
  47.         }
  48.     }
  49.     return ;
  50. }

  51. /* add event timer */
  52. int evtimer_add(EVTIMER *evtimer, off_t timeout, EVTCALLBACK *handler, void *arg)
  53. {
  54.     int evid = -1, x = 0, i = 0;
  55.     struct timeval tv = {0};
  56.     EVTNODE *node = NULL;

  57.     if(evtimer && handler && timeout > 0)
  58.     {
  59.         MUTEX_LOCK(evtimer->mutex);
  60.         if((node = evtimer->left))
  61.         {
  62.             evtimer->left = node->next;
  63.         }
  64.         else
  65.         {
  66.             if((x = evtimer->nevlist) < EVTNODE_LINE_MAX
  67.                     && (node = (EVTNODE *)xmm_new(sizeof(EVTNODE) * EVTNODE_LINE_NUM)))
  68.             {
  69.                 evtimer->evlist[x] = node;
  70.                 evtimer->nevlist++;
  71.                 //fprintf(stdout, "%s::%d lines:%d\n", __FILE__, __LINE__, evtimer->nevlist);
  72.                 x *= EVTNODE_LINE_NUM;
  73.                 node[0].id = x;
  74.                 i = 1;
  75.                 while(i < EVTNODE_LINE_NUM)
  76.                 {
  77.                     node[i].id = i + x;
  78.                     node[i].next = evtimer->left;
  79.                     evtimer->left = &(node[i]);
  80.                     ++i;
  81.                 }
  82.             }
  83.         }
  84.         if(node)
  85.         {
  86.             evid = node->id;
  87.             node->handler = handler;
  88.             node->arg = arg;
  89.             node->ison = 1;
  90.             gettimeofday(&tv, NULL);
  91.             node->evusec = (off_t)(tv.tv_sec * 1000000ll + tv.tv_usec * 1ll) + timeout;
  92.             evtimer_push(evtimer, node);
  93.         }
  94.         MUTEX_UNLOCK(evtimer->mutex);
  95.     }
  96.     return evid;
  97. }

  98. /* update event timer */
  99. int evtimer_update(EVTIMER *evtimer, int evid, off_t timeout, EVTCALLBACK *handler, void *arg)
  100. {
  101.     EVTNODE *nodes = NULL, *node = NULL;
  102.     int x = 0, i = 0, ret = -1;
  103.     struct timeval tv = {0};

  104.     if(evtimer && evid >= 0 && evid < ((evtimer->nevlist+1) * EVTNODE_LINE_NUM))
  105.     {
  106.         MUTEX_LOCK(evtimer->mutex);
  107.         x = evid / EVTNODE_LINE_NUM;
  108.         i = evid % EVTNODE_LINE_NUM;
  109.         if((nodes = evtimer->evlist[x]) && (node = &(nodes[i])) && node->ison)
  110.         {
  111.             if(node->prev) node->prev->next = node->next;
  112.             if(node->next) node->next->prev = node->prev;
  113.             if(node == evtimer->head) evtimer->head = node->next;
  114.             if(node == evtimer->tail) evtimer->tail = node->prev;
  115.             node->handler = handler;
  116.             node->arg = arg;
  117.             gettimeofday(&tv, NULL);
  118.             node->evusec = (off_t)(tv.tv_sec * 1000000ll + tv.tv_usec * 1ll) + timeout;
  119.             evtimer_push(evtimer, node);
  120.             ret = 0;
  121.         }
  122.         MUTEX_UNLOCK(evtimer->mutex);
  123.     }
  124.     return ret;
  125. }

  126. /* delete event timer */
  127. int evtimer_delete(EVTIMER *evtimer, int evid)
  128. {
  129.     EVTNODE *nodes = NULL, *node = NULL;
  130.     int ret = -1, i = 0, x = 0;

  131.     if(evtimer && evid >= 0 && evid < ((evtimer->nevlist+1) * EVTNODE_LINE_NUM))
  132.     {
  133.         MUTEX_LOCK(evtimer->mutex);
  134.         x = evid / EVTNODE_LINE_NUM;
  135.         i = evid % EVTNODE_LINE_NUM;
  136.         if((nodes = evtimer->evlist[x]) && (node = &(nodes[i])) && node->ison)
  137.         {
  138.             //fprintf(stdout, "%s::%d delete evid:%d\n", __FILE__, __LINE__, evid);
  139.             if(node->prev) node->prev->next = node->next;
  140.             if(node->next) node->next->prev = node->prev;
  141.             if(node == evtimer->head) evtimer->head = node->next;
  142.             if(node == evtimer->tail) evtimer->tail = node->prev;
  143.             memset(node, 0, sizeof(EVTNODE));
  144.             node->id = evid;
  145.             node->next = evtimer->left;
  146.             evtimer->left = node;
  147.         }
  148.         MUTEX_UNLOCK(evtimer->mutex);
  149.     }
  150.     return ret;
  151. }

  152. /* check timeout */
  153. void evtimer_check(EVTIMER *evtimer)
  154. {
  155.     EVTCALLBACK *handler = NULL;
  156.     struct timeval tv = {0};
  157.     EVTNODE *node = NULL;
  158.     off_t now = 0;
  159.     int i = 0;

  160.     if(evtimer && evtimer->head)
  161.     {
  162.         MUTEX_LOCK(evtimer->mutex);
  163.         gettimeofday(&tv, NULL);
  164.         now = (off_t)(tv.tv_sec * 1000000ll + tv.tv_usec * 1ll);
  165.         evtimer->ntimeout = 0;
  166.         while(evtimer->ntimeout < EVTNODE_LINE_MAX
  167.                 && (node = evtimer->head) && node->evusec < now)
  168.         {
  169.             //if(node->handler) node->handler(node->arg);
  170.             if((evtimer->head = node->next))
  171.                 evtimer->head->prev = NULL;
  172.             else
  173.                 evtimer->tail = NULL;
  174.             evtimer->timeouts[evtimer->ntimeout++] = node;
  175.             node->next = node->prev = NULL;
  176.         }
  177.         MUTEX_UNLOCK(evtimer->mutex);
  178.         for(i = 0; i < evtimer->ntimeout; i++)
  179.         {
  180.             if((node = evtimer->timeouts[i]) && node->next == NULL && node->prev == NULL
  181.                     && node->ison && (handler = node->handler))
  182.                 handler(node->arg);
  183.         }
  184.     }
  185.     return ;
  186. }

  187. /* reset evtimer */
  188. void evtimer_reset(EVTIMER *evtimer)
  189. {
  190.     EVTNODE *tmp = NULL, *node = NULL;
  191.     int id = -1;

  192.     if(evtimer && (node = evtimer->head))
  193.     {
  194.         do
  195.         {
  196.             id = node->id;
  197.             tmp = node;
  198.             node = node->next;
  199.             memset(tmp, 0, sizeof(EVTNODE));
  200.             tmp->id = id;
  201.             tmp->next = evtimer->left;
  202.             evtimer->left = tmp;
  203.         }while(node);
  204.     }
  205.     return ;
  206. }

  207. /* clean evtimer */
  208. void evtimer_clean(EVTIMER *evtimer)
  209. {
  210.     int i = 0;

  211.     if(evtimer)
  212.     {
  213.         MUTEX_DESTROY(evtimer->mutex);
  214.         for(i = 0; i < evtimer->nevlist; i++)
  215.         {
  216.             xmm_free(evtimer->evlist[i], sizeof(EVTNODE) * EVTNODE_LINE_NUM);
  217.         }
  218.         xmm_free(evtimer, sizeof(EVTIMER));
  219.     }

  220.     return ;
  221. }

  222. /* intialize evtimer */
  223. EVTIMER *evtimer_init()
  224. {
  225.     EVTIMER *evtimer = NULL;

  226.     if((evtimer = (EVTIMER *)xmm_new(sizeof(EVTIMER))))
  227.     {
  228.         MUTEX_INIT(evtimer->mutex);
  229.     }
  230.     return evtimer;
  231. }

  232. #ifdef _DEBUG_EVTIMER
  233. void evtimer_handler(void *arg)
  234. {
  235.     fprintf(stdout, "active evtimer\n");
  236.     return ;
  237. }
  238. int main()
  239. {
  240.     EVTIMER *evtimer = NULL;
  241.     int i = 0, id = 0, max = 1000000;
  242.     off_t timeout = 10000000;

  243.     if((evtimer = evtimer_init()))
  244.     {
  245.         for(i = 0; i < max; i++)
  246.         {
  247.             timeout = random()%1000000000;
  248.             id = evtimer_add(evtimer, timeout, &evtimer_handler, NULL);
  249.             fprintf(stdout, "%d:%lu\n", id, (unsigned long)(timeout));
  250.         }
  251.         fprintf(stdout, "starting check()");
  252.         evtimer_check(evtimer);
  253.         fprintf(stdout, "over check()");
  254.         evtimer_reset(evtimer);
  255.         fprintf(stdout, "over reset()");
  256.         evtimer_clean(evtimer);
  257.     }
  258.     return 0;
  259. }
  260. #endif
复制代码

evtimer.zip

3.94 KB, 下载次数: 18

evtimer

论坛徽章:
1
CU十二周年纪念徽章
日期:2013-10-24 15:41:34
2 [报告]
发表于 2010-11-04 14:42 |只看该作者
看看。

论坛徽章:
0
3 [报告]
发表于 2010-11-04 18:12 |只看该作者
有一点不明白,这代码是用来干嘛的?
仅仅是check预定的项目有没有在一段时间后要执行吗?
坦白说,意义不大
因为所有的回调操作都是在你check的时候执行的,也就是说这些任务并不是在你设定的时间执行的。

我以前写过一个类似的 timequeue ,记时执行队列,写的很简陋,内部用select做定时器,到期的任务,pop出queue,然后调整这个queue里的每个任务的时间戳,再设定select超时等待。queue里按照时间戳排序
(可以优化成分时段更新时间戳--没必要都更新,占用了cpu),这个queue就比较符合我们需要,定时执行任务。

论坛徽章:
0
4 [报告]
发表于 2010-11-07 17:50 |只看该作者
本帖最后由 redor 于 2010-11-07 17:53 编辑
有一点不明白,这代码是用来干嘛的?
仅仅是check预定的项目有没有在一段时间后要执行吗?
坦白说,意义不 ...
ydfgic 发表于 2010-11-04 18:12



   你理解的基本不对 用来做超时检查的 不是用来作定时器的, 比如要检查一个fd是否一定时间内没有数据读写..... 相当于事件超时检查, libevent里也有一个,不过跟它那个实现不一样.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP