本文章针对linux环境下的libev进行分析。
下面贴出测试程序,根据该程序进行分析
-
#include <stdio.h>
-
#include <ev.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
-
void call_(struct ev_loop * ploop,ev_io * io_w,int e)
-
{
-
char buf[1024];
-
int n = read(io_w->fd,buf,sizeof(buf));
-
buf[n] = '\0';
-
printf("%s",buf);
-
}
-
-
int main(int argc,char ** argv)
-
{
-
struct ev_loop * ploop = ev_loop_new();
-
if(ploop == NULL)
-
{
-
printf("ploop is null \n");
-
return -1 ;
-
}
-
struct ev_io io_w;
-
ev_io_init(&io_w,call_,0,EV_READ);
-
ev_io_start(ploop,&io_w);
-
ev_run(ploop,0);
-
-
}
编译命令: g++ -g -o test test.cxx -lev
下面针对每一步进行分析:
在ev_loop_new()这一步,函数如下:
-
struct ev_loop * ecb_cold
-
ev_loop_new (unsigned int flags) EV_THROW
-
{
-
EV_P = (struct ev_loop *)ev_malloc (sizeof (struct ev_loop));//为指针分配空间
-
-
memset (EV_A, 0, sizeof (struct ev_loop));//将结构清0
-
loop_init (EV_A_ flags);//初始化
-
-
if (ev_backend (EV_A)) //判断loop有没有初始化到epoll/poll/select等多路复用的接口。
-
return EV_A;
-
-
ev_free (EV_A);
-
return 0;
-
}
ev_malloc可以看出,是分配内存的函数。具体的流程,通过查找,定义如下:
-
#define ev_malloc(size) ev_realloc (0, (size))
-
inline_speed void *
-
ev_realloc (void *ptr, long size)
-
{
-
ptr = alloc (ptr, size);
-
-
if (!ptr && size)//若未分配的空间
-
{
-
#if EV_AVOID_STDIO
-
ev_printerr ("(libev) memory allocation failed, aborting.\n");
-
#else
-
fprintf (stderr, "(libev) cannot allocate %ld bytes, aborting.", size);
-
#endif
-
abort ();
-
}
-
-
return ptr;
-
}
在上述代码中,ev_realloc主要调用了alloc函数,alloc函数如下:
-
static void *
-
ev_realloc_emul (void *ptr, long size) EV_THROW
-
{
-
/* some systems, notably openbsd and darwin, fail to properly
-
* implement realloc (x, 0) (as required by both ansi c-89 and
-
* the single unix specification, so work around them here.
-
* recently, also (at least) fedora and debian started breaking it,
-
* despite documenting it otherwise.
-
*/
-
-
if (size)
-
return realloc (ptr, size);
-
-
free (ptr);
-
return 0;
-
}
-
-
static void *(*alloc)(void *ptr, long size) EV_THROW = ev_realloc_emul;
-
即,alloc为一个函数指针,被赋值为realloc.
下面分析loop_init函数的过程
-
static void noinline ecb_cold
-
loop_init (EV_P_ unsigned int flags) EV_THROW
-
{
-
if (!backend)
-
{
-
origflags = flags;
-
-
#if EV_USE_REALTIME //系统是否支持CLOCK_REALTIM
-
if (!have_realtime)
-
{
-
struct timespec ts;
-
-
if (!clock_gettime (CLOCK_REALTIME, &ts))
-
have_realtime = 1;
-
}
-
#endif
-
-
#if EV_USE_MONOTONIC //系统是否支持CLOCK_MONOTONI,不会随系统时间的变化而变化
-
if (!have_monotonic)
-
{
-
struct timespec ts;
-
-
if (!clock_gettime (CLOCK_MONOTONIC, &ts))
-
have_monotonic = 1;
-
}
-
#endif
-
-
/* pid check not overridable via env */
-
#ifndef _WIN32
-
if (flags & EVFLAG_FORKCHECK)
-
curpid = getpid ();
-
#endif
-
-
if (!(flags & EVFLAG_NOENV)
-
&& !enable_secure ()
-
&& getenv ("LIBEV_FLAGS"))
-
flags = atoi (getenv ("LIBEV_FLAGS"));
-
-
ev_rt_now = ev_time ();
-
mn_now = get_clock ();
-
now_floor = mn_now;
-
rtmn_diff = ev_rt_now - mn_now;
-
#if EV_FEATURE_API
-
invoke_cb = ev_invoke_pending;
-
#endif
-
-
io_blocktime = 0.;
-
timeout_blocktime = 0.;
-
backend = 0;
-
backend_fd = -1;
-
sig_pending = 0;
-
#if EV_ASYNC_ENABLE
-
async_pending = 0;
-
#endif
-
pipe_write_skipped = 0;
-
pipe_write_wanted = 0;
-
evpipe [0] = -1;
-
evpipe [1] = -1;
-
#if EV_USE_INOTIFY
-
fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2;
-
#endif
-
#if EV_USE_SIGNALFD
-
sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1;
-
#endif
-
-
if (!(flags & EVBACKEND_MASK))
-
flags |= ev_recommended_backends (); //得到系统中支持哪些方式select,poll,epoll等 ,我的系统是linux,因此三者都有,该处值为7
-
-
#if EV_USE_IOCP
-
if (!backend && (flags & EVBACKEND_IOCP )) backend = iocp_init (EV_A_ flags);
-
#endif
-
#if EV_USE_PORT
-
if (!backend && (flags & EVBACKEND_PORT )) backend = port_init (EV_A_ flags);
-
#endif
-
#if EV_USE_KQUEUE
-
if (!backend && (flags & EVBACKEND_KQUEUE)) backend = kqueue_init (EV_A_ flags);
-
#endif
-
#if EV_USE_EPOLL
-
if (!backend && (flags & EVBACKEND_EPOLL )) backend = epoll_init (EV_A_ flags);//使用epoll初始化,后面因为此处backend被初始化成功后,!backend为假,不会再进行初始化。
-
#endif
-
#if EV_USE_POLL
-
if (!backend && (flags & EVBACKEND_POLL )) backend = poll_init (EV_A_ flags);
-
#endif
-
#if EV_USE_SELECT
-
if (!backend && (flags & EVBACKEND_SELECT)) backend = select_init (EV_A_ flags);
-
#endif
-
-
ev_prepare_init (&pending_w, pendingcb); //此处等同于ev_init(&pending_w,pendingcb)
-
-
#if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE
-
ev_init (&pipe_w, pipecb);
-
ev_set_priority (&pipe_w, EV_MAXPRI);//设置优先级
-
#endif
-
}
-
}
在loop_init中,最重要的函数是epoll_init/poll_init/select_init
下面以epoll_init来例进行说明
-
int inline_size
-
epoll_init (EV_P_ int flags)
-
{
-
#ifdef EPOLL_CLOEXEC
-
backend_fd = epoll_create1 (EPOLL_CLOEXEC);
-
-
if (backend_fd < 0 && (errno == EINVAL || errno == ENOSYS))
-
#endif
-
backend_fd = epoll_create (256); //epoll_create初始化backend_fd
-
-
if (backend_fd < 0)
-
return 0;
-
-
fcntl (backend_fd, F_SETFD, FD_CLOEXEC);
-
-
backend_mintime = 1e-3; /* epoll does sometimes return early, this is just to avoid the worst */
-
backend_modify = epoll_modify;//修改事件调用函数,内部调用了epoll_ctl
-
backend_poll = epoll_poll;//调用epoll_poll来返回事件列表,epoll_poll内部调用了epoll_wait
-
-
epoll_eventmax = 64; /* initial number of events receivable per poll */
-
epoll_events = (struct epoll_event *)ev_malloc (sizeof (struct epoll_event) * epoll_eventmax);
-
-
return EVBACKEND_EPOLL;
-
}
下面对ev_io_init进行说明
-
#define ev_io_init(ev,cb,fd,events) do { ev_init ((ev), (cb)); ev_io_set ((ev),(fd),(events)); } while (0)
-
#define ev_init(ev,cb_) do { \
-
((ev_watcher *)(void *)(ev))->active = \
-
((ev_watcher *)(void *)(ev))->pending = 0; \
-
ev_set_priority ((ev), 0); \
-
ev_set_cb ((ev), cb_); \
-
} while (0)
-
#define ev_io_set(ev,fd_,events_) do { (ev)->fd = (fd_); (ev)->events = (events_) | EV__IOFDSET; } while (0)
-
# define ev_set_cb(ev,cb_) (ev_cb_ (ev) = (cb_), memmove (&((ev_watcher *)(ev))->cb, &ev_cb_ (ev), sizeof (ev_cb_ (ev))))
-
#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进行说明
-
void noinline
-
ev_io_start (EV_P_ ev_io *w) EV_THROW
-
{
-
int fd = w->fd;
-
-
if (expect_false (ev_is_active (w)))
-
return;
-
-
assert (("libev: ev_io_start called with negative fd", fd >= 0));
-
assert (("libev: ev_io_start called with illegal event mask", !(w->events & ~(EV__IOFDSET | EV_READ | EV_WRITE))));
-
-
EV_FREQUENT_CHECK;
-
-
ev_start (EV_A_ (W)w, 1);
-
array_needsize (ANFD, anfds, anfdmax, fd + 1, array_init_zero);
-
wlist_add (&anfds[fd].head, (WL)w); //将w加入到anfds链表中
-
-
/* common bug, apparently */
-
assert (("libev: ev_io_start called with corrupted watcher", ((WL)w)->next != (WL)w));
-
-
fd_change (EV_A_ fd, w->events & EV__IOFDSET | EV_ANFD_REIFY);
-
w->events &= ~EV__IOFDSET;
-
-
EV_FREQUENT_CHECK;
-
}
-
inline_size void
-
pri_adjust (EV_P_ W w)
-
{
-
int pri = ev_priority (w);
-
pri = pri < EV_MINPRI ? EV_MINPRI : pri;
-
pri = pri > EV_MAXPRI ? EV_MAXPRI : pri;
-
ev_set_priority (w, pri);
-
}
-
-
inline_speed void
-
ev_start (EV_P_ W w, int active)
-
{
-
pri_adjust (EV_A_ w);
-
w->active = active;
-
ev_ref (EV_A);
-
}
-
void
-
ev_ref (EV_P) EV_THROW
-
{
-
++activecnt;
-
}
下面是ev_run调用的过程
-
int
-
ev_run (EV_P_ int flags)
-
{
-
#if EV_FEATURE_API
-
++loop_depth;
-
#endif
-
-
assert (("libev: ev_loop recursion during release detected", loop_done != EVBREAK_RECURSE));
-
-
loop_done = EVBREAK_CANCEL;
-
-
EV_INVOKE_PENDING; /* in case we recurse, ensure ordering stays nice and clean */
-
-
do
-
{
-
#if EV_VERIFY >= 2
-
ev_verify (EV_A);
-
#endif
-
-
#ifndef _WIN32
-
if (expect_false (curpid)) /* penalise the forking check even more */
-
if (expect_false (getpid () != curpid))
-
{
-
curpid = getpid ();
-
postfork = 1;
-
}
-
#endif
-
-
#if EV_FORK_ENABLE
-
/* we might have forked, so queue fork handlers */
-
if (expect_false (postfork))
-
if (forkcnt)
-
{
-
queue_events (EV_A_ (W *)forks, forkcnt, EV_FORK);
-
EV_INVOKE_PENDING;
-
}
-
#endif
-
-
#if EV_PREPARE_ENABLE
-
/* queue prepare watchers (and execute them) */
-
if (expect_false (preparecnt))
-
{
-
queue_events (EV_A_ (W *)prepares, preparecnt, EV_PREPARE);
-
EV_INVOKE_PENDING;
-
}
-
#endif
-
-
if (expect_false (loop_done))
-
break;
-
-
/* we might have forked, so reify kernel state if necessary */
-
if (expect_false (postfork))
-
loop_fork (EV_A);
-
-
/* update fd-related kernel structures */
-
fd_reify (EV_A);
-
-
/* calculate blocking time */
-
{
-
ev_tstamp waittime = 0.;
-
ev_tstamp sleeptime = 0.;
-
-
/* remember old timestamp for io_blocktime calculation */
-
ev_tstamp prev_mn_now = mn_now;
-
-
/* update time to cancel out callback processing overhead */
-
time_update (EV_A_ 1e100);
-
-
/* from now on, we want a pipe-wake-up */
-
pipe_write_wanted = 1;
-
-
ECB_MEMORY_FENCE; /* make sure pipe_write_wanted is visible before we check for potential skips */
-
-
if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt || pipe_write_skipped)))
-
{
-
waittime = MAX_BLOCKTIME;
-
-
if (timercnt)
-
{
-
ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now;
-
if (waittime > to) waittime = to;
-
}
-
-
#if EV_PERIODIC_ENABLE
-
if (periodiccnt)
-
{
-
ev_tstamp to = ANHE_at (periodics [HEAP0]) - ev_rt_now;
-
if (waittime > to) waittime = to;
-
}
-
#endif
-
-
/* don't let timeouts decrease the waittime below timeout_blocktime */
-
if (expect_false (waittime < timeout_blocktime))
-
waittime = timeout_blocktime;
-
-
/* at this point, we NEED to wait, so we have to ensure */
-
/* to pass a minimum nonzero value to the backend */
-
if (expect_false (waittime < backend_mintime))
-
waittime = backend_mintime;
-
-
/* extra check because io_blocktime is commonly 0 */
-
if (expect_false (io_blocktime))
-
{
-
sleeptime = io_blocktime - (mn_now - prev_mn_now);
-
-
if (sleeptime > waittime - backend_mintime)
-
sleeptime = waittime - backend_mintime;
-
-
if (expect_true (sleeptime > 0.))
-
{
-
ev_sleep (sleeptime);
-
waittime -= sleeptime;
-
}
-
}
-
}
-
-
#if EV_FEATURE_API
-
++loop_count;
-
#endif
-
assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */
-
backend_poll (EV_A_ waittime);//调用多路复用函数
-
assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */
-
-
pipe_write_wanted = 0; /* just an optimisation, no fence needed */
-
-
ECB_MEMORY_FENCE_ACQUIRE;
-
if (pipe_write_skipped)
-
{
-
assert (("libev: pipe_w not active, but pipe not written", ev_is_active (&pipe_w)));
-
ev_feed_event (EV_A_ &pipe_w, EV_CUSTOM);
-
}
-
-
-
/* update ev_rt_now, do magic */
-
time_update (EV_A_ waittime + sleeptime);
-
}
-
-
/* queue pending timers and reschedule them */
-
timers_reify (EV_A); /* relative timers called last */
-
#if EV_PERIODIC_ENABLE
-
periodics_reify (EV_A); /* absolute timers called first */
-
#endif
-
-
#if EV_IDLE_ENABLE
-
/* queue idle watchers unless other events are pending */
-
idle_reify (EV_A);
-
#endif
-
-
#if EV_CHECK_ENABLE
-
/* queue check watchers, to be executed first */
-
if (expect_false (checkcnt))
-
queue_events (EV_A_ (W *)checks, checkcnt, EV_CHECK);
-
#endif
-
-
EV_INVOKE_PENDING;
-
}
-
while (expect_true (
-
activecnt
-
&& !loop_done
-
&& !(flags & (EVRUN_ONCE | EVRUN_NOWAIT))
-
));//循环主体
-
-
if (loop_done == EVBREAK_ONE)
-
loop_done = EVBREAK_CANCEL;
-
-
#if EV_FEATURE_API
-
--loop_depth;
-
#endif
-
-
return activecnt;
-
}
上述为事件IO调用的全过程。
阅读(2956) | 评论(0) | 转发(0) |