Chinaunix首页 | 论坛 | 博客
  • 博客访问: 53562
  • 博文数量: 8
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 75
  • 用 户 组: 普通用户
  • 注册时间: 2013-05-11 20:04
文章分类
文章存档

2017年(2)

2016年(3)

2014年(2)

2013年(1)

我的朋友

分类: C/C++

2016-06-07 22:15:59

本文章针对linux环境下的libev进行分析。

下面贴出测试程序,根据该程序进行分析

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <ev.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>

  5. void call_(struct ev_loop * ploop,ev_io * io_w,int e)
  6. {
  7.     char buf[1024];
  8.     int n = read(io_w->fd,buf,sizeof(buf));
  9.     buf[n] = '\0';
  10.     printf("%s",buf);
  11. }

  12. int main(int argc,char ** argv)
  13. {
  14.     struct ev_loop * ploop = ev_loop_new();
  15.     if(ploop == NULL)
  16.     {
  17.         printf("ploop is null \n");
  18.         return -1 ;
  19.     }
  20.     struct ev_io io_w;
  21.     ev_io_init(&io_w,call_,0,EV_READ);
  22.     ev_io_start(ploop,&io_w);
  23.     ev_run(ploop,0);

  24. }
编译命令:   g++ -g -o test  test.cxx -lev

下面针对每一步进行分析:
在ev_loop_new()这一步,函数如下:


点击(此处)折叠或打开

  1. struct ev_loop * ecb_cold
  2. ev_loop_new (unsigned int flags) EV_THROW
  3. {
  4.   EV_P = (struct ev_loop *)ev_malloc (sizeof (struct ev_loop));//为指针分配空间

  5.   memset (EV_A, 0, sizeof (struct ev_loop));//将结构清0 
  6.   loop_init (EV_A_ flags);//初始化

  7.   if (ev_backend (EV_A)) //判断loop有没有初始化到epoll/poll/select等多路复用的接口。
  8.     return EV_A;

  9.   ev_free (EV_A);
  10.   return 0;
  11. }
ev_malloc可以看出,是分配内存的函数。具体的流程,通过查找,定义如下:

点击(此处)折叠或打开

  1. #define ev_malloc(size) ev_realloc (0, (size))

点击(此处)折叠或打开

  1. inline_speed void *
  2. ev_realloc (void *ptr, long size)
  3. {
  4.   ptr = alloc (ptr, size);

  5.   if (!ptr && size)//若未分配的空间
  6.     {
  7. #if EV_AVOID_STDIO
  8.       ev_printerr ("(libev) memory allocation failed, aborting.\n");
  9. #else
  10.       fprintf (stderr, "(libev) cannot allocate %ld bytes, aborting.", size);
  11. #endif
  12.       abort ();
  13.     }

  14.   return ptr;
  15. }
在上述代码中,ev_realloc主要调用了alloc函数,alloc函数如下:

点击(此处)折叠或打开

  1. static void *
  2. ev_realloc_emul (void *ptr, long size) EV_THROW
  3. {
  4.   /* some systems, notably openbsd and darwin, fail to properly
  5.    * implement realloc (x, 0) (as required by both ansi c-89 and
  6.    * the single unix specification, so work around them here.
  7.    * recently, also (at least) fedora and debian started breaking it,
  8.    * despite documenting it otherwise.
  9.    */

  10.   if (size)
  11.     return realloc (ptr, size);

  12.   free (ptr);
  13.   return 0;
  14. }

  15. static void *(*alloc)(void *ptr, long size) EV_THROW = ev_realloc_emul;

即,alloc为一个函数指针,被赋值为realloc.


下面分析loop_init函数的过程

