如何将libev 自动生成的makefile生成动态库 还原到初始状态

6921人阅读
由于最近现网的epoll版本服务器,出现了点诡异的问题,不得已改用libev快速上线,在这里先记录下简单的使用实例。代码中可能存在部分bug,此代码并非线上跑的代码,不过已经五脏俱全,如果有任何疑问,欢迎一起讨论。
转载注明出处:
#include &ev.h&
#include &stdio.h&
#include &netinet/in.h&
#include&stdlib.h&
#include &string.h&
#define PORT 57789
#define BUFFER_SIZE 2048
#define MAX_ALLOWED_CLIENT 10240
struct ev_io *libevlist[MAX_ALLOWED_CLIENT] = {NULL};
void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents);
void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents);
void timer_beat(struct ev_loop *loop, struct ev_timer *watcher, int revents);
int freelibev(struct ev_loop *loop, int fd);
int main()
struct ev_loop *loop=ev_default_loop(0);
struct sockaddr_
int addr_len = sizeof(addr);
//创建一个io watcher和一个timer watcher
struct ev_io socket_
struct ev_timer timeout_w;
//创建socket连接
sd = socket(PF_INET, SOCK_STREAM, 0);
if(sd & 0)
printf(&socket error\n&);
return -1;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = INADDR_ANY;
//正常bind
if(bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0)
printf(&bind error\n&);
return -1;
//正常listen
if(listen(sd, SOMAXCONN) & 0)
printf(&listen error\n&);
return -1;
//设置fd可重用
int bReuseaddr=1;
if(setsockopt(sd,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(bReuseaddr)) != 0)
printf(&setsockopt error in reuseaddr[%d]\n&, sd);
//初始化io watcher,用于监听fd
ev_io_init(&socket_accept, accept_cb, sd, EV_READ);
ev_io_start(loop, &socket_accept);
//可以向远端发送心跳包
//ev_timer_init(&timeout_w, timer_beat, 1., 0.);
//ev_timer_start(loop, &timeout_w);
ev_run(loop, 0);
void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
如果有链接,则继续监听fd;
struct sockaddr_in client_
socklen_t client_len = sizeof(client_addr);
int client_
//创建客户端的io watcher
struct ev_io *w_client = (struct ev_io*) malloc(sizeof(struct ev_io));
if(w_client == NULL)
printf(&malloc error in accept_cb\n&);
if(EV_ERROR & revents)
printf(&error event in accept\n&);
//获取与客户端相连的fd
client_sd = accept(watcher-&fd, (struct sockaddr*)&client_addr, &client_len);
if(client_sd & 0)
printf(&accept error\n&);
//如果连接数超出指定范围,则关闭连接
if( client_sd & MAX_ALLOWED_CLIENT)
printf(&fd too large[%d]\n&, client_sd);
close(client_sd);
if(libevlist[client_sd] != NULL)
printf(&client_sd not NULL fd is [%d]\n&, client_sd);
printf(&client connected\n&);
//监听新的fd
ev_io_init(w_client, read_cb, client_sd, EV_READ);
ev_io_start(loop, w_client);
libevlist[client_sd] = w_
void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
char buffer[BUFFER_SIZE];
if(EV_ERROR & revents)
printf(&error event in read\n&);
//正常的recv
read = recv(watcher-&fd, buffer, BUFFER_SIZE, 0);
if(read & 0)
printf(&read error\n&);
if(read == 0)
printf(&client disconnected.\n&);
//ev_io_stop(loop, watcher);
//free(watcher);
//如果客户端断开连接,释放响应的资源,并且关闭监听
freelibev(loop, watcher-&fd);
//buffer[read] = '\0';
printf(&receive message:%s\n&, buffer);
//返回给客户端
send(watcher-&fd, buffer, read, 0);
bzero(buffer, read);
void timer_beat(struct ev_loop *loop, struct ev_timer *watcher, int revents)
float timeout = 2.0;
//这里可以发送心跳包,也可以什么都不做
printf(&send beat per[%f]\n&,timeout);
fflush(stdout);
if(EV_ERROR & revents)
printf(&error event in timer_beat\n&);
ev_timer_set(watcher, timeout,0.);
ev_timer_start(loop, watcher);
int freelibev(struct ev_loop *loop, int fd)
/*if(fd & MAX_ALLOWED_CLIENT)
printf(&more than MAX_ALLOWED_CLIENT[%d]&, fd);
return -1;
//清理相关资源
if(libevlist[fd] == NULL)
printf(&the fd already freed[%d]\n&, fd);
return -1;
close(fd);
ev_io_stop(loop, libevlist[fd]);
free(libevlist[fd]);
libevlist[fd] = NULL;
makefile:
FLAGS=-I. -I/home/lengzijian/c/libev/libev-4.11
LDFLAGS=-L/usr/lib -L/home/lengzijian/c/libev/libev-4.11/.libs -lev -Wall
OBJECTS=server.o
ALL_BIN=server
all:$(ALL_BIN)
$(ALL_BIN):$(OBJECTS)
$(CC) $(FLAGS) $(LDFLAGS) -o $@ $^
$(CC) -c $& $(FLAGS) $(FLAGS)
rm -fr $(OBJECTS)
rm -fr $(ALL_BIN)
注意makefile中的头文件路径,和动态链接库的路径
测试时,只需要telnet ip 57789 即可
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:291346次
积分:4217
积分:4217
排名:第4600名
原创:81篇
评论:201条
文章:25篇
阅读:95912
(1)(2)(7)(1)(3)(4)(1)(6)(4)(3)(4)(5)(12)(13)(8)(1)(14)IntroLibev是一个基于Reactor模式的事件库,效率较高()并且代码精简(4.15版本8000多行),是学习事件驱动编程的很好的资源。
本文不会介绍Reactor模式,也不会介绍Libev的API,主要内容是我学习libev后的一些总结,介绍了Livev的设计方法和实现方法,并对一部分核心代码进行了注解。
如需更详尽的API介绍,可以参见Libev的。
FeatureLibev是一个用C编写的功能齐全的高性能的轻量级事件驱动库,其支持多种后台IO复用接口,并且可以注册多达十几种事件。
支持的后台IO复用接口:
selectpollepollkqueuesolaris event port
支持的事件类型:
ev_periodic
ev_cleanup
ev_prepare
Sample在介绍Libev的代码结构之前,先看一个Libev手册中自带的例子,其注册了两个事件,一个timeout事件,一个io事件,任何一个事件发生后都会调用回调函数并终止主循环。这也是事件驱动编程的标准模式——注册事件后等待其触发并调用回调函数。
代码中的注释已经十分详细,我就不再赘述。要编译这段代码(evtest.c),首先在下载Libev源码编译安装,然后使用gcc evtest.c -libev编译(记得ldconfig)。
evtest.c#include &ev.h&#include &stdio.h& ev_io stdin_ev_timer timeout_static voidstdin_cb (EV_P_ ev_io *w, int revents){
puts ("stdin ready");
ev_io_stop (EV_A_ w);
ev_break (EV_A_ EVBREAK_ALL);}static voidtimeout_cb (EV_P_ ev_timer *w, int revents){
puts ("timeout");
ev_break (EV_A_ EVBREAK_ONE);}intmain (void){
struct ev_loop *loop = EV_DEFAULT;
ev_io_init (&stdin_watcher, stdin_cb,
0, EV_READ);
ev_io_start (loop, &stdin_watcher);
ev_timer_init (&timeout_watcher, timeout_cb, 5.5, 0.);
ev_timer_start (loop, &timeout_watcher);
ev_run (loop, 0);
return 0;}
Main StructuresWather事件驱动库中,很重要的一部分就是对事件的封装。在Libev中,事件被封装在Watcher结构体中,通过注册Watcher并指定对应的回调函数等参数,就可以将事件添加到主循环中。
先解释一下EV_P,EV_P_,EV_A,EV_A_这几个宏,在代码中几乎随处可见,主要是为了简化单线程模式下的函数调用的接口,这几个宏定义如下。#if EV_MULTIPLICITYstruct ev_# define EV_P
struct ev_loop *loop
/* a loop as sole parameter in a declaration */# define EV_P_ EV_P,
/* a loop as first of multiple parameters */# define EV_A
/* a loop as sole argument to a function call */# define EV_A_ EV_A,
/* a loop as first of multiple arguments */#else# define EV_P void# define EV_P_# define EV_A# define EV_A_#endif
ev_loop是主循环,而EV_MULTIPLICITY是一个条件编译的宏,表明是否支持有多个ev_loop实例存在,一般来说,每个线程中有且仅有一个ev_loop实例。如果整个程序是单线程的,程序中使用全局默认的ev_loop即可,不需要在函数中传参。而在多线程中调用函数很多时候都要指定函数操作的loop。比如启动一个io事件,调用的函数是void ev_io_start (EV_P_ ev_io *w),如果没有定义EV_MULTIPLICITY,将会编译成ev_io_start(io *w),否则会编译成ev_io_start(struct ev_loop *loop, ev_io *w)。
对于每一种事件,都有结构体ev_TYPE与之对应,比如ev_io,ev_timer等。为了统一事件结构,libev在C中使用结构体布局实现了多态,可以将ev_watcher结构体看做所有ev_TYPE结构体的基类,它包含了所有ev_TYPE中相同的字段。
代码中对这些结构体的定义如下,为了便于理解,我对部分宏进行了还原。之所以只还原部分宏而不是全部,是因为这些宏体现了作者设计这些结构体的思路。
相关的宏#define EV_WATCHER(type)
\ /* private */
\ /* private */
\ /* private */
void * /* rw */
void (*cb)(EV_P_ struct type *w, int revents); /* private */#define EV_WATCHER_TIME(type)
EV_WATCHER (type)
/* private */#define EV_WATCHER_LIST(type)
EV_WATCHER (type)
struct ev_watcher_list * /* private */
“基类”typedef struct ev_watcher{
EV_WATCHER (ev_watcher)} ev_typedef struct ev_watcher_time{
EV_WATCHER_TIME (ev_watcher_time)} ev_watcher_typedef struct ev_watcher_list{
EV_WATCHER_LIST (ev_watcher_list)} ev_watcher_
“派生类”,这里只列举了ev_io,ev_timer和ev_signal,这三种是比较常用的事件,其它事件结构的代码都差不多,具体可以见源码。typedef struct ev_io{
EV_WATCHER_LIST (ev_io)
int } ev_typedef struct ev_signal{
EV_WATCHER_LIST (ev_signal)
int } ev_typedef struct ev_timer{
EV_WATCHER_TIME (ev_timer)
ev_ } ev_```
从以上代码可以看出来,每个事件结构体中的共有字段表示了这个事件的状态,优先级,参数,以及回调函数,而私有字段则是该类型事件的特有信息,比如io事件有对应的fd、定时器事件有发生时间等。
另外还有一个叫做ev_any_watcher的union可以容纳所有的事件类型。```cunion ev_any_watcher{
struct ev_
struct ev_watcher_
struct ev_
struct ev_
struct ev_
struct ev_
struct ev_
struct ev_
struct ev_
struct ev_
struct ev_
struct ev_
struct ev_
struct ev_
struct ev_};
ev_loopev_loop是个十分重要也非常庞大的结构体,可以称其为事件控制器,事件的调度基本都是由它控制的。
该结构体的定义十分晦涩,从下面的代码可以看出,代码会根据EV_MULTIPLICITY是否定义进行条件编译,在单线程环境下,因为只有一个loop,所以所有变量直接作为全局变量使用,而在多线程模式下会有多个loop实例,因此需要将变量封装在ev_loop结构体中,调用函数时要指定所操作的loop。这些变量定义在ev_vars.h中,通过include展开。
另外,在多线程模式下,定义了ev_loop结构体之后,还include了ev_wrap.h,这个文件中对ev_vars.h中的所有变量定义了一堆形如#define anfds ((loop)-&anfds)的宏,这个宏的目的是为了统一代码的编写,在未开启EV_MULTIPLICITY时anfds表示的就是全局变量anfds,而在开启了EV_MULTIPLICITY后,函数一般会传一个struct ev_loop *loop,anfds也会展开成((loop)-&anfds)。这使得代码中不用再写一堆的#if #else #endif,但也让代码变的更加晦涩难懂。
#if EV_MULTIPLICITY
struct ev_loop
ev_tstamp ev_rt_
#define ev_rt_now ((loop)-&ev_rt_now)
#define VAR(name,decl)
#include "ev_vars.h"
#undef VAR
#include "ev_wrap.h"
static struct ev_loop default_loop_
EV_API_DECL struct ev_loop *ev_default_loop_ptr = 0; #else
EV_API_DECL ev_tstamp ev_rt_now = 0;
#define VAR(name,decl)
#include "ev_vars.h"
#undef VAR
static int ev_default_loop_#endif
ANFD在管理io事件的时候,如何根据fd快速找到与其相关的事件,是一个需要考虑的问题。Libev的方法是用一个数组来存所有fd信息的结构体,然后以fd值为索引直接找到对应的结构体,这个结构体就是下面的ANFD结构体(省略了有关Windows系统的变量)。这种方法可以在O(1)复杂度内进行索引,问题是它占的空间有多少?假如我们同时开了一百万个fd,所占空间一共是10^6*sizeof(ANFD),大约12M左右,这完全是可以接受的。
结构体中字段的含义在后面介绍Libev流程时会逐渐提到。typedef ev_watcher_list *WL;typedef struct{
unsigned char
unsigned char
unsigned char
unsigned char#if EV_USE_EPOLL
unsigned int
#endif} ANFD;
How it works?这节主要介绍了libev的代码是怎样工作的,主要分为事件注册,事件调度与后台I/O复用三部分。
事件注册事件注册,也就是告诉事件驱动器程序要关注某个事件的发生。这里以io事件为例来分析怎样去注册以及销毁一个事件,其它事件的代码逻辑基本上都是一样的,就不再赘述。
从上面Sample里的代码中我们可以看到,启动一个io事件调用了了以下这两个函数:ev_io stdin_ev_io_init (&stdin_watcher, stdin_cb,
0, EV_READ);ev_io_start (loop, &stdin_watcher);
首先看一下ev_io_init,与其相关的代码主要有以下几个宏。基本就是初始化了ev_io结构体中各个字段的值,优先级会被初始化为0,如需改变需要单独调用ev_set_priority。上面的ev_io_init,实际上就是注册了一个关注读的IO事件,相应的fd为0也就是标准输入。
#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)
然后是ev_io_start,核心工作就是将ev_io添加到相关fd的事件链表上去,下面是主要代码,我在代码中给出了较为详细的注释。其中noinline等都是作者因为编译器差异定义的一些宏,而EV_FREQUENT_CHECK也是为了验证程序正确性添加的宏,在生产环境下不会生成任何内容,这些宏现在都可以忽略,我们只关心主要逻辑。
typedef ev_watcher *W;typedef ev_watcher_list *WL;void noinlineev_io_start (EV_P_ ev_io *w) EV_THROW{
int fd = w-&
if (expect_false (ev_is_active (w)))
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);
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_speed voidev_start (EV_P_ W w, int active){
pri_adjust (EV_A_ w);
w-&active =
ev_ref (EV_A);}inline_size voidwlist_add (WL *head, WL elem){
elem-&next = *
*head =}inline_size voidfd_change (EV_P_ int fd, int flags){
unsigned char reify = anfds [fd].
anfds [fd].reify |=
if (expect_true (!reify))
array_needsize (int, fdchanges, fdchangemax, fdchangecnt, EMPTY2);
fdchanges [fdchangecnt - 1] =
}}
最后看一下ev_io_stop,逻辑基本就是ev_io_start的反过程。void noinlineev_io_stop (EV_P_ ev_io *w) EV_THROW{
clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
assert (("libev: ev_io_stop called with illegal fd (must stay constant after start!)", w-&fd &= 0 && w-&fd & anfdmax));
EV_FREQUENT_CHECK;
wlist_del (&anfds[w-&fd].head, (WL)w);
ev_stop (EV_A_ (W)w);
fd_change (EV_A_ w-&fd, EV_ANFD_REIFY);
EV_FREQUENT_CHECK;}inline_size voidwlist_del (WL *head, WL elem){
while (*head)
if (expect_true (*head == elem))
*head = elem-&
head = &(*head)-&
}}
Main Loopev_io系列函数所做的操作基本就是填充ev_io结构体并将其放在对应fd的事件链表上,而将监听事件状态发生改变的fd存在fdchanges数组中,驱动控制器会根据该数组更改后台监听的事件,当事件发生时驱动控制器会自动调用相应事件的回调函数。在整个过程中,驱动控制器也就是ev_loop就像胶水一样将事件和后台复用机制粘在一起。
整个事件的调度过程基本都在函数ev_run中,整个函数较长,大概有两百多行,这里就不列出代码了,只把程序的主要逻辑写了出来。intev_run (EV_P_ int flags){
backend_poll (EV_A_ waittime);
EV_INVOKE_PENDING;
while (条件成立);}
ev_run的逻辑可以说还是比较清晰的。程序首先会先执行一些需要在poll之前执行的回调,接着根据最先超时的计时器算出poll需要wait的时间,之后调用poll等待I/O事件发生,最后执行发生事件的回调。
具体的代码中,程序使用queue_events将要运行的事件放入一个叫做pending的二维数组中,其第一维是优先级,第二维是动态分配的,存放具体事件。之后程序会在适当的地方调用宏EV_INVOKE_PENDING,将pending数组中的事件按优先级从高到低依次执行。
I/O复用Libev使用函数指针来实现支持多种I/O复用机制,每种复用机制要实现init, modify, poll, destroy这几个函数,也就是初始化、修改关注事件、等待事件发生、销毁这几个功能。这部分代码我只看了epoll的实现,感觉实现的还是很巧妙的,读者可以根据自己熟悉的I/O复用机制去选择看哪部分代码。
More至此,Libev的主要设计方法和实现思路基本介绍的差不多了,限于篇幅,还有很多细节无法在一篇文章中叙述完,如果有时间的话,我会尽量完善这篇文章。
作为一个事件库,Libev的设计可以说是十分精良,代码中的各种tips也让我受益良多。但是,Libev几乎不涉及网络编程,如果要在此基础上实现网络库,还是有大量工作要做的。>> libev-4.19-_-ev++.h
libev-4.19-_-ev++.h ( 文件浏览 )
* libev simple C++ wrapper classes
* Copyright (c) 10 Marc Alexander Lehmann &libev@schmorp.de&
* All rights reserved.
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* Alternatively, the contents of this file may be used under the terms of
* the GNU General Public License (&GPL&) version 2 or any later version,
* in which case the provisions of the GPL are applicable instead of
* the above. If you wish to allow the use of your version of this file
* only under the terms of the GPL and not to allow others to use your
* version of this file under the BSD license, indicate your decision
* by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete the
* provisions above, a recipient may use your version of this file under
* either the BSD or the GPL.
#ifndef EVPP_H__
#define EVPP_H__
#ifdef EV_H
# include EV_H
# include &ev.h&
#ifndef EV_USE_STDEXCEPT
# define EV_USE_STDEXCEPT 1
#if EV_USE_STDEXCEPT
# include &stdexcept&
namespace ev {
typedef ev_
= EV_UNDEF,
= EV_NONE,
= EV_READ,
= EV_WRITE,
#if EV_COMPAT3
= EV_TIMEOUT,
= EV_TIMER,
PERIODIC = EV_PERIODIC,
= EV_SIGNAL,
= EV_CHILD,
= EV_STAT,
= EV_IDLE,
= EV_CHECK,
= EV_PREPARE,
= EV_FORK,
= EV_ASYNC,
= EV_EMBED,
undef ERROR // some systems stupidly #define ERROR
= EV_ERROR
= EVFLAG_AUTO,
= EVFLAG_NOENV,
FORKCHECK = EVFLAG_FORKCHECK,
= EVBACKEND_SELECT,
= EVBACKEND_POLL,
= EVBACKEND_EPOLL,
= EVBACKEND_KQUEUE,
= EVBACKEND_DEVPOLL,
= EVBACKEND_PORT
#if EV_COMPAT3
NONBLOCK = EVLOOP_NONBLOCK,
= EVLOOP_ONESHOT,
= EVRUN_NOWAIT,
= EVRUN_ONCE
enum how_t
ONE = EVBREAK_ONE,
ALL = EVBREAK_ALL
struct bad_loop
#if EV_USE_STDEXCEPT
: std::runtime_error
#if EV_USE_STDEXCEPT
bad_loop ()
: std::runtime_error (&libev event loop cannot be initialized, bad value of LIBEV_FLAGS?&)
#ifdef EV_AX
undef EV_AX
#ifdef EV_AX_
undef EV_AX_
#if EV_MULTIPLICITY
define EV_AX
define EV_AX_ raw_loop,
define EV_AX
define EV_AX_
struct loop_ref
loop_ref (EV_P) throw ()
#if EV_MULTIPLICITY
: EV_AX (EV_A)
bool operator == (const loop_ref &other) const throw ()
#if EV_MULTIPLICITY
return EV_AX == other.EV_AX;
bool operator != (const loop_ref &other) const throw ()
#if EV_MULTIPLICITY
return ! (*this == other);
#if EV_MULTIPLICITY
bool operator == (const EV_P) const throw ()
return this-&EV_AX == EV_A;
bool operator != (const EV_P) const throw ()
return (*this == EV_A);
operator struct ev_loop * () const throw ()
return EV_AX;
operator const struct ev_loop * () const throw ()
return EV_AX;
bool is_default () const throw ()
return EV_AX == ev_default_loop (0);
#if EV_COMPAT3
void loop (int flags = 0)
ev_run (EV_AX_ flags);
void unloop (how_t how = ONE) throw ()
ev_break (EV_AX_ how);
void run (int flags = 0)
ev_run (EV_AX_ flags);
void break_loop (how_t how = ONE) throw ()
ev_break (EV_AX_ how);
void post_fork () throw ()
ev_loop_fork (EV_AX);
unsigned int backend () const throw ()
return ev_backend (EV_AX);
tstamp now () const throw ()
return ev_now (EV_AX);
void ref () throw ()
ev_ref (EV_AX);
void unref () throw ()
ev_unref (EV_AX);
#if EV_FEATURE_API
unsigned int iteration () const throw ()
return ev_iteration (EV_AX);
unsigned int depth () const throw ()
return ev_depth (EV_AX);
void set_io_collect_interval (tstamp interval) throw ()
ev_set_io_collect_interval (EV_AX_ interval);
void set_timeout_collect_interval (tstamp interval) throw ()
ev_set_timeout_collect_interval (EV_AX_ interval);
// function callback
void once (int fd, int events, tstamp timeout, void (*cb)(int, void *), void *arg = 0) throw ()
ev_once (EV_AX_ fd, events, timeout, cb, arg);
// method callback
template&class K, void (K::*method)(int)&
void once (int fd, int events, tstamp timeout, K *object) throw ()
once (fd, events, timeout, method_thunk&K, method&, object);
// default method == operator ()
template&class K&
void once (int fd, int events, tstamp timeout, K *object) throw ()
once (fd, events, timeout, method_thunk&K, &K::operator ()&, object);
template&class K, void (K::*method)(int)&
static void method_thunk (int revents, void *arg)
(static_cast&K *&(arg)-&*method)
(revents);
// no-argument method callback
template&class K, void (K::*method)()&
void once (int fd, int events, tstamp timeout, K *object) throw ()
once (fd, events, timeout, method_noargs_thunk&K, method&, object);
template&class K, void (K::*method)()&
static void method_noargs_thunk (int revents, void *arg)
(static_cast&K *&(arg)-&*method)
// simpler function callback
template&void (*cb)(int)&
void once (int fd, int events, tstamp timeout) throw ()
once (fd, events, timeout, simpler_func_thunk&cb&);
template&void (*cb)(int)&
static void simpler_func_thunk (int revents, void *arg)
(revents);
// simplest function callback
template&void (*cb)()&
void once (int fd, int events, tstamp timeout) throw ()
once (fd, events, timeout, simplest_func_thunk&cb&);
template&void (*cb)()&
static void simplest_func_thunk (int revents, void *arg)
void feed_fd_event (int fd, int revents) throw ()
ev_feed_fd_event (EV_AX_ fd, revents);
void feed_signal_event (int signum) throw ()
ev_feed_signal_event (EV_AX_ signum);
#if EV_MULTIPLICITY
struct ev_loop* EV_AX;
#if EV_MULTIPLICITY
struct dynamic_loop : loop_ref
dynamic_loop (unsigned int flags = AUTO) throw (bad_loop)
: loop_ref (ev_loop_new (flags))
if (!EV_AX)
throw bad_loop ();
~dynamic_loop () throw ()
ev_loop_destroy (EV_AX);
EV_AX = 0;
dynamic_loop (const dynamic_loop &);
dynamic_loop & operator= (const dynamic_loop &);
struct default_loop : loop_ref
default_loop (unsigned int flags = AUTO) throw (bad_loop)
#if EV_MULTIPLICITY
: loop_ref (ev_default_loop (flags))
#if EV_MULTIPLICITY
!ev_default_loop (flags)
throw bad_loop ();
default_loop (const default_loop &);
default_loop &operator = (const default_loop &);
inline loop_ref get_default_loop () throw ()
#if EV_MULTIPLICITY
return ev_default_loop (0);
return loop_ref ();
#undef EV_AX
#undef EV_AX_
#undef EV_PX
#undef EV_PX_
#if EV_MULTIPLICITY
define EV_PX
loop_ref EV_A
define EV_PX_ loop_ref EV_A_
define EV_PX
define EV_PX_
template&class ev_watcher, class watcher&
struct base : ev_watcher
#if EV_MULTIPLICITY
// loop set
void set (EV_P) throw ()
this-&EV_A = EV_A;
base (EV_PX) throw ()
#if EV_MULTIPLICITY
: EV_A (EV_A)
ev_init (this, 0);
void set_ (const void *data, void (*cb)(EV_P_ ev_watcher *w, int revents)) throw ()
this-&data = (void *)
ev_set_cb (static_cast&ev_watcher *&(this), cb);
// function callback
template&void (*function)(watcher &w, int)&
void set (void *data = 0) throw ()
set_ (data, function_thunk&function&);
template&void (*function)(watcher &w, int)&
static void function_thunk (EV_P_ ev_watcher *w, int revents)
(*static_cast&watcher *&(w), revents);
// method callback
template&class K, void (K::*method)(watcher &w, int)&
void set (K *object) throw ()
set_ (object, method_thun
(文件超长,未完全显示,请下载后阅读剩余部分)
展开> <收缩
下载源码到电脑,阅读使用更方便
还剩0行未阅读,继续阅读 ▼
Sponsored links
源码文件列表
温馨提示: 点击源码文件名可预览文件内容哦 ^_^
&&0.00 B 21:10
19.97 kB 14:53
29.25 kB 21:09
406.00 B 02:18
Symbols.ev1.07 kB 21:10
depcomp18.18 kB 14:53
Symbols.event378.00 B 21:10
ev.3258.23 kB 11:56
config.guess43.84 kB 14:53
Changes26.42 kB 02:18
9.64 kB 14:53
install-sh6.96 kB 14:53
6.25 kB 14:53
config.h.in3.24 kB 14:53
ev.pod212.64 kB 14:53
LICENSE2.01 kB 14:53
50.00 B 14:53
5.12 kB 14:53
9.72 kB 14:53
2.50 kB 14:53
config.sub32.60 kB 14:53
4.34 kB 14:53
410.00 kB 02:18
6.65 kB 14:53
277.02 kB 14:53
mkinstalldirs1.94 kB 14:53
6.11 kB 14:53
533.00 B 14:53
aclocal.m4344.20 kB 02:18
119.81 kB 21:10
6.08 kB 17:49
5.38 kB 21:10
compile7.16 kB 04:53
missing6.71 kB 04:53
28.42 kB 02:18
8.61 kB 14:53
libev.m41.53 kB 14:53
Sponsored links
23 篇源代码 21 篇源代码 18 篇源代码 13 篇源代码 9 篇源代码
285 篇源代码 173 篇源代码 48 篇源代码 42 篇源代码 36 篇源代码
评价成功,多谢!
下载libev-4.19.tar.gz
CodeForge积分(原CF币)全新升级,功能更强大,使用更便捷,不仅可以用来下载海量源代码马上还可兑换精美小礼品了
您的积分不足
支付宝优惠套餐快速获取 30 积分
10积分 / ¥100
30积分 / ¥200原价 ¥300 元
100积分 / ¥500原价 ¥1000 元
订单支付完成后,积分将自动加入到您的账号。以下是优惠期的人民币价格,优惠期过后将恢复美元价格。
支付宝支付宝付款
微信钱包微信付款
更多付款方式:、
您本次下载所消耗的积分将转交上传作者。
同一源码,30天内重复下载,只扣除一次积分。
鲁ICP备号-2
登录 CodeForge
还没有CodeForge账号?
Switch to the English version?
^_^"呃 ...
Sorry!这位大神很神秘,未开通博客呢,请浏览一下其他的吧}

我要回帖

更多关于 makefile自动生成工具 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信