精华内容
下载资源
问答
  • libevent头文件问题

    2019-06-22 10:24:37
    工程需要用到libevent,但是在编译的时候出错: In file included from /usr/local/include/event.h:68:0, from /home/project/base.cpp:26: /usr/local/include/event2/event_struct.h:166:30: error: macro ...

    工程需要用到libevent,但是在编译的时候出错:

    In file included from /usr/local/include/event.h:68:0,
                     from /home/project/base.cpp:26:
    /usr/local/include/event2/event_struct.h:166:30: error: macro "LIST_HEAD" passed 2 arguments, but takes just 1
     LIST_HEAD (event_dlist, event); 
                                  ^
    /usr/local/include/event2/event_struct.h:166:1: error: ‘LIST_HEAD’ does not name a type
     LIST_HEAD (event_dlist, event); 
     

    解决方法:

    打开/usr/local/include/envent2/event_struct.h, 第166行,改为:#define LIST_HEAD (event_dlist, event); 就成功编译了

    展开全文
  • VS2015编译后的libevent头文件和库文件——基于libevent-2.1.10
  • libevent的win10(32),android(NDK10),linux(cenots7),库文件和头文件,NDK10以上的就无法使用了。
  • libevent编译成android动态库较为麻烦,下面来详细介绍整个编译过程。 1. 下载libevent源码(最好源码版本和本教程保持一致) ...

    libevent编译成android动态库较为麻烦,下面来详细介绍整个编译过程。

    1. 下载libevent源码(最好源码版本和本教程保持一致)

    https://github.com/libevent/libevent/releases/download/release-2.1.8-stable/libevent-2.1.8-stable.tar.gz

    2. 下载android交叉编译工具ndk(不挂链接,自行百度安装)

    3. 编译mk文件

    Android.mk

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_ARM_MODE := arm
    LOCAL_MODULE := libevent
    ANDROID := true
    LIB_SRC := \
    event.c \
               evthread.c \
               buffer.c \
               bufferevent.c \
               bufferevent_filter.c \
               bufferevent_pair.c \
               listener.c \
               bufferevent_ratelim.c \
               evmap.c \
               log.c \
               evutil.c \
               evutil_rand.c \
    		   evutil_time.c \
               select.c \
               poll.c \
               epoll.c \
               signal.c \
               event_tagging.c \
               http.c \
               evdns.c \
               evrpc.c \
               bufferevent_sock.c \
    		   strlcpy.c 
    
    LOCAL_SRC_FILES  := $(LIB_SRC)
    LOCAL_C_INCLUDES := $(LOCAL_PATH)/include \
                        $(LOCAL_PATH)/compat
    LOCAL_CFLAGS += -pie -fPIE -static -fPIC
    include $(BUILD_SHARED_LIBRARY)

    Application.mk

    APP_STL      := c++_static
    APP_CPPFLAGS := -frtti -std=c++11
    APP_ABI      := armeabi-v7a arm64-v8a
    APP_BUILD_SCRIPT := Android.mk

    4. 修改配置文件event2/event-config.h,如果没有就新建一个

    修改成如下:

    /* event2/event-config.h
     *
     * This file was generated by autoconf when libevent was built, and post-
     * processed by Libevent so that its macros would have a uniform prefix.
     *
     * DO NOT EDIT THIS FILE.
     *
     * Do not rely on macros in this file existing in later versions.
     */
    
    #ifndef EVENT2_EVENT_CONFIG_H_INCLUDED_
    #define EVENT2_EVENT_CONFIG_H_INCLUDED_
    
    /* config.h.  Generated from config.h.in by configure.  */
    /* config.h.in.  Generated from configure.ac by autoheader.  */
    
    /* Define if libevent should build without support for a debug mode */
    /* #undef EVENT__DISABLE_DEBUG_MODE */
    
    /* Define if libevent should not allow replacing the mm functions */
    /* #undef EVENT__DISABLE_MM_REPLACEMENT */
    
    /* Define if libevent should not be compiled with thread support */
    /* #undef EVENT__DISABLE_THREAD_SUPPORT */
    
    /* Define to 1 if you have the `accept4' function. */
    #define EVENT__HAVE_ACCEPT4 1
    
    /* Define to 1 if you have the `arc4random' function. */
    /* #undef EVENT__HAVE_ARC4RANDOM */
    
    /* Define to 1 if you have the `arc4random_buf' function. */
    /* #undef EVENT__HAVE_ARC4RANDOM_BUF */
    
    /* Define to 1 if you have the <arpa/inet.h> header file. */
    #define EVENT__HAVE_ARPA_INET_H 1
    
    /* Define to 1 if you have the `clock_gettime' function. */
    #define EVENT__HAVE_CLOCK_GETTIME 1
    
    /* Define to 1 if you have the declaration of `CTL_KERN', and to 0 if you
       don't. */
    #define EVENT__HAVE_DECL_CTL_KERN 1
    
    /* Define to 1 if you have the declaration of `KERN_ARND', and to 0 if you
       don't. */
    #define EVENT__HAVE_DECL_KERN_ARND 0
    
    /* Define to 1 if you have the declaration of `KERN_RANDOM', and to 0 if you
       don't. */
    #define EVENT__HAVE_DECL_KERN_RANDOM 1
    
    /* Define to 1 if you have the declaration of `RANDOM_UUID', and to 0 if you
       don't. */
    #define EVENT__HAVE_DECL_RANDOM_UUID 1
    
    /* Define if /dev/poll is available */
    /* #undef EVENT__HAVE_DEVPOLL */
    
    /* Define to 1 if you have the <dlfcn.h> header file. */
    #define EVENT__HAVE_DLFCN_H 1
    
    /* Define if your system supports the epoll system calls */
    #define EVENT__HAVE_EPOLL 1
    
    /* Define to 1 if you have the `epoll_create1' function. */
    #define EVENT__HAVE_EPOLL_CREATE1 1
    
    /* Define to 1 if you have the `epoll_ctl' function. */
    #define EVENT__HAVE_EPOLL_CTL 1
    
    /* Define to 1 if you have the <errno.h> header file. */
    #define EVENT__HAVE_ERRNO_H 1
    
    /* Define to 1 if you have ERR_remove_thread_stat(). */
    #define EVENT__HAVE_ERR_REMOVE_THREAD_STATE 1
    
    /* Define to 1 if you have the `eventfd' function. */
    #define EVENT__HAVE_EVENTFD 1
    
    /* Define if your system supports event ports */
    /* #undef EVENT__HAVE_EVENT_PORTS */
    
    /* Define to 1 if you have the `fcntl' function. */
    #define EVENT__HAVE_FCNTL 1
    
    /* Define to 1 if you have the <fcntl.h> header file. */
    #define EVENT__HAVE_FCNTL_H 1
    
    /* Define to 1 if the system has the type `fd_mask'. */
    #define EVENT__HAVE_FD_MASK 1
    
    /* Do we have getaddrinfo()? */
    #define EVENT__HAVE_GETADDRINFO 1
    
    /* Define to 1 if you have the `getegid' function. */
    #define EVENT__HAVE_GETEGID 1
    
    /* Define to 1 if you have the `geteuid' function. */
    #define EVENT__HAVE_GETEUID 1
    
    /* Define this if you have any gethostbyname_r() */
    /* #undef EVENT__HAVE_GETHOSTBYNAME_R */
    
    /* Define this if gethostbyname_r takes 3 arguments */
    /* #undef EVENT__HAVE_GETHOSTBYNAME_R_3_ARG */
    
    /* Define this if gethostbyname_r takes 5 arguments */
    /* #undef EVENT__HAVE_GETHOSTBYNAME_R_5_ARG */
    
    /* Define this if gethostbyname_r takes 6 arguments */
    /* #undef EVENT__HAVE_GETHOSTBYNAME_R_6_ARG */
    
    /* Define to 1 if you have the `getifaddrs' function. */
    #define EVENT__HAVE_GETIFADDRS 1
    
    /* Define to 1 if you have the `getnameinfo' function. */
    #define EVENT__HAVE_GETNAMEINFO 1
    
    /* Define to 1 if you have the `getprotobynumber' function. */
    #define EVENT__HAVE_GETPROTOBYNUMBER 1
    
    /* Define to 1 if you have the `getservbyname' function. */
    #define EVENT__HAVE_GETSERVBYNAME 1
    
    /* Define to 1 if you have the `gettimeofday' function. */
    #define EVENT__HAVE_GETTIMEOFDAY 1
    
    /* Define to 1 if you have the <ifaddrs.h> header file. */
    #define EVENT__HAVE_IFADDRS_H 1
    
    /* Define to 1 if you have the `inet_ntop' function. */
    #define EVENT__HAVE_INET_NTOP 1
    
    /* Define to 1 if you have the `inet_pton' function. */
    #define EVENT__HAVE_INET_PTON 1
    
    /* Define to 1 if you have the <inttypes.h> header file. */
    #define EVENT__HAVE_INTTYPES_H 1
    
    /* Define to 1 if you have the `issetugid' function. */
    /* #undef EVENT__HAVE_ISSETUGID */
    
    /* Define to 1 if you have the `kqueue' function. */
    /* #undef EVENT__HAVE_KQUEUE */
    
    /* Define if the system has zlib */
    /* #undef EVENT__HAVE_LIBZ */
    
    /* Define to 1 if you have the `mach_absolute_time' function. */
    /* #undef EVENT__HAVE_MACH_ABSOLUTE_TIME */
    
    /* Define to 1 if you have the <mach/mach_time.h> header file. */
    /* #undef EVENT__HAVE_MACH_MACH_TIME_H */
    
    /* Define to 1 if you have the <memory.h> header file. */
    #define EVENT__HAVE_MEMORY_H 1
    
    /* Define to 1 if you have the `mmap' function. */
    #define EVENT__HAVE_MMAP 1
    
    /* Define to 1 if you have the `nanosleep' function. */
    #define EVENT__HAVE_NANOSLEEP 1
    
    /* Define to 1 if you have the <netdb.h> header file. */
    #ifndef WIN32
    #define EVENT__HAVE_NETDB_H 1
    #endif
    
    /* Define to 1 if you have the <netinet/in6.h> header file. */
    /* #undef EVENT__HAVE_NETINET_IN6_H */
    
    /* Define to 1 if you have the <netinet/in.h> header file. */
    #define EVENT__HAVE_NETINET_IN_H 1
    
    /* Define to 1 if you have the <netinet/tcp.h> header file. */
    #define EVENT__HAVE_NETINET_TCP_H 1
    
    /* Define if the system has openssl */
    #define EVENT__HAVE_OPENSSL 1
    
    /* Define to 1 if you have the `pipe' function. */
    #define EVENT__HAVE_PIPE 1
    
    /* Define to 1 if you have the `pipe2' function. */
    #define EVENT__HAVE_PIPE2 1
    
    /* Define to 1 if you have the `poll' function. */
    #define EVENT__HAVE_POLL 1
    
    /* Define to 1 if you have the <poll.h> header file. */
    #define EVENT__HAVE_POLL_H 1
    
    /* Define to 1 if you have the `port_create' function. */
    /* #undef EVENT__HAVE_PORT_CREATE */
    
    /* Define to 1 if you have the <port.h> header file. */
    /* #undef EVENT__HAVE_PORT_H */
    
    /* Define if you have POSIX threads libraries and header files. */
    /* #undef EVENT__HAVE_PTHREAD */
    
    /* Define if we have pthreads on this system */
    #define EVENT__HAVE_PTHREADS 1
    
    /* Define to 1 if you have the `putenv' function. */
    #define EVENT__HAVE_PUTENV 1
    
    /* Define to 1 if the system has the type `sa_family_t'. */
    #define EVENT__HAVE_SA_FAMILY_T 1
    
    /* Define to 1 if you have the `select' function. */
    #define EVENT__HAVE_SELECT 1
    
    /* Define to 1 if you have the `sendfile' function. */
    #define EVENT__HAVE_SENDFILE 1
    
    /* Define to 1 if you have the `setenv' function. */
    #define EVENT__HAVE_SETENV 1
    
    /* Define if F_SETFD is defined in <fcntl.h> */
    #define EVENT__HAVE_SETFD 1
    
    /* Define to 1 if you have the `setrlimit' function. */
    #define EVENT__HAVE_SETRLIMIT 1
    
    /* Define to 1 if you have the `sigaction' function. */
    #define EVENT__HAVE_SIGACTION 1
    
    /* Define to 1 if you have the `signal' function. */
    #define EVENT__HAVE_SIGNAL 1
    
    /* Define to 1 if you have the `splice' function. */
    #define EVENT__HAVE_SPLICE 1
    
    /* Define to 1 if you have the <stdarg.h> header file. */
    #define EVENT__HAVE_STDARG_H 1
    
    /* Define to 1 if you have the <stddef.h> header file. */
    #define EVENT__HAVE_STDDEF_H 1
    
    /* Define to 1 if you have the <stdint.h> header file. */
    #define EVENT__HAVE_STDINT_H 1
    
    /* Define to 1 if you have the <stdlib.h> header file. */
    #define EVENT__HAVE_STDLIB_H 1
    
    /* Define to 1 if you have the <strings.h> header file. */
    #define EVENT__HAVE_STRINGS_H 1
    
    /* Define to 1 if you have the <string.h> header file. */
    #define EVENT__HAVE_STRING_H 1
    
    /* Define to 1 if you have the `strlcpy' function. */
    /* #undef EVENT__HAVE_STRLCPY */
    
    /* Define to 1 if you have the `strsep' function. */
    #define EVENT__HAVE_STRSEP 1
    
    /* Define to 1 if you have the `strtok_r' function. */
    #define EVENT__HAVE_STRTOK_R 1
    
    /* Define to 1 if you have the `strtoll' function. */
    #define EVENT__HAVE_STRTOLL 1
    
    /* Define to 1 if the system has the type `struct addrinfo'. */
    #define EVENT__HAVE_STRUCT_ADDRINFO 1
    
    /* Define to 1 if the system has the type `struct in6_addr'. */
    #define EVENT__HAVE_STRUCT_IN6_ADDR 1
    
    /* Define to 1 if `s6_addr16' is a member of `struct in6_addr'. */
    #define EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR16 1
    
    /* Define to 1 if `s6_addr32' is a member of `struct in6_addr'. */
    #define EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR32 1
    
    /* Define to 1 if the system has the type `struct sockaddr_in6'. */
    #define EVENT__HAVE_STRUCT_SOCKADDR_IN6 1
    
    /* Define to 1 if `sin6_len' is a member of `struct sockaddr_in6'. */
    /* #undef EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN */
    
    /* Define to 1 if `sin_len' is a member of `struct sockaddr_in'. */
    /* #undef EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
    
    /* Define to 1 if the system has the type `struct sockaddr_storage'. */
    #define EVENT__HAVE_STRUCT_SOCKADDR_STORAGE 1
    
    /* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */
    #define EVENT__HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1
    
    /* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */
    /* #undef EVENT__HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY */
    
    /* Define to 1 if the system has the type `struct so_linger'. */
    /* #undef EVENT__HAVE_STRUCT_SO_LINGER */
    
    /* Define to 1 if you have the `sysctl' function. */
    #define EVENT__HAVE_SYSCTL 1
    
    /* Define to 1 if you have the <sys/devpoll.h> header file. */
    /* #undef EVENT__HAVE_SYS_DEVPOLL_H */
    
    /* Define to 1 if you have the <sys/epoll.h> header file. */
    
    #define EVENT__HAVE_SYS_EPOLL_H 1
    
    /* Define to 1 if you have the <sys/eventfd.h> header file. */
    #define EVENT__HAVE_SYS_EVENTFD_H 1
    
    /* Define to 1 if you have the <sys/event.h> header file. */
    /* #undef EVENT__HAVE_SYS_EVENT_H */
    
    /* Define to 1 if you have the <sys/ioctl.h> header file. */
    #define EVENT__HAVE_SYS_IOCTL_H 1
    
    /* Define to 1 if you have the <sys/mman.h> header file. */
    #define EVENT__HAVE_SYS_MMAN_H 1
    
    /* Define to 1 if you have the <sys/param.h> header file. */
    #define EVENT__HAVE_SYS_PARAM_H 1
    
    /* Define to 1 if you have the <sys/queue.h> header file. */
    #define EVENT__HAVE_SYS_QUEUE_H 1
    
    /* Define to 1 if you have the <sys/resource.h> header file. */
    #define EVENT__HAVE_SYS_RESOURCE_H 1
    
    /* Define to 1 if you have the <sys/select.h> header file. */
    #define EVENT__HAVE_SYS_SELECT_H 1
    
    /* Define to 1 if you have the <sys/sendfile.h> header file. */
    #define EVENT__HAVE_SYS_SENDFILE_H 1
    
    /* Define to 1 if you have the <sys/socket.h> header file. */
    #define EVENT__HAVE_SYS_SOCKET_H 1
    
    /* Define to 1 if you have the <sys/stat.h> header file. */
    #define EVENT__HAVE_SYS_STAT_H 1
    
    /* Define to 1 if you have the <sys/sysctl.h> header file. */
    #ifndef ANDROID
    #define EVENT__HAVE_SYS_SYSCTL_H 1
    #endif
    
    /* Define to 1 if you have the <sys/timerfd.h> header file. */
    #define EVENT__HAVE_SYS_TIMERFD_H 1
    
    /* Define to 1 if you have the <sys/time.h> header file. */
    #ifndef WIN32
    #define EVENT__HAVE_SYS_TIME_H 1
    #endif
    
    /* Define to 1 if you have the <sys/types.h> header file. */
    #define EVENT__HAVE_SYS_TYPES_H 1
    
    /* Define to 1 if you have the <sys/uio.h> header file. */
    #define EVENT__HAVE_SYS_UIO_H 1
    
    /* Define to 1 if you have the <sys/wait.h> header file. */
    #define EVENT__HAVE_SYS_WAIT_H 1
    
    /* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
    #define EVENT__HAVE_TAILQFOREACH 1
    
    /* Define if timeradd is defined in <sys/time.h> */
    #define EVENT__HAVE_TIMERADD 1
    
    /* Define if timerclear is defined in <sys/time.h> */
    #define EVENT__HAVE_TIMERCLEAR 1
    
    /* Define if timercmp is defined in <sys/time.h> */
    #define EVENT__HAVE_TIMERCMP 1
    
    /* Define to 1 if you have the `timerfd_create' function. */
    #define EVENT__HAVE_TIMERFD_CREATE 1
    
    /* Define if timerisset is defined in <sys/time.h> */
    #define EVENT__HAVE_TIMERISSET 1
    
    /* Define to 1 if the system has the type `uint16_t'. */
    #define EVENT__HAVE_UINT16_T 1
    
    /* Define to 1 if the system has the type `uint32_t'. */
    #define EVENT__HAVE_UINT32_T 1
    
    /* Define to 1 if the system has the type `uint64_t'. */
    #define EVENT__HAVE_UINT64_T 1
    
    /* Define to 1 if the system has the type `uint8_t'. */
    #define EVENT__HAVE_UINT8_T 1
    
    /* Define to 1 if the system has the type `uintptr_t'. */
    #define EVENT__HAVE_UINTPTR_T 1
    
    /* Define to 1 if you have the `umask' function. */
    #define EVENT__HAVE_UMASK 1
    
    /* Define to 1 if you have the <unistd.h> header file. */
    #define EVENT__HAVE_UNISTD_H 1
    
    /* Define to 1 if you have the `unsetenv' function. */
    #define EVENT__HAVE_UNSETENV 1
    
    /* Define to 1 if you have the `usleep' function. */
    #define EVENT__HAVE_USLEEP 1
    
    /* Define to 1 if you have the `vasprintf' function. */
    #define EVENT__HAVE_VASPRINTF 1
    
    /* Define if waitpid() supports WNOWAIT */
    /* #undef EVENT__HAVE_WAITPID_WITH_WNOWAIT */
    
    /* Define if kqueue works correctly with pipes */
    /* #undef EVENT__HAVE_WORKING_KQUEUE */
    
    /* Define to 1 if you have the <zlib.h> header file. */
    /* #undef EVENT__HAVE_ZLIB_H */
    
    /* Define to the sub-directory where libtool stores uninstalled libraries. */
    #define EVENT__LT_OBJDIR ".libs/"
    
    /* Numeric representation of the version */
    #define EVENT__NUMERIC_VERSION 0x02010800
    
    /* Name of package */
    #define EVENT__PACKAGE "libevent"
    
    /* Define to the address where bug reports for this package should be sent. */
    #define EVENT__PACKAGE_BUGREPORT ""
    
    /* Define to the full name of this package. */
    #define EVENT__PACKAGE_NAME "libevent"
    
    /* Define to the full name and version of this package. */
    #define EVENT__PACKAGE_STRING "libevent 2.1.8-stable"
    
    /* Define to the one symbol short name of this package. */
    #define EVENT__PACKAGE_TARNAME "libevent"
    
    /* Define to the home page for this package. */
    #define EVENT__PACKAGE_URL ""
    
    /* Define to the version of this package. */
    #define EVENT__PACKAGE_VERSION "2.1.8-stable"
    
    /* Define to necessary symbol if this constant uses a non-standard name on
       your system. */
    /* #undef EVENT__PTHREAD_CREATE_JOINABLE */
    
    /* The size of `int', as computed by sizeof. */
    #define EVENT__SIZEOF_INT 4
    
    /* The size of `long', as computed by sizeof. */
    #define EVENT__SIZEOF_LONG 8
    
    /* The size of `long long', as computed by sizeof. */
    #define EVENT__SIZEOF_LONG_LONG 8
    
    /* The size of `off_t', as computed by sizeof. */
    #define EVENT__SIZEOF_OFF_T 8
    
    /* The size of `pthread_t', as computed by sizeof. */
    #define EVENT__SIZEOF_PTHREAD_T 8
    
    /* The size of `short', as computed by sizeof. */
    #define EVENT__SIZEOF_SHORT 2
    
    /* The size of `size_t', as computed by sizeof. */
    #define EVENT__SIZEOF_SIZE_T 8
    
    /* The size of `void *', as computed by sizeof. */
    #define EVENT__SIZEOF_VOID_P 8
    
    /* Define to 1 if you have the ANSI C header files. */
    #define EVENT__STDC_HEADERS 1
    
    /* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
    #define EVENT__TIME_WITH_SYS_TIME 1
    
    /* Enable extensions on AIX 3, Interix.  */
    #ifndef EVENT___ALL_SOURCE
    # define EVENT___ALL_SOURCE 1
    #endif
    /* Enable GNU extensions on systems that have them.  */
    #ifndef EVENT___GNU_SOURCE
    # define EVENT___GNU_SOURCE 1
    #endif
    /* Enable threading extensions on Solaris.  */
    #ifndef EVENT___POSIX_PTHREAD_SEMANTICS
    # define EVENT___POSIX_PTHREAD_SEMANTICS 1
    #endif
    /* Enable extensions on HP NonStop.  */
    #ifndef EVENT___TANDEM_SOURCE
    # define EVENT___TANDEM_SOURCE 1
    #endif
    /* Enable general extensions on Solaris.  */
    #ifndef EVENT____EXTENSIONS__
    # define EVENT____EXTENSIONS__ 1
    #endif
    
    
    /* Version number of package */
    #define EVENT__VERSION "2.1.8-stable"
    
    /* Enable large inode numbers on Mac OS X 10.5.  */
    #ifndef EVENT___DARWIN_USE_64_BIT_INODE
    # define EVENT___DARWIN_USE_64_BIT_INODE 1
    #endif
    
    /* Number of bits in a file offset, on hosts where this is settable. */
    /* #undef EVENT___FILE_OFFSET_BITS */
    
    /* Define for large files, on AIX-style hosts. */
    /* #undef EVENT___LARGE_FILES */
    
    /* Define to 1 if on MINIX. */
    /* #undef EVENT___MINIX */
    
    /* Define to 2 if the system does not provide POSIX.1 features except with
       this defined. */
    /* #undef EVENT___POSIX_1_SOURCE */
    
    /* Define to 1 if you need to in order for `stat' and other things to work. */
    /* #undef EVENT___POSIX_SOURCE */
    
    /* Define to appropriate substitue if compiler doesnt have __func__ */
    /* #undef EVENT____func__ */
    
    /* Define to empty if `const' does not conform to ANSI C. */
    /* #undef EVENT__const */
    
    /* Define to `__inline__' or `__inline' if that's what the C compiler
       calls it, or to nothing if 'inline' is not supported under any name.  */
    #ifndef EVENT____cplusplus
    /* #undef EVENT__inline */
    #endif
    
    /* Define to `int' if <sys/types.h> does not define. */
    /* #undef EVENT__pid_t */
    
    /* Define to `unsigned int' if <sys/types.h> does not define. */
    /* #undef EVENT__size_t */
    
    /* Define to unsigned int if you dont have it */
    /* #undef EVENT__socklen_t */
    
    /* Define to `int' if <sys/types.h> does not define. */
    /* #undef EVENT__ssize_t */
    
    #ifdef ANDROID
    #undef EVENT__HAVE_ARC4RANDOM
    #undef EVENT__HAVE_ARC4RANDOM_BUF
    #undef EVENT__HAVE_FD_MASK
    #undef EVENT__HAVE_SYS_TIMERFD_H
    #undef EVENT__HAVE_EPOLL_CREATE
    #undef EVENT__HAVE_GETIFADDRS
    #endif
    
    #endif /* event2/event-config.h */
    

    5. 使用ndk命令进行编译

    进入源码目录,输入命令

    ndk-build.cmd NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk

    arm64-v8a编译通过

     

    展开全文
  • libevent介绍

    万次阅读 2011-12-05 11:05:43
    libevent讲解  什么是libevent libevent 是一个轻量级的事件触发的网络库。它适用于windows、linux、bsd等多种平台,它是跨平台的。libevent是c语言编写的一个开源的网络库。 libevent 的设计目标是: 1、可...
      
    

    libevent讲解

     什么是libevent

    libevent 是一个轻量级的事件触发的网络库。它适用于windows、linux、bsd等多种平台,它是跨平台的。libevent是c语言编写的一个开源的网络库。

    libevent 的设计目标是:

    1、可移植性,它是跨平台的。
    2、效率高。基于事件驱动(event-driven),采用非阻塞I/O,对事件异步处理;

           libevent API提供了一种当某事件的条件发生时再去调用回调函数去处理机制。事件条件的触发一般是文件描述符可读或可写,定时器时间到;回调函数一般是调用者事先编好的处理函数。这种异步机制类似于linux信号的异步处理机制。

    3、可扩展性。既使活动的套接字达到成千上万,它也能很好的工作。(有关于讨论如果连接数上万会有某些瓶颈,我还没来得及深究,暂时没有能力对它评价)

    4、轻量级,专注于底层网络库;

    5、使用方便。用libevent编写程序的方式应该是稳定的、可移植的。

    另外,libevent还有如下特点:

    1、支持多种I/O多路复用技术;

    几乎所有UNIX平台都支技的poll、select,Linux的epoll,以Solaris为主的/dev/pool,以BSD平台为主的kquque;libevent对这些接口进行了条件预编译封装,从而到了跨平台。
    2、支持异步I/O,定时器和信号等事件,宏观上对这三种事件的处理集成在一起;
    3、对注册好的事件进行了等待分类,就绪优先级调用;

    当添加的是事件是I/O、信号事件时,它会分别加到这两个双链表中,如果是定时器事件,会加一个以时间作为key小根堆中,libevent 之前对定时事件的管理用的是红黑树,小根堆相对而言查找效率上高一些;调度就绪链表是分级的双向链表。

           4、支持多线程。

    libevent1.4.7及以前版本已经弃用,1..3之前的版本有不少bug。libevent当前的最新稳定版是2.0.16。

    libevent从1.2.* 版本开始支持轻量级的http server 开发,随后陆续还推出轻量级 DNS server、RPC server 开发。

    libevent已经被广泛的应用,作为底层的网络库;目前有应用到libevent的应用有:

    The usefulness of libevent API is demonstrated by the following applications:

    • Chromium – Google's open-source web browser (uses Libevent on Mac and Linux)
    • Memcached – a high-performance, distributed memory object caching system
    • Transmission – a fast, easy, and free BitTorrent client
    • NTP – the network time protocol that makes your clock right (uses Libevent in SNTP)
    • tmux – A clean, modern, BSD-licensed terminal multiplexer, similar to GNU screen
    • Tor – an anonymous Internet communication system.
    • libevhtp – A fast and flexible replacement for libevent's httpd API
    • Prosody – A Jabber/XMPP server written in Lua
    • PgBouncer – Lightweight connection pooler for PostgreSQL
    • redsocks – a simple transparent TCP -> Socks5/HTTPS proxy daemon.
    • Vomit – Voice Over Misconfigured Internet Telephones
    • Crawl – A Small and Efficient HTTP Crawler
    • Libio – an input/output abstraction library
    • Honeyd – a virtual honeynet daemon – can be used tofight Internet worms.
    • Fragroute – an IDS testing tool
    • Nylon – nested proxy server
    • Disconcert – a Distributed Computing Framework for Loosely-Coupled Workstations.
    • Trickle – a lightweight userspace bandwidth shaper.
    • watchcatd – software watchdog designed to take actions not as drastic as the usual solutions, which reset the machine.
    • ScanSSH – a fast SSH server and open proxy scanner.
    • Nttlscan – a network topology scanner for Honeyd.
    • NetChat – a combination of netcat and ppp's chat.
    • Io – a small programming language; uses libevent for network communication.
    • Systrace – a system call sandbox.
    • SpyBye – detect malware on web pages.
    • GreenSQL – an SQL database firewall.
    • dnsscan – a fast scanner for identifying open recursive dns resolvers
    • Kargo Event – a PHP extension for libevent.
    • wlmproxy – a transparent proxy server for the MSN Messenger protocol

     

    Libevent的安装

    1、先从官网www.libevent.org下载最新的稳定版本,我前两天下载最新的是libevent-2.0.15-stable,现在更新到libevent-2.0.16-stable了;

    2、将软件包解压。如果是从windows平台通过软件连接到linux服务器的,可能要以解压的文件修改权限,通常添加一个可执行权限就可正常安装了;

    3、在解压的文件夹目录下,./configure;

    4、make;

    5、sudo make install;

    如果这几个步骤都没有出现错误,说明已经安装好,可以下面命令查看安装的库文件。

    ls -al /usr/lib | grep libevent(或 ls -al /usr/local/lib | grep libevent,取决于你安装在哪个目录下面),输出一些库文件信息,说明真的安装好了。

    编译时加上选项     -levent。如gcc test.c –o test –levent.

    我在编写一个小程序测试的时候,发现了一个有意思的小问题。我的小程序是输出libevent的版本号,我安装的是libevent-2.0.15-stable,结果它却输出了1.4.12-stable,怎么会输出这么老掉牙的版本号?我就纳闷了,去/usr/lib/目录查看,发现里面的库文件确实是1.4.12,我再去/usr/local/lib/下面查看,发现我的libevent装在这个目录下了。原来,那个老版本是同事之前装memcache的时候装上去的,系统优先找到这个目录下面的库文件。那我怎样使用的我最近安装的新版本库呢?其实很简单,不需要卸载旧版本,只要在编译时加上选项-L/usr/local/lib/来告编译器你要使用的库文件在这个目录就可以了。如,我用gcc test.c –o test -L/usr/local/lib/ -levent,一切OK,输出了新版本号2.0.15-stable。

    顺便说一下编写程序添加libevent头文件的问题。老版本是include <event.h>,新版本是用include <event2/event.h>,至于从哪个版本开始使用include <event2/event.h>我就没有考证了,当然老版本是兼容旧版本的。新版本改进了老版本的一些接口,也增加了一些新的接口。

     

    Libevent整体结构

          libevent分成下面几个组件:

    1、  evutil

    其功能是抽象出不同平台网络实现差异的通用性。

    2、  event and event_base

    这这两者libevent的核心。它提供了支持不同平台特有的,基于事件驱动的非阻塞IO的抽象接口。它可以通知你文件描述符在何时可读或可写,处理基本的定时事件以及检测系统信号,然后调用相应的回调函数进行处理。

    Event是libevent的基本操作单元。每个event都有一组触发事件的条件,包括:

    ·         A file descriptor being ready to read from or write to.

    ·         A file descriptor becoming ready to read from or write to (Edge-triggered IO only).

    ·         A timeout expiring.

    ·         A signal occurring.

    ·         A user-triggered event.

      Events have similar lifecycles. Once you call a Libevent function to set up an event and associate it with an event base, it becomesinitialized. At this point, you can add, which makes itpending in the base. When the event is pending, if the conditions that would trigger an event occur (e.g., its file descriptor changes state or its timeout expires), the event becomesactive, and its (user-provided) callback function is run. If the event is configuredpersistent, it remains pending. If it is not persistent, it stops being pending when its callback runs. You can make a pending event non-pending bydeleting it, and you can add a non-pending event to make it pending again.

             这里提到了event的几种状态,我在啰嗦一遍:

    ★初始化状态

        创建event,配置event的基本信息,将event与event_base邦定,完成这个过程event就被初始化了,调用event_new()就可以完成这个过程。

    ★未决状态

             Event初始化后,再调用event_add()将event添加到监视事件集中,event就变成的未决状态。

    ★激活状态

             当事件的触发条件发生时,event就变成了激活状态,然后会调用回调函数做相应的操作。

     

    3、  bufferevent

    为libevent基于事件的核心提供使用更方便的封装。除了通知程序套接字已经准备好读写之外,还让程序可以请求缓冲的读写操作,可以知道何时IO已经真正发生。(bufferevent接口有多个后端,可以采用系统能够提供的更快的非阻塞IO方式,如Windows中的IOCP。)

    4、 evbuffer

    在bufferevent层之下实现了缓冲功能,并且提供了方便有效的访问函数。

    5、 evhttp

    一个简单的HTTP客户端/服务器实现。

    6、 evdns

    一个简单的DNS客户端/服务器实现。

    7、 evrpc

    一个简单的RPC实现。

          libevent安装后的库文件

        安装libevent时,默认安装下列库:

    v libevent_core:所有核心的事件和缓冲功能,包含了所有的event_base、evbuffer、bufferevent和工具函数。

    v libevent_extra:定义了程序可能需要,也可能不需要的协议特定功能,包括HTTP、DNS和RPC。

    v libevent:这个库因为历史原因而存在,它包含libevent_core和libevent_extra的内容。不应该使用这个库,未来版本的libevent可能去掉这个库。

    某些平台上可能安装下列库:

    v libevent_pthreads:添加基于pthread可移植线程库的线程和锁定实现。它独立于libevent_core,这样程序使用libevent时就不需要链接到pthread,除非是以多线程方式使用libevent。

    v libevent_openssl:这个库为使用bufferevent和OpenSSL进行加密的通信提供支持。它独立于libevent_core,这样程序使用libevent时就不需要链接到OpenSSL,除非是进行加密通信。

     

          libevent的头文件

    libevent公用头文件都安装在event2目录中,分为三类:

    v API头文件:定义libevent公用接口。这类头文件没有特定后缀。

    To browse the complete documentation of the libevent API, click on any of the following links.

    event2/event.h The primary libevent header

    event2/thread.h Functions for use by multithreaded programs

    event2/buffer.h andevent2/bufferevent.h Buffer management for network reading and writing

    event2/util.h Utility functions for portable nonblocking network code

    event2/dns.h Asynchronous DNS resolution

    event2/http.h An embedded libevent-based HTTP server

    event2/rpc.h A framework for creating RPC servers and clients

     

    v 兼容头文件:文件名有后缀compat,为已废弃的函数提供兼容的头部包含定义。不应该使用这类头文件,除非是在移植使用较老版本libevent的程序时。

    v 结构头文件:这类头文件以相对不稳定的布局定义各种结构体。这些结构体中的一些是为了提供快速访问而暴露;一些是因为历史原因而暴露。直接依赖这类头文件中的任何结构体都会破坏程序对其他版本libevent的二进制兼容性,有时候是以非常难以调试的方式出现。这类头文件具有后缀“_struct.h”。

    (还存在 一些在../event2目录中的较老版本libevent的头文件,请参考下节:如果需要使用老版本libevent)

    libevent 2.0.*以更合理的、不易出错的方式修正了API。如果可能,编写新程序时应该使用libevent 2.0。但是有时候可能需要使用较老的API,例如在升级已存的应用时,或者支持因为某些原因不能安装2.0或者更新版本libevent的环境时。

    较老版本的libevent头文件较少,也不安装在event2目录中。在2.0以及以后版本的libevent中,老的头文件仍然会作为新头文件的封装而存在。

    其他关于使用较老版本的提示:

    v 1.4版之前只有一个库libevent,它包含现在分散到libevent_core和libevent_extra中的所有功能。

    v 2.0版之前不支持锁定:只有确定不同时在多个线程中使用同一个结构体时,libevent才是线程安全的。

    下面的节还将讨论特定代码区域可能遇到的已经废弃的API。

    libevent源代码文件的说明

             ps:此节引用于“libevent源码深度剖析”

     

    Libevent的源代码虽然都在一层文件夹下面,但是其代码分类还是相当清晰的,主要可分为头文件、内部使用的头文件、辅助功能函数、日志、libevent框架、对系统I/O多路复用机制的封装、信号管理、定时事件管理、缓冲区管理、基本数据结构和基于libevent的两个实用库等几个部分。源代码中的test和sample文件夹下面就是一些测试的例子了,可以拿来学习试手。
    1)头文件
    主要就是event.h:事件宏定义、接口函数声明,主要结构体event的声明;
    2)内部头文件
    xxx-internal.h:内部数据结构和函数,对外不可见,以达到信息隐藏的目的;
    3)libevent框架
    event.c:event整体框架的代码实现;
    4)对系统I/O多路复用机制的封装
    epoll.c:对epoll的封装;

    select.c:对select的封装;
    devpoll.c:对dev/poll的封装;
    kqueue.c:对kqueue的封装;
    5)定时事件管理
    min-heap.h:其实就是一个以时间作为key的小根堆结构;
    6)信号管理
    signal.c:对信号事件的处理;
    7)辅助功能函数
    evutil.h 和evutil.c:一些辅助功能函数,包括创建socket pair和一些时间操作函数:加、减和比较等。
    8)日志
    log.h和log.c:log日志函数
    9)缓冲区管理
    evbuffer.c和buffer.c:libevent对缓冲区的封装;
    10)基本数据结构
    compat/sys下的两个源文件:queue.h是libevent基本数据结构的实现,包括链表,双向链表,队列等;_libevent_time.h:一些用于时间操作的结构体定义、函数和宏定义;
    11)实用网络库
    http和evdns:是基于libevent实现的http服务器和异步dns查询库;

     

    libevent事件处理流程

    ps:此节引用于“libevent源码深度剖析”

     

    当应用程序向libevent 注册一个事件后,libevent 内部是怎么样进行处理的呢?下面的

    图就给出了这一基本流程。

    1 )  首先应用程序准备并初始化event,设置好事件类型和回调函数;这对应于前面第步骤

    2 和3 ;

    2 )  向libevent 添加该事件 event。对于定时事件,libevent 使用一个小根堆管理,key 为超

    时时间;对于 Signal 和I/O 事件,libevent 将其放入到等待链表(wait list)中,这是一

    个双向链表结构;

    3 )  程序调用event_base_dispatch() 系列函数进入无限循环,等待事件,以select() 函数为例;

    每次循环前libevent 会检查定时事件的最小超时时间 tv ,根据 tv 设置select() 的最大等

    待时间,以便于后面及时处理超时事件;

    当select() 返回后,首先检查超时事件,然后检查I/O 事件;

      11

    Libevent 将所有的就绪事件,放入到激活链表中;

    然后对激活链表中的事件,调用事件的回调函数执行事件处理;

    libevent对event 的管理

    从event 结构体中的 3 个链表节点指针和一个堆索引出发,大体上也能窥出 libevent 对

    event的管理方法了,可以参见下面的示意图。每次当有事件event转变为就绪状态时,libevent 就会把它移入到active event list[priority]中,其中priority是event的优先级;

    接着libevent 会根据自己的调度策略选择就绪事件,调用其cb_callback()函数执行事件

    处理;并根据就绪的句柄和事件类型填充cb_callback 函数的参数。

     

    libevent的一般编程思路

    创建event_base实例

    (1) struct event_base *event_base_new(void);方法,创建默认的event_base

            注意:老版本是用struct event_base *event_init(void),这个函数在新版本中已经弃用,因为它会初始化当前event_base,在使用多线程的时候是不安全的。

    (2) event_base_new_with_config(),创建带配置的event_base.

    调用接口:

    struct event_config *event_config_new(void);

    struct event_base *event_base_new_with_config(conststruct event_config *cfg);

    void event_config_free(struct event_config *cfg);

            

    event_baselibevent的中心,每个应用必须有一个,它监视事件未决和活动的事件,并且通知应用程序活动的事件,好让应用程序在事件发生时调用回调函数对它们进行处理。

     

     

     

     

    创建event对象

     

    对于一个我们想监视的文件描述符,首先得建一个event结构体,然后将fdeventfd成员邦定在一起。建一个event结构体方法可以是:

    1event_new()方法

    接口:

    #define EV_TIMEOUT     0x01

    #define EV_READ        0x02

    #define EV_WRITE       0x04

    #define EV_SIGNAL      0x08

    #define EV_PERSIST     0x10

    #define EV_ET          0x20   // edge-triggered

     

    typedefvoid (*event_callback_fn)(evutil_socket_t,short,void *);

     

    struct event *event_new(struct event_base *base, evutil_socket_t fd,

       short what, event_callback_fn cb,

       void *arg);

     

    void event_free(struct event *event);

     

    The event_new() function tries to allocate and construct a new event for use withbase. The what argument is a set of the flags listed above. (Their semantics are described below.) Iffd is nonnegative, it is the file that we’ll observe for read or write events. When the event is active, Libevent will invoke the providedcb function, passing it as arguments: the file descriptorfd, a bitfield ofall the events that triggered, and the value that was passed in forarg when the function was constructed.

    All new events are initialized and non-pending. To make an event pending, call event_add() (documented below).

    To deallocate an event, call event_free().It is safe to call event_free() on an event that is pending or active: doing so makes the event non-pending and inactive before deallocating it.

    函数说明:

    struct event *event_new(struct event_base *base, evutil_socket_t fd,

       short what, event_callback_fn cb,

       void *arg)

    Parameters:

     

    base 

    the event base to which the event should be attached.

     

    fd 

    the file descriptor or signal to be monitored, or -1.

     

    what 

    desired events to monitor: bitfield of EV_READ, EV_WRITE, EV_SIGNAL, EV_PERSIST, EV_ET.

     

    cb 

    callback function to be invoked when the event occurs

     

    arg 

    an argument to be passed to the callback function

         

    Returns:

    a newly allocated struct event that must later be freed withevent_free().

            Or,    on an internal error, or invalid arguments, event_new() will return NULL

    注:当参数fd-1时,事件只能被定时器触发或用event_active()手动活激事件。

    The event flags

    EV_TIMEOUT

    This flag indicates an event that becomes active after a timeout elapses.

    The EV_TIMEOUT flag is ignored when constructing an event: you
    can either set a timeout when you add the event, or not.  It is
    set in the 'what' argument to the callback function when a timeout
    has occurred.

    EV_READ

    This flag indicates an event that becomes active when the provided file descriptor is ready for reading.

    EV_WRITE

    This flag indicates an event that becomes active when the provided file descriptor is ready for writing.

    EV_SIGNAL

    Used to implement signal detection. See "Constructing signal events" below.

    EV_PERSIST

    Indicates that the event ispersistent. See "About Event Persistence" below.

    EV_ET

    Indicates that the event should be edge-triggered, if the underlying event_base backend supports edge-triggered events. This affects the semantics of EV_READ and EV_WRITE.

    Since Libevent 2.0.1-alpha, any number of events may be pending for the same conditions at the same time. For example, you may have two events that will become active if a given fd becomes ready to read. The order in which their callbacks are run is undefined.

    These flags are defined in <event2/event.h>. All have existed since before Libevent 1.0, except for EV_ET, which was introduced in Libevent 2.0.1-alpha.

    About Event Persistence

    By default, whenever a pending event becomes active (because its fd is ready to read or write, or because its timeout expires), it becomes non-pending right before its callback is executed. Thus, if you want to make the event pending again, you can call event_add() on it again from inside the callback function.

    If the EV_PERSIST flag is set on an event, however, the event ispersistent. This means that event remains pending even when its callback is activated. If you want to make it non-pending from within its callback, you can call event_del() on it.

    The timeout on a persistent event resets whenever the event’s callback runs. Thus, if you have an event with flags EV_READ|EV_PERSIST and a timeout of five seconds, the event will become active:

    ·        Whenever the socket is ready for reading.

    ·        Whenever five seconds have passed since the event last became active.

     

     

    See also:

    event_free(),event_add(),event_del(),event_assign()

     

    (1)    也可以先申明一个结构体,然后调用event_assign()来初始化结构体成员。

    创建好event后,用event_add()添加事件通知。这个结构最好分配在堆上,因为event_base要一直对它监视,直到你把它撤销。

     

    int event_assign

    (

    structevent

    ,

       

    structevent_base

    ,

       

    evutil_socket_t 

    ,

       

    short 

    ,

       

    event_callback_fn 

    ,

       

    void * 

     

     

     

    )

         

    Parameters:

     

    ev 

    an event struct to be modified

     

    base 

    the event base to which ev should be attached.

     

    fd 

    the file descriptor to be monitored

     

    events 

    desired events to monitor; can be EV_READ and/or EV_WRITE

     

    callback 

    callback function to be invoked when the event occurs

     

    callback_arg 

    an argument to be passed to the callback function

    Returns:

    0 if success, or -1 on invalid arguments.

     

    int event_add

    (

    structevent

    ev,

       

    const struct timeval * 

    timeout

     

     

    )

         

    Add an event to the set of pending events.

    The functionevent_add() schedules the execution of the ev event when the event specified in event_assign()/event_new() occurs, or when the time specified in timeout has elapesed. If atimeout is NULL, no timeout occurs and the function will only be called if a matching event occurs. The event in the ev argument must be already initialized byevent_assign() or event_new() and may not be used in calls to event_assign() until it is no longer pending.

       If the event in the ev argument already has a scheduled timeout, callingevent_add() replaces the old timeout with the new one, or clears the old timeout if the timeout argument is NULL.

    If you call event_add() on an event that isalready pending, it will leave it pending, and reschedule it with the provided timeout

     

    Note

    Do not settv to the time at which you want the timeout to run. If you say "tv→tv_sec = time(NULL)+10;" on 1 January 2010, your timeout will wait 40 years, not 10 seconds

     

    Parameters:

     

    ev 

    an event struct initialized viaevent_set()

     

    timeout 

    the maximum amount of time to wait for the event, or NULL to wait forever

    Returns:

    0 if successful, or -1 if an error occurred

     

     

     

     

    老版本使用下面的的接口,创建event ,eventevent_base邦定,现在已弃用:

    void event_set(struct event *event, evutil_socket_t fd, short what,

           void(*callback)(evutil_socket_t,short,void *),void *arg);

    int event_base_set(struct event_base *base, struct event *event);

    Deprecated:

    event_set() is not recommended for new code, because it requires a subsequent call to event_base_set() to be safe under most circumstances. Use event_assign() or event_new() instead.

     

     

    相关函数:

    1.判断event的是否存在指定的未决事件

    int event_pending

    (

    const structevent

    ev,

       

    short 

    events,

       

    struct timeval * 

    tv

     

     

    )

         

    Checks if a specific event is pending or scheduled.

    Parameters:

     

    ev 

    an event struct previously passed toevent_add()

     

    events 

    the requested event type; any of EV_TIMEOUT|EV_READ| EV_WRITE|EV_SIGNAL

     

    tv 

    if this field is not NULL, and the event has a timeout, this field is set to hold the time at which the timeout will expire.

    Returns:

    true if the event is pending on any of the events in 'what', (that is to say, it has been added), or 0 if the event is not added.

    2.设置event的优先级

    int event_priority_set

    (

    structevent

    ,

       

    int 

     

     

     

    )

         

    Assign a priority to an event.

    Parameters:

     

    ev 

    an event struct

     

    priority 

    the new priority to be assigned

    Returns:

    0 if successful, or -1 if an error occurred

    See also:

    event_priority_init()

    3.重新初始化event,与fork结合使用

    int event_reinit

    (

    structevent_base

    base

     ) 

     

    Reinitialize the event base after a fork.

    Some event mechanisms do not survive across fork. The event base needs to be reinitialized with theevent_reinit() function.

    Parameters:

     

    base 

    the event base that needs to be re-initialized

    Returns:

    0 if successful, or -1 if some events could not be re-added.

    See also:

    event_base_new()

     

    更多参考信息,请查看官网推建的资料

    http://www.wangafu.net/~nickm/libevent-book/

     

    调用event_base_dispatch()

    让它一直循环,调度事件。

     

            还有一个与它功能相似但比它复杂的函数event_base_loop(),它带有两个运行标志。

    Event dispatching loop.

    This loop will run the event base until either there are no more added events, or until something callsevent_base_loopbreak() or event_base_loopexit().

    Parameters:

     

    base 

    theevent_base structure returned by event_base_new() or event_base_new_with_config()

    Returns:

    0 if successful, -1 if an error occurred, or 1 if no events were registered.

    See also:

    event_base_loop()

     

     

    int event_base_loop

    (

    structevent_base

    ,

       

    int 

     

     

     

    )

         

    Wait for events to become active, and run their callbacks.

    This is a more flexible version ofevent_base_dispatch().

    By default, this loop will run the event base until either there are no more added events, or until something callsevent_base_loopbreak() or evenet_base_loopexit(). You can override this behavior with the 'flags' argument.

    Parameters:

     

    eb 

    theevent_base structure returned by event_base_new() or event_base_new_with_config()

     

    flags 

    any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK

    Returns:

    0 if successful, -1 if an error occurred, or 1 if no events were registered.

    See also:

    event_base_loopexit(),event_base_dispatch(),EVLOOP_ONCE,EVLOOP_NONBLOCK

     

     

     

     

    libevent连接监听器:接收TCP的连接

            Ps:此节翻译于http://www.wangafu.net/~nickm/libevent-book/Ref8_listener.html

     

    libevent基于事件的连接监听机制,给了我们一种监听并且接收到达的TCP连接。

    这个模块的所有函数和类型都定义在event2/listener.h当中。除非特别注明,它们第一次出现在Libevent 2.0.2-alpha版本中。

    创建和释放一个连接监听器对象

    调用接口:

    struct evconnlistener *evconnlistener_new(struct event_base *base,

       evconnlistener_cb cb, void *ptr,unsigned flags,int backlog,

       evutil_socket_t fd);

    struct evconnlistener *evconnlistener_new_bind(struct event_base *base,

       evconnlistener_cb cb, void *ptr,unsigned flags,int backlog,

       conststruct sockaddr *sa,int socklen);

    void evconnlistener_free(struct evconnlistener *lev);

     

    前面两个函数都会返回在内存分配好的监听器对象。监听器利用event_base通知何时在一个指定的监听套接字上会有一个新的TCP连接。当新连接到达时,它会调用给定的回调函数cb

    参数说明:

    Base                  监听新连接的到达

    Cb             新连接的到达时调用的回调函数

    Ptr            将传递给回调函数

    Flags        控制监听器的行为。下面会细讲。

    Backlog   最大未决连接数。未决连接:还没被接受的连接(原文:Thebacklog parameter controls the maximum number of pending connections that the network stack should allow to wait in a not-yet-accepted state at any time)。如果blacklog为负,libevent会尽量给一个合适的值。如果它为0libevent认为你已经在给定的socket上调用的listen()

    前面两个函数的不同点,如果之前已经邦定了socket的端口,则调用evconnlistener_new()fd就是已经邦定了端口的socket。如果你想让libevent分配和邦定一个socket,则调用evconnlistener_new_bind()

    释放连接监听器用evconnlistener_free().

     

    Flags细讲:它是一个位或参数,可是下面的宏。

    LEV_OPT_LEAVE_SOCKETS_BLOCKING

          默认,当监听器收到一个新的socke,会把设为非阻塞。

    LEV_OPT_LEAVE_SOCKETS_BLOCKING

          当释放一个监听器对象时,会把下面的所有监听的socket关闭掉。

          LEV_OPT_CLOSE_ON_EXEC

                 在监听的socket上设置close-on-exec

          LEV_OPT_REUSEABLE

                 在一些平台上,当一个socket被关闭时,它的端口要过一会儿才能被其它socket邦定。LEV_OPT_REUSEABLE使得这个廷时消失。

    LEV_OPT_THREADSAFE

          为监听器加锁,出于多线程方面的安全。

     

    连接监听器的回调函数

    调用接口:

    typedefvoid (*evconnlistener_cb)(struct evconnlistener *listener,

       evutil_socket_t sock, struct sockaddr *addr,int len,void *ptr);

            当新连接到达时,回调函数将会被调用。

    参数说明:

    Listener            接收连接的监听器。

    Sock                   一个新socket

    Addrlen      接收连接的地址和它的长度

    Ptr                     来自于evconnlistener_new()的参数ptr

     

     

    启用和禁用监听器对象

            用来临时地启用和禁用监听器对象监听新连接。

    调用接口:

    int evconnlistener_disable(struct evconnlistener *lev);

    int evconnlistener_enable(struct evconnlistener *lev);

     

     

    更改监听器对象的回调函数

    调用接口:

    void evconnlistener_set_cb(struct evconnlistener *lev,

       evconnlistener_cb cb, void *arg);

     

     

    查询监听器对象的socketevent_base

    调用接口:

    evutil_socket_t evconnlistener_get_fd(struct evconnlistener *lev);

    struct event_base *evconnlistener_get_base(struct evconnlistener *lev);

    查看错误

    调用接口:

    typedefvoid (*evconnlistener_errorcb)(struct evconnlistener *lis, void *ptr);

    void evconnlistener_set_error_cb(struct evconnlistener *lev,

       evconnlistener_errorcb errorcb);

    你可以设置一个检测错误的回调函数,用来检测监听器对象调用accept()失败的错误。检测错误的回调函数都会在每次发生错误时被调用。这个回调函数的第一个参数是监听器对象,第二个参数是evconnlistener_new()ptr参数。

     

    Bufferevents:概念与基础

    Ps:本节译自http://www.wangafu.net/~nickm/libevent-book/Ref6_bufferevent.html

     

    Libevent提供了一个读写缓冲机制,并且不同的缓冲事件类型可以共用同一个接口。

    有以下几种缓冲事件类型:

    socket-based bufferevents

            socket流的接收和发送缓冲。

    asynchronous-IO bufferevents

          利用Windows IOCP接口向一个socket流接收和发送数据的缓冲,只能用于Windows

    filtering bufferevents

            在把数据传给bufferevent的使用对象之前,可以对接收和发送的数据进行处理——比如,压缩和转化数据——的缓冲。

    paired bufferevents

            可以把一个bufferevents把数据传到另一个buffereventsbufferevents对。

     

    注意:截至Libevent 2.0.2-alpha版本,并不是下面每一个描述的接口都适用于所有buffervent类型,不过这个缺点可能会在以后的版本中改进。Bufferevents目前只支持面向流的TCP,在以后版本中可能会去持面向数据报的UDP

     

          每一个bufferevent都有一个输入缓冲和一个输出缓冲。这些都定义在struct evbuffer当中。当有数据写时,就把它写入输出缓冲;当有数据读时,就从输入缓冲读出。

          每一个bufferevent都有一个与数据相关的回调函数:读回调函数和写回调函数。默认地,当传输层有任何数据可读时会调用读回调函数;当输出缓冲有足够的数据写入传输层时,将调用写回调函数“清空”(写入传输层)输出缓冲。你可以调节bufferevent的读/写“水印标记”(上/下限)来改变回调函数的调用次数。

          每一个bufferevent都有四个“水印标记”:

    Read low-water mark——输入缓冲的下限

          当读事件发现使得bufferevent的输入缓冲大于等于这个值,读回调函数将会被调用。默认为0,以便每次读都会调用读回调函数。

    Read high-water mark——输入缓冲的上限

          bufferevent的输入缓冲的数据量达到这个值时,bufferevent就会停止读,直到足够的数据从输入缓冲取走使得输入缓冲的数据量低于这个值。默认为无限大,以便bufferevent不会因为输入缓冲的大小面停止读。

    Write low-water mark——输出缓冲下限

          当一次写操作发生使得输出缓冲的数据量少于等于这个值时,写回调函数将被调用。默认为0,以便只有当输出缓冲为空时才调用写回调函数。

    Write high-water mark——输出缓冲上限

          这个值不是被bufferevent直接使用,在bufferevent被用作另一个bufferevent的传输层时,它有特别的意义,可以查看filtering bufferevents对它的使用。

    socket-based bufferevents

    创建一个socket-based bufferevent

    调用接口:

    struct bufferevent *bufferevent_socket_new(

       struct event_base *base,

       evutil_socket_t fd,

       enum bufferevent_options options);

    Thebase is an event_base, and options is a bitmask of bufferevent options (BEV_OPT_CLOSE_ON_FREE, etc). Thefd argument is an optional file descriptor for a socket. You can set fd to -1 if you want to set the file descriptor later.

    This function returns a bufferevent on success, and NULL on failure.

    The bufferevent_socket_new() function was introduced in Libevent 2.0.1-alpha.

    Options说明:

    BEV_OPT_CLOSE_ON_FREE

    When the bufferevent is freed, close the underlying transport. This will close an underlying socket, free an underlying bufferevent, etc.

    BEV_OPT_THREADSAFE

    Automatically allocate locks for the bufferevent, so that it’s safe to use from multiple threads.

    BEV_OPT_DEFER_CALLBACKS

    When this flag is set, the bufferevent defers all of its callbacks, as described above.

    BEV_OPT_UNLOCK_CALLBACKS

    By default, when the bufferevent is set up to be threadsafe, the bufferevent’s locks are held whenever the any user-provided callback is invoked. Setting this option makes Libevent release the bufferevent’s lock when it’s invoking your callbacks.

    (Libevent 2.0.5-beta introduced BEV_OPT_UNLOCK_CALLBACKS. The other options above were new in Libevent 2.0.1-alpha.)

     

    socket-based bufferevents上建立连接

    If the bufferevent’s socket is not yet connected, you can launch a new connection.

    调用接口:

    int bufferevent_socket_connect(struct bufferevent *bev,

       struct sockaddr *address,int addrlen);

    The address and addrlen arguments are as for the standard call connect(). If the bufferevent does not already have a socket set, calling this function allocates a new stream socket for it, and makes it nonblocking.

    If the buffereventdoes have a socket already, calling bufferevent_socket_connect() tells Libevent that the socket is not connected, and no reads or writes should be done on the socket until the connect operation has succeeded.

    It is okay to add data to the output buffer before the connect is done.

    This function returns 0 if the connect was successfully launched, and -1 if an error occurred.

     

    通用的bufferevent操作

    (1)Freeing a bufferevent

    接口:

    void bufferevent_free(struct bufferevent *bev);

    如果bufferevente有未决的延时调用,则会在这些调用完成后才会删除。

     

    (2)操作回调函数,读写“水印标记”的设置,启动操作

    接口:

    typedefvoid (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);

    typedefvoid (*bufferevent_event_cb)(struct bufferevent *bev,

       short events,void *ctx);

     

    void bufferevent_setcb(struct bufferevent *bufev,

       bufferevent_data_cb readcb, bufferevent_data_cb writecb,

       bufferevent_event_cb eventcb, void *cbarg);

    The bufferevent_setcb() function changes one or more of the callbacks of a bufferevent. The readcb, writecb, and eventcb functions are called (respectively) when enough data is read, when enough data is written, or when an event occurs. The first argument of each is the bufferevent that has had the event happen. The last argument is the value provided by the user in the cbarg parameter of bufferevent_callcb(): You can use this to pass data to your callbacks. Theevents argument of the event callback is a bitmask of event flags: see "callbacks and watermarks" above.

    You can disable a callback by passing NULL instead of the callback function. Note the all callback functions on a bufferevent share a single cbarg value, so changing it will affect all of them.

    This function was introduced in Libevent 1.4.4. The type names "bufferevent_data_cb" and "bufferevent_event_cb" are new in Libevent 2.0.2-alpha.

     

    禁用/启用bufferevent

    void bufferevent_enable(struct bufferevent *bufev, short events);

    void bufferevent_disable(struct bufferevent *bufev, short events);

     

    short bufferevent_get_enabled(struct bufferevent *bufev);

    You can enable or disable the events EV_READ, EV_WRITE, or EV_READ|EV_WRITE on a bufferevent. When reading or writing is not enabled, the bufferevent will not try to read or write data.

    There is no need to disable writing when the output buffer is empty: the bufferevent automatically stops writing, and restarts again when there is data to write.

    Similarly, there is no need to disable reading when the input buffer is up to its high-water mark: the bufferevent automatically stops reading, and restarts again when there is space to read.

    By default, a newly created bufferevent has writing enabled, but not reading.

    You can call bufferevent_get_enabled() to see which events are currently enabled on the bufferevent.

    These functions were introduced in Libevent 0.8, except for bufferevent_get_enabled(), which was introduced in version 2.0.3-alpha.

     

    设置读/写“水印标记”

    void bufferevent_setwatermark(struct bufferevent *bufev, short events,

       size_t lowmark, size_t highmark);

    The bufferevent_setwatermark() function adjusts the read watermarks, the write watermarks, or both, of a single bufferevent. (If EV_READ is set in the events field, the read watermarks are adjusted. If EV_WRITE is set in the events field, the write watermarks are adjusted.)

    A high-water mark of 0 is equivalent to "unlimited".

    This function was first exposed in Libevent 1.4.4.

     

    还不一些接口就没一一列出来了,请参考上面给的网站。

     

     

    注意事项

    Never call event_assign() on an event that is already pending in an event base. Doing so can lead to extremely hard-to-diagnose errors. If the event is already initialized and pending, call event_del() on it before you call event_assign() on it again.

     

    Don’t set a timeout on a signal event. It might not be supported.

    Caveats when working with signals

    With current versions of Libevent, with most backends, only one event_base per process at a time can be listening for signals. If you add signal events to two event_bases at once ---even if the signals are different!--- only one event_base will receive signals.

    The kqueue backend does not have this limitation.

     

    拓展

     

    参考:
    libevent
    源码深度解剖

    www.libevent.org

     

    展开全文
  • libevent(三)event_add

    2020-07-21 16:04:15
    头文件event-internal.h中,有这样一段话: #ifdef _WIN32 /* If we're on win32, then file descriptors are not nice low densely packed integers. Instead, they are pointer-like windows handles, and we ...

    在Linux下,结构体event_io_map就被定义为event_signal_map。

    在头文件event-internal.h中,有这样一段话:

    #ifdef _WIN32
    /* If we're on win32, then file descriptors are not nice low densely packed
       integers.  Instead, they are pointer-like windows handles, and we want to
       use a hashtable instead of an array to map fds to events.
    */
    #define EVMAP_USE_HT
    #endif
    #ifdef EVMAP_USE_HT
    #define HT_NO_CACHE_HASH_VALUES
    #include "ht-internal.h"
    struct event_map_entry;
    HT_HEAD(event_io_map, event_map_entry);
    #else
    #define event_io_map event_signal_map
    #endif
        
    /* Used to map signal numbers to a list of events.  If EVMAP_USE_HT is not
       defined, this structure is also used as event_io_map, which maps fds to a
       list of events.
    */  
    

    在Linux下是没有定义EVMAP_USE_HT的所以结构体event_io_map就被定义为event_signal_map。
    而对应的操作宏,也会有相应的变化。而在Windows下,宏EVMAP_USE_HT是存在的,所以event_io_map被定义为:

    struct event_io_map
    {
        //哈希表
        struct event_map_entry **hth_table;
        //哈希表的长度
        unsigned hth_table_length;
        //哈希的元素个数
        unsigned hth_n_entries;
        //resize 之前可以存多少个元素
        //在event_io_map_HT_GROW函数中可以看到其值为hth_table_length的
        //一半。但hth_n_entries>=hth_load_limit时,就会发生增长哈希表的长度
        unsigned hth_load_limit;
        //后面素数表中的下标值。主要是指明用到了哪个素数
        int hth_prime_idx;
    };
    

    复杂结构体
    对应的宏操作也非常麻烦:具体参考:
    https://blog.csdn.net/luotuo44/article/details/38403241

    现在分析Linux下对应操作,选取函数evmap_io_add_中的一个关键宏GET_IO_SLOT_AND_CTOR为例:

    同样Linux下和Windows下此宏都存在,由于数据结构的不同,操作也不同:

    #ifndef EVMAP_USE_HT
    #define GET_IO_SLOT(x,map,slot,type) GET_SIGNAL_SLOT(x,map,slot,type)
    #define GET_IO_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len)   \
        GET_SIGNAL_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len)
    #define FDINFO_OFFSET sizeof(struct evmap_io)
    
    

    先看一下关键结构体:

    #define event_io_map event_signal_map
    
    struct event_io_map {
        /* An array of evmap_io * or of evmap_signal *; empty entries are
         * set to NULL. */
        void **entries;
        /* The number of entries available in entries */
        int nentries;
    };
    
    struct event_list
    {
        struct event *tqh_first;
        struct event **tqh_last;
    };
    
    struct evmap_io {
        struct event_list events;
        ev_uint16_t nread;
        ev_uint16_t nwrite;
        ev_uint16_t nclose;
    };
    
    struct event_map_entry {
        HT_ENTRY(event_map_entry) map_node;
        evutil_socket_t fd;
        union { /* This is a union in case we need to make more things that can
                   be in the hashtable. */
            struct evmap_io evmap_io;
        } ent;
    };
    
    #define HT_ENTRY(type)                          \
      struct {                                      \
        struct type *hte_next;                      \
      }
    

    函数event_add

    int
    event_add(struct event *ev, const struct timeval *tv)
    {
        int res;
    
    
        if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
            event_warnx("%s: event has no event_base set.", __func__);
            return -1;
        }
    
    
        EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
    
    
        res = event_add_nolock_(ev, tv, 0);
    
    
        EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
    
    
        return (res);
    }
    

    函数event_add_nolock_

    int
    event_add_nolock_(struct event *ev, const struct timeval *tv,
        int tv_is_absolute)
    {
        struct event_base *base = ev->ev_base;
        int res = 0;
        int notify = 0;
    
    
        EVENT_BASE_ASSERT_LOCKED(base);
        event_debug_assert_is_setup_(ev);
    
    
        event_debug((
             "event_add: event: %p (fd "EV_SOCK_FMT"), %s%s%s%scall %p",
             ev,
             EV_SOCK_ARG(ev->ev_fd),
             ev->ev_events & EV_READ ? "EV_READ " : " ",
             ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
             ev->ev_events & EV_CLOSED ? "EV_CLOSED " : " ",
             tv ? "EV_TIMEOUT " : " ",
             ev->ev_callback));
    
    
        EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL));
    
    
        if (ev->ev_flags & EVLIST_FINALIZING) {
            /* XXXX debug */
            return (-1);
        }
    
    
        /*
         * prepare for timeout insertion further below, if we get a
         * failure on any step, we should not change any state.
         */
        if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
            if (min_heap_reserve_(&base->timeheap,
                1 + min_heap_size_(&base->timeheap)) == -1)
                return (-1);  /* ENOMEM == errno */
        }//超时事件为其在小根堆中预留一个位置
    
    
        /* If the main thread is currently executing a signal event's
         * callback, and we are not the main thread, then we want to wait
         * until the callback is done before we mess with the event, or else
         * we can race on ev_ncalls and ev_pncalls below. */
    #ifndef EVENT__DISABLE_THREAD_SUPPORT
        if (base->current_event == event_to_event_callback(ev) &&
            (ev->ev_events & EV_SIGNAL)
            && !EVBASE_IN_THREAD(base)) {
            ++base->current_event_waiters;
            EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
        }
    #endif
    
    
        if ((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL)) &&
            !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))) {
            if (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))
                res = evmap_io_add_(base, ev->ev_fd, ev);
            else if (ev->ev_events & EV_SIGNAL)
                res = evmap_signal_add_(base, (int)ev->ev_fd, ev);
            if (res != -1)
                event_queue_insert_inserted(base, ev);//ev->ev_flags |= EVLIST_INSERTED;
            if (res == 1) {
                /* evmap says we need to notify the main thread. */
                notify = 1;
                res = 0;
            }
        }
       /*
         * we should change the timeout state only if the previous event
         * addition succeeded.
         */
        if (res != -1 && tv != NULL) {
            struct timeval now;
            int common_timeout;
    #ifdef USE_REINSERT_TIMEOUT
            int was_common;
            int old_timeout_idx;
    #endif
    
    
            /*
             * for persistent timeout events, we remember the
             * timeout value and re-add the event.
             *
             * If tv_is_absolute, this was already set.
             */
            if (ev->ev_closure == EV_CLOSURE_EVENT_PERSIST && !tv_is_absolute)
                ev->ev_io_timeout = *tv;
    
    
    #ifndef USE_REINSERT_TIMEOUT
            if (ev->ev_flags & EVLIST_TIMEOUT) {
                event_queue_remove_timeout(base, ev);
            }
    #endif
    
    
            /* Check if it is active due to a timeout.  Rescheduling
             * this timeout before the callback can be executed
             * removes it from the active list. */
            if ((ev->ev_flags & EVLIST_ACTIVE) &&
                (ev->ev_res & EV_TIMEOUT)) {
                if (ev->ev_events & EV_SIGNAL) {
                    /* See if we are just active executing
                     * this event in a loop
                     */
                    if (ev->ev_ncalls && ev->ev_pncalls) {
                        /* Abort loop */
                        *ev->ev_pncalls = 0;
                    }
                }
    
    
                event_queue_remove_active(base, event_to_event_callback(ev));
            }
    
    
            gettime(base, &now);
    
    
            common_timeout = is_common_timeout(tv, base);
    #ifdef USE_REINSERT_TIMEOUT
            was_common = is_common_timeout(&ev->ev_timeout, base);
            old_timeout_idx = COMMON_TIMEOUT_IDX(&ev->ev_timeout);
    #endif
    
    
            if (tv_is_absolute) {
                ev->ev_timeout = *tv;
            } else if (common_timeout) {
                struct timeval tmp = *tv;
                tmp.tv_usec &= MICROSECONDS_MASK;
                evutil_timeradd(&now, &tmp, &ev->ev_timeout);
                ev->ev_timeout.tv_usec |=
                    (tv->tv_usec & ~MICROSECONDS_MASK);
            } else {
                evutil_timeradd(&now, tv, &ev->ev_timeout);
            }
    
    
            event_debug((
                 "event_add: event %p, timeout in %d seconds %d useconds, call %p",
                 ev, (int)tv->tv_sec, (int)tv->tv_usec, ev->ev_callback));
    #ifdef USE_REINSERT_TIMEOUT
            event_queue_reinsert_timeout(base, ev, was_common, common_timeout,
    old_timeout_idx);
    #else
            event_queue_insert_timeout(base, ev);
    #endif
    
    
            if (common_timeout) {
                struct common_timeout_list *ctl =
                    get_common_timeout_list(base, &ev->ev_timeout);
                if (ev == TAILQ_FIRST(&ctl->events)) {
                    common_timeout_schedule(ctl, &now, ev);
                }
            } else {
                struct event* top = NULL;
                /* See if the earliest timeout is now earlier than it
                 * was before: if so, we will need to tell the main
                 * thread to wake up earlier than it would otherwise.
                 * We double check the timeout of the top element to
                 * handle time distortions due to system suspension.
                 */
                if (min_heap_elt_is_top_(ev))
                    notify = 1;
                else if ((top = min_heap_top_(&base->timeheap)) != NULL &&
                         evutil_timercmp(&top->ev_timeout, &now, <))
                    notify = 1;
           }
        }
    
    
        /* if we are not in the right thread, we need to wake up the loop */
        if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))
            evthread_notify_base(base);
    
    
        event_debug_note_add_(ev);
    
    
        return (res);
    }
    
    

    展示函数evmap_io_add_中的宏GET_IO_SLOT_AND_CTOR

    int evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
    {
        const struct eventop *evsel = base->evsel;
        struct event_io_map *io = &base->io;
        
    /*event_base初始化
    evmap_io_initmap_(&base->io);
    void evmap_io_initmap_(struct event_io_map* ctx)
    {
        evmap_signal_initmap_(ctx);
    }
    void evmap_signal_initmap_(struct event_signal_map *ctx)
    {
        ctx->nentries = 0;
        ctx->entries = NULL;
    }*/
        struct evmap_io *ctx = NULL;
        int nread, nwrite, nclose, retval = 0;
        short res = 0, old = 0;
        struct event *old_ev;
    
        EVUTIL_ASSERT(fd == ev->ev_fd);
    
        if (fd < 0)
            return 0;
    
    #ifndef EVMAP_USE_HT
            if (fd >= io->nentries) {//第一次调用时,io->nentries为0
                if (evmap_make_space(io, fd, sizeof(struct evmap_io *)) == -1)
                    return (-1);
            }
    #endif
    
      
    GET_IO_SLOT_AND_CTOR(ctx, io, fd, evmap_io, evmap_io_init,evsel->fdinfo_len);
    
    do {
         if ((io)->entries[fd] == ((void *)0))//内存有效且为NULL
         {
             (io)->entries[fd] = event_mm_calloc_((1), (sizeof(struct evmap_io)+evsel-       
    >fdinfo_len));//为内存指针分配一个evmap_io结构体,
             if (__builtin_expect(!!((io)->entries[fd] == ((void *)0)),0))
                 return (-1);
             (evmap_io_init)((struct evmap_io *)(io)->entries[fd]);//初始化
         }
         (ctx) = (struct evmap_io *)((io)->entries[fd]);//指针ctx指向为新fd分配的内存
    } while (0);
    
    函数evmap_io_init:
    static void
    evmap_io_init(struct evmap_io *entry)
    {
    do { 
           (&entry->events)->lh_first = ((void *)0); 
       } while ( 0);
    entry->nread = 0;
    entry->nwrite = 0;
    entry->nclose = 0;
    }  
        nread = ctx->nread;
        nwrite = ctx->nwrite;
        nclose = ctx->nclose;
    
    
        if (nread)
            old |= EV_READ;
        if (nwrite)
            old |= EV_WRITE;
        if (nclose)
            old |= EV_CLOSED;//第一次此代码是不会被执行的
    
    
        if (ev->ev_events & EV_READ) {
            if (++nread == 1)
                res |= EV_READ;
        }
        if (ev->ev_events & EV_WRITE) {
            if (++nwrite == 1)
                res |= EV_WRITE;
        }
        if (ev->ev_events & EV_CLOSED) {
            if (++nclose == 1)
                res |= EV_CLOSED;
        }//返回值res会在后面用到,如果我们加入的event的ev->events为EV_READ,则res会为非0,如果我们再次将event的ev->events的标志EV_READ再次加入到event_base,则会为0。即一个fd虽然可以添加多次,但是同一个标志只允许添加一次,这里说的有问题,一个fd的一个标志可以有多个event
        if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff || nclose > 0xffff)) {
            event_warnx("Too many events reading or writing on fd %d",
                (int)fd);
            return -1;
        }
        if (EVENT_DEBUG_MODE_IS_ON() &&
            (old_ev = LIST_FIRST(&ctx->events)) &&
            (old_ev->ev_events&EV_ET) != (ev->ev_events&EV_ET)) {
            event_warnx("Tried to mix edge-triggered and non-edge-triggered"
                " events on fd %d", (int)fd);
            return -1;
        }
       if (res) {
            void *extra = ((char*)ctx) + sizeof(struct evmap_io);
            /* XXX(niels): we cannot mix edge-triggered and
             * level-triggered, we should probably assert on
             * this. */
            if (evsel->add(base, ev->ev_fd,
                old, (ev->ev_events & EV_ET) | res, extra) == -1)//对应后端的add函数
                return (-1);
            retval = 1;
        }
    
    
        ctx->nread = (ev_uint16_t) nread;
        ctx->nwrite = (ev_uint16_t) nwrite;
        ctx->nclose = (ev_uint16_t) nclose;//更新fd内存
        LIST_INSERT_HEAD(&ctx->events, ev, ev_io_next);//将此fd加入到此event的链表
    
    
        return (retval);
    }
    
    
    
    static int
    evmap_make_space(struct event_signal_map *map, int slot, int msize)
    {                        
        if (map->nentries <= slot) {
            int nentries = map->nentries ? map->nentries : 32;
            void **tmp;
        
            if (slot > INT_MAX / 2)
                return (-1);
            
            while (nentries <= slot)
                nentries <<= 1;
        
            if (nentries > INT_MAX / msize)
                return (-1);
    
    
            tmp = (void **)mm_realloc(map->entries, nentries * msize);//回调用realloc函数在原内存基础上"添加"一段内存
            if (tmp == NULL)
                return (-1);
    
    
            memset(&tmp[map->nentries], 0,
                (nentries - map->nentries) * msize);//清零新分配那段内存
    
    
            map->nentries = nentries;
            map->entries = tmp;//新分配的地址可能变化,更新指针
        }
    
    
        return (0);
    }
    

    接下来看看select的add函数的实现

    static int
    select_add(struct event_base *base, int fd, short old, short events, void *p)
    {
        struct selectop *sop = base->evbase;
        (void) p;
    
    
        EVUTIL_ASSERT((events & EV_SIGNAL) == 0);
        check_selectop(sop);
        /*
         * Keep track of the highest fd, so that we can calculate the size
         * of the fd_sets for select(2)
         */
        if (sop->event_fds < fd) {
            int fdsz = sop->event_fdsz;//更新select最大文件描述符,扩展内存
    
    
            if (fdsz < (int)sizeof(fd_mask))
                fdsz = (int)sizeof(fd_mask);
    
    
            /* In theory we should worry about overflow here.  In
             * reality, though, the highest fd on a unixy system will
             * not overflow here. XXXX */
            while (fdsz < (int) SELECT_ALLOC_SIZE(fd + 1))
                fdsz *= 2;
    
    
            if (fdsz != sop->event_fdsz) {
                if (select_resize(sop, fdsz)) {
                    check_selectop(sop);
                    return (-1);
                }
            }
    
    
            sop->event_fds = fd;
        }
        if (events & EV_READ)
            FD_SET(fd, sop->event_readset_in);
        if (events & EV_WRITE)
            FD_SET(fd, sop->event_writeset_in);//加入文件描述符到对应位数组
        check_selectop(sop);
    
    
        return (0);
    }
    
    展开全文
  • libevent学习笔记

    2020-06-14 00:09:46
    libevent学习笔记 学习资料:链接:百度网盘 提取码:jqsp 包括libevent源码剖析,参考手册 另外推荐一个网站:学习网站 libevent工作结构 libevent是高性能i/o网路库,基于reactor事件驱动模型。 下面这张图直观地...
  • 使用libevent编写的程序,配有博客教程,工程中的inc、lib为已编译的libevent,大家可以直接下载回去使用,免得再在官网下载
  • Mac 编译安装libevent

    千次阅读 2015-04-02 01:21:36
    Mac 编译安装libevent 库 打开下面的网页,复制shell 脚本: https://github.com/mtigas/iOS-OnionBrowser/blob/master/build-libevent.sh 我把build-libevent.sh中下面的验证代码注释掉。 #if out=$(gpg --...
  • 翻译自:http://www.wangafu.net/~nickm/libevent-book/Ref0_meta.html ... 1 从一万英尺外看Libevent ...Libevent是用于编写高速可移植非阻塞IO应用的库,其设计目标是: v 可移植性:使用lib
  • 头文件中定义了许多有用的函数和类型来帮助实现可移植的程序。Libevent在内部使用这些类型和函数。   一:基本类型 evutil_socket_t  除了Windows之外的大多数系统,socket就是一个整数,而且操作系统按照数值...
  • libevent学习笔记1:牛刀小试

    千次阅读 2011-07-28 14:26:20
    Libevent是一个轻量级的开源的高性能的网络库,被众多的开源项目使用,例如大名鼎鼎的memcached等。具有如下的显著的特点:事件驱动,轻量级(和ACE相比的话),跨平台,支持多路的IO复用技术,支持定时器、信号等
  • /** @file event2/http.h  * * Basic support for HTTP serving.  * * As Libevent is a library for dealing with event notification and most * interesting applications are networked today, I have often ...
  • libevent最新静态库

    2018-09-25 15:11:55
    该资源为已经编译好的libevent静态库以及头文件,编译环境为win10 VS2017,对于该库的使用,创建http https server可参考本账号博客文章。
  • qt_eventdispatcher_libevent 是基于 Libevent 的 Qt 事件调度器 特点 非常快速 支持Qt4和Qt5 不需要Qt的私有头文件 通过Qt4 和 Qt5 的事件调度,事件循环,...
  • 源码默认使用的是MingW版本的libevent头文件和库,也包含Windows版本的libevent头文件和库,后缀为_win。 libevent的编译和使用可以参考: libevent学习之二:Windows7(Win7)下编译libevent 如何调试libevent可参考...
  • libevent

    2021-03-23 22:36:34
    libevent
  • linux_libevent_SDK.zip

    2020-08-20 10:29:44
    libevent-2.1.12-stable Linux下编译的动态库,包含头文件。可在自己的c/C++代码中使用。因为是在ubuntu.20下编译的,GCC、G++版本是9.0,如果在使用过程中出现编译符号问题,请考虑更新自己的gcc/g++版本
  • 初入libevent的人,很可能是第一次接触异步编程。Libevent的编程思想,建议还是多看前人的程序,或者是看libevent本身的文档学习。或者是介绍另外一个库,那就是libuv,它是libev某种意义上的的替代品(而libev又...
  • libevent简介和使用

    千次阅读 2016-05-31 14:21:39
    libevent是一个基于事件触发的网络库,memcached底层也是使用libevent库,今天学习下。 总体来说,libevent有下面一些特点和优势: * 统一数据源, 统一I/O事件,信号和定时器这三种事件; * 可移植,跨平台支持...
  • windows下编译libevent(2.1.8)及使用

    千次阅读 2018-11-14 14:54:53
    一:获取libevent github地址:https://github.com/libevent/libevent/releases 下载2.1.8稳定版 二:编译libevent 我是用的visual studio 2010,当然也可以使用更高的版本 启动后,进入"Libevent-...
  • Linux高性能I/O框架库Libevent介绍 这篇文章主要讲一下Libevent库的内容,顺便对I/O库整体做个介绍。 Linux服务器程序必须处理的三类事件: I/O事件 信号 定时事件 在处理这三类事件时我们通常需要考虑如下三个...
  • LibEvent中文帮助文档--第1、2、3、4章

    万次阅读 2016-12-02 10:20:34
    LibEvent中文帮助文档:http://blog.csdn.net/zhouyongku LibEvent快速可移植非阻塞式网络编程
  • Libevent 源码文件结构分析

    千次阅读 2018-04-15 07:49:57
    下载 Libevent 源码,切换到 2.1.8 稳定版本,步骤如下: git clone https://github.com/libevent/libevent.git cd libevent git checkout release-2.1.8-stable 在分析源码先要先对源码进行配置,因为 libevent...
  • 目录libevent接口分析事件Event处理 libevent是一款事件驱动的网络开发包,由于采用c语言开发体积小巧,跨平台,速度极快。大量开源项目使用了libevent比如谷歌浏览器和分布式的高速缓存系统Memcached。ibevent支持...
  • Libevent is a library for writing fast portable nonblocking IO.  libevent是一个为编写快速可移植的非阻塞IO程序而设计的。 libevent组件  libevent包括了以下组件:  1.evutil  Generic functionality...
  • libevent 结合 pthread-win32 在windows 平台上的使用 libevent 在windows 平台上的使用,大致过程是: 1)WSAStartup 2)evthread_use_windows_threads 3)event_base_new 4)WSACleanup 其中,1)WSAStartup...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,221
精华内容 1,288
关键字:

libevent头文件