点击(此处)折叠或打开

  1. static void noinline ecb_cold
  2. loop_init (EV_P_ unsigned int flags) EV_THROW
  3. {
  4.   if (!backend)
  5.     {
  6.       origflags = flags;

  7. #if EV_USE_REALTIME //系统是否支持CLOCK_REALTIM
  8.       if (!have_realtime)
  9.         {
  10.           struct timespec ts;

  11.           if (!clock_gettime (CLOCK_REALTIME, &ts))
  12.             have_realtime = 1;
  13.         }
  14. #endif

  15. #if EV_USE_MONOTONIC //系统是否支持CLOCK_MONOTONI,不会随系统时间的变化而变化
  16.       if (!have_monotonic)
  17.         {
  18.           struct timespec ts;

  19.           if (!clock_gettime (CLOCK_MONOTONIC, &ts))
  20.             have_monotonic = 1;
  21.         }
  22. #endif

  23.       /* pid check not overridable via env */
  24. #ifndef _WIN32
  25.       if (flags & EVFLAG_FORKCHECK)
  26.         curpid = getpid ();
  27. #endif

  28.       if (!(flags & EVFLAG_NOENV)
  29.           && !enable_secure ()
  30.           && getenv ("LIBEV_FLAGS"))
  31.         flags = atoi (getenv ("LIBEV_FLAGS"));

  32.       ev_rt_now = ev_time ();
  33.       mn_now = get_clock ();
  34.       now_floor = mn_now;
  35.       rtmn_diff = ev_rt_now - mn_now;
  36. #if EV_FEATURE_API
  37.       invoke_cb = ev_invoke_pending;
  38. #endif

  39.       io_blocktime = 0.;
  40.       timeout_blocktime = 0.;
  41.       backend = 0;
  42.       backend_fd = -1;
  43.       sig_pending = 0;
  44. #if EV_ASYNC_ENABLE
  45.       async_pending = 0;
  46. #endif
  47.       pipe_write_skipped = 0;
  48.       pipe_write_wanted = 0;
  49.       evpipe [0] = -1;
  50.       evpipe [1] = -1;
  51. #if EV_USE_INOTIFY
  52.       fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2;
  53. #endif
  54. #if EV_USE_SIGNALFD
  55.       sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1;
  56. #endif

  57.       if (!(flags & EVBACKEND_MASK))
  58.         flags |= ev_recommended_backends (); //得到系统中支持哪些方式select,poll,epoll等 ,我的系统是linux,因此三者都有,该处值为7

  59. #if EV_USE_IOCP
  60.       if (!backend && (flags & EVBACKEND_IOCP )) backend = iocp_init (EV_A_ flags);
  61. #endif
  62. #if EV_USE_PORT
  63.       if (!backend && (flags & EVBACKEND_PORT )) backend = port_init (EV_A_ flags);
  64. #endif
  65. #if EV_USE_KQUEUE
  66.       if (!backend && (flags & EVBACKEND_KQUEUE)) backend = kqueue_init (EV_A_ flags);
  67. #endif
  68. #if EV_USE_EPOLL
  69.       if (!backend && (flags & EVBACKEND_EPOLL )) backend = epoll_init (EV_A_ flags);//使用epoll初始化,后面因为此处backend被初始化成功后,!backend为假,不会再进行初始化。
  70. #endif
  71. #if EV_USE_POLL
  72.       if (!backend && (flags & EVBACKEND_POLL )) backend = poll_init (EV_A_ flags);
  73. #endif
  74. #if EV_USE_SELECT
  75.       if (!backend && (flags & EVBACKEND_SELECT)) backend = select_init (EV_A_ flags);
  76. #endif

  77.       ev_prepare_init (&pending_w, pendingcb); //此处等同于ev_init(&pending_w,pendingcb)

  78. #if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE
  79.       ev_init (&pipe_w, pipecb);
  80.       ev_set_priority (&pipe_w, EV_MAXPRI);//设置优先级
  81. #endif
  82.     }
  83. }

在loop_init中,最重要的函数是epoll_init/poll_init/select_init
下面以epoll_init来例进行说明


点击(此处)折叠或打开

  1. int inline_size
  2. epoll_init (EV_P_ int flags)
  3. {
  4. #ifdef EPOLL_CLOEXEC
  5.   backend_fd = epoll_create1 (EPOLL_CLOEXEC);

  6.   if (backend_fd < 0 && (errno == EINVAL || errno == ENOSYS))
  7. #endif
  8.     backend_fd = epoll_create (256); //epoll_create初始化backend_fd

  9.   if (backend_fd < 0)
  10.     return 0;

  11.   fcntl (backend_fd, F_SETFD, FD_CLOEXEC);

  12.   backend_mintime = 1e-3; /* epoll does sometimes return early, this is just to avoid the worst */
  13.   backend_modify = epoll_modify;//修改事件调用函数,内部调用了epoll_ctl
  14.   backend_poll = epoll_poll;//调用epoll_poll来返回事件列表,epoll_poll内部调用了epoll_wait

  15.   epoll_eventmax = 64; /* initial number of events receivable per poll */
  16.   epoll_events = (struct epoll_event *)ev_malloc (sizeof (struct epoll_event) * epoll_eventmax);

  17.   return EVBACKEND_EPOLL;
  18. }

下面对ev_io_init进行说明

点击(此处)折叠或打开

  1. #define ev_io_init(ev,cb,fd,events) do { ev_init ((ev), (cb)); ev_io_set ((ev),(fd),(events)); } while (0)

点击(此处)折叠或打开

  1. #define ev_init(ev,cb_) do { \
  2.   ((ev_watcher *)(void *)(ev))->active = \
  3.   ((ev_watcher *)(void *)(ev))->pending = 0; \
  4.   ev_set_priority ((ev), 0); \
  5.   ev_set_cb ((ev), cb_); \
  6. } while (0)

点击(此处)折叠或打开

  1. #define ev_io_set(ev,fd_,events_) do { (ev)->fd = (fd_); (ev)->events = (events_) | EV__IOFDSET; } while (0)

点击(此处)折叠或打开

  1. # define ev_set_cb(ev,cb_) (ev_cb_ (ev) = (cb_), memmove (&((ev_watcher *)(ev))->cb, &ev_cb_ (ev), sizeof (ev_cb_ (ev))))

点击(此处)折叠或打开

  1. #define ev_cb_(ev) (ev)->cb /* rw */

准确地说,ev_io_init不是一个函数,是一个宏。
ev_set_cb(ev,cb_) 最终变成了 (ev)->cb = cb_,memmove(&((ev_watcher *)(ev))->cb,&(ev)->cb,sizeof((ev)->cb))

下面对ev_io_start进行说明

点击(此处)折叠或打开

  1. void noinline
  2. ev_io_start (EV_P_ ev_io *w) EV_THROW
  3. {
  4.   int fd = w->fd;

  5.   if (expect_false (ev_is_active (w)))
  6.     return;

  7.   assert (("libev: ev_io_start called with negative fd", fd >= 0));
  8.   assert (("libev: ev_io_start called with illegal event mask", !(w->events & ~(EV__IOFDSET | EV_READ | EV_WRITE))));

  9.   EV_FREQUENT_CHECK;

  10.   ev_start (EV_A_ (W)w, 1);
  11.   array_needsize (ANFD, anfds, anfdmax, fd + 1, array_init_zero);
  12.   wlist_add (&anfds[fd].head, (WL)w); //将w加入到anfds链表中

  13.   /* common bug, apparently */
  14.   assert (("libev: ev_io_start called with corrupted watcher", ((WL)w)->next != (WL)w));

  15.   fd_change (EV_A_ fd, w->events & EV__IOFDSET | EV_ANFD_REIFY);
  16.   w->events &= ~EV__IOFDSET;

  17.   EV_FREQUENT_CHECK;
  18. }


点击(此处)折叠或打开

  1. inline_size void
  2. pri_adjust (EV_P_ W w)
  3. {
  4.   int pri = ev_priority (w);
  5.   pri = pri < EV_MINPRI ? EV_MINPRI : pri;
  6.   pri = pri > EV_MAXPRI ? EV_MAXPRI : pri;
  7.   ev_set_priority (w, pri);
  8. }

  9. inline_speed void
  10. ev_start (EV_P_ W w, int active)
  11. {
  12.   pri_adjust (EV_A_ w);
  13.   w->active = active;
  14.   ev_ref (EV_A);
  15. }

点击(此处)折叠或打开

  1. void
  2. ev_ref (EV_P) EV_THROW
  3. {
  4.   ++activecnt;
  5. }

下面是ev_run调用的过程

点击(此处)折叠或打开

  1. int
  2. ev_run (EV_P_ int flags)
  3. {
  4. #if EV_FEATURE_API
  5.   ++loop_depth;
  6. #endif

  7.   assert (("libev: ev_loop recursion during release detected", loop_done != EVBREAK_RECURSE));

  8.   loop_done = EVBREAK_CANCEL;

  9.   EV_INVOKE_PENDING; /* in case we recurse, ensure ordering stays nice and clean */

  10.   do
  11.     {
  12. #if EV_VERIFY >= 2
  13.       ev_verify (EV_A);
  14. #endif

  15. #ifndef _WIN32
  16.       if (expect_false (curpid)) /* penalise the forking check even more */
  17.         if (expect_false (getpid () != curpid))
  18.           {
  19.             curpid = getpid ();
  20.             postfork = 1;
  21.           }
  22. #endif

  23. #if EV_FORK_ENABLE
  24.       /* we might have forked, so queue fork handlers */
  25.       if (expect_false (postfork))
  26.         if (forkcnt)
  27.           {
  28.             queue_events (EV_A_ (W *)forks, forkcnt, EV_FORK);
  29.             EV_INVOKE_PENDING;
  30.           }
  31. #endif

  32. #if EV_PREPARE_ENABLE
  33.       /* queue prepare watchers (and execute them) */
  34.       if (expect_false (preparecnt))
  35.         {
  36.           queue_events (EV_A_ (W *)prepares, preparecnt, EV_PREPARE);
  37.           EV_INVOKE_PENDING;
  38.         }
  39. #endif

  40.       if (expect_false (loop_done))
  41.         break;

  42.       /* we might have forked, so reify kernel state if necessary */
  43.       if (expect_false (postfork))
  44.         loop_fork (EV_A);

  45.       /* update fd-related kernel structures */
  46.       fd_reify (EV_A);

  47.       /* calculate blocking time */
  48.       {
  49.         ev_tstamp waittime = 0.;
  50.         ev_tstamp sleeptime = 0.;

  51.         /* remember old timestamp for io_blocktime calculation */
  52.         ev_tstamp prev_mn_now = mn_now;

  53.         /* update time to cancel out callback processing overhead */
  54.         time_update (EV_A_ 1e100);

  55.         /* from now on, we want a pipe-wake-up */
  56.         pipe_write_wanted = 1;

  57.         ECB_MEMORY_FENCE; /* make sure pipe_write_wanted is visible before we check for potential skips */

  58.         if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt || pipe_write_skipped)))
  59.           {
  60.             waittime = MAX_BLOCKTIME;

  61.             if (timercnt)
  62.               {
  63.                 ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now;
  64.                 if (waittime > to) waittime = to;
  65.               }

  66. #if EV_PERIODIC_ENABLE
  67.             if (periodiccnt)
  68.               {
  69.                 ev_tstamp to = ANHE_at (periodics [HEAP0]) - ev_rt_now;
  70.                 if (waittime > to) waittime = to;
  71.               }
  72. #endif

  73.             /* don't let timeouts decrease the waittime below timeout_blocktime */
  74.             if (expect_false (waittime < timeout_blocktime))
  75.               waittime = timeout_blocktime;

  76.             /* at this point, we NEED to wait, so we have to ensure */
  77.             /* to pass a minimum nonzero value to the backend */
  78.             if (expect_false (waittime < backend_mintime))
  79.               waittime = backend_mintime;

  80.             /* extra check because io_blocktime is commonly 0 */
  81.             if (expect_false (io_blocktime))
  82.               {
  83.                 sleeptime = io_blocktime - (mn_now - prev_mn_now);

  84.                 if (sleeptime > waittime - backend_mintime)
  85.                   sleeptime = waittime - backend_mintime;

  86.                 if (expect_true (sleeptime > 0.))
  87.                   {
  88.                     ev_sleep (sleeptime);
  89.                     waittime -= sleeptime;
  90.                   }
  91.               }
  92.           }

  93. #if EV_FEATURE_API
  94.         ++loop_count;
  95. #endif
  96.         assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */
  97.         backend_poll (EV_A_ waittime);//调用多路复用函数
  98.         assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */

  99.         pipe_write_wanted = 0; /* just an optimisation, no fence needed */

  100.         ECB_MEMORY_FENCE_ACQUIRE;
  101.         if (pipe_write_skipped)
  102.           {
  103.             assert (("libev: pipe_w not active, but pipe not written", ev_is_active (&pipe_w)));
  104.             ev_feed_event (EV_A_ &pipe_w, EV_CUSTOM);
  105.           }


  106.         /* update ev_rt_now, do magic */
  107.         time_update (EV_A_ waittime + sleeptime);
  108.       }

  109.       /* queue pending timers and reschedule them */
  110.       timers_reify (EV_A); /* relative timers called last */
  111. #if EV_PERIODIC_ENABLE
  112.       periodics_reify (EV_A); /* absolute timers called first */
  113. #endif

  114. #if EV_IDLE_ENABLE
  115.       /* queue idle watchers unless other events are pending */
  116.       idle_reify (EV_A);
  117. #endif

  118. #if EV_CHECK_ENABLE
  119.       /* queue check watchers, to be executed first */
  120.       if (expect_false (checkcnt))
  121.         queue_events (EV_A_ (W *)checks, checkcnt, EV_CHECK);
  122. #endif

  123.       EV_INVOKE_PENDING;
  124.     }
  125.   while (expect_true (
  126.     activecnt
  127.     && !loop_done
  128.     && !(flags & (EVRUN_ONCE | EVRUN_NOWAIT))
  129.   ));//循环主体

  130.   if (loop_done == EVBREAK_ONE)
  131.     loop_done = EVBREAK_CANCEL;

  132. #if EV_FEATURE_API
  133.   --loop_depth;
  134. #endif

  135.   return activecnt;
  136. }

上述为事件IO调用的全过程。



阅读(2978) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~