libevent reference Mannual II--library

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

The Libevent Reference Manual: Preliminaries

Libevent is a library for writing fast portable nonblocking IO. Its design goals are:

  • portability
  • speed
  • scalability
  • convenience

The components of Libevent:

  • evutil: Generic functionality to abstract out the differences between different platforms' networking implementations.
  • event and event_base: heart of libevent. diversity abstrct API, event-based nonblocking IO backends. It can let you know when sockets are ready to read or write, do basic timeout functionality, and detect OS signals.
  • bufferevent: These functions provide a more convenient wrapper around Libevent’s event-based core. They let your application request buffered reads and writes, and rather than informing you when sockets are ready to do, they let you know when IO has actually occurred.
  • evbuffer: This module implements the buffers underlying bufferevents, and provides functions for efficient and/or convenient access.
  • evhttp: A simple HTTP client/server implementation.
  • evdns: A simple DNS client/server implementation
  • evrpc: A simple RPC implementation

Log messages in Libevent

Log internal errors and warnings, debugging messages (if support).

Default, these messages are written to stderr. could be overrided.

Interface
 1 #define EVENT_LOG_DEBUG 0
 2 #define EVENT_LOG_MSG   1
 3 #define EVENT_LOG_WARN  2
 4 #define EVENT_LOG_ERR   3
 5 
 6 /* Deprecated; see note at the end of this section */
 7 #define _EVENT_LOG_DEBUG EVENT_LOG_DEBUG
 8 #define _EVENT_LOG_MSG   EVENT_LOG_MSG
 9 #define _EVENT_LOG_WARN  EVENT_LOG_WARN
10 #define _EVENT_LOG_ERR   EVENT_LOG_ERR
11 
12 typedef void (*event_log_cb)(int severity, const char *msg);
13 
14 void event_set_log_callback(event_log_cb cb);

severity is one of EVENT_LOG_DEBUG, EVENT_LOG_MSG, EVENT_LOG_WARN, EVENT_LOG_ERR.

To override Libevent’s logging behavior, write your own function matching the signature of event_log_cb, and pass it as an argument to event_set_log_callback(). Whenever Libevent wants to log a message, it will pass it to the function you provided. You can have Libevent return to its default behavior by calling event_set_log_callback() again with NULL as an argument.

Handling fatal errors

Default behavior is to call exit() or abort() to leave current running process.

Interface

1 typedef void (*event_fatal_cb)(int err);
2 void event_set_fatal_callback(event_fatal_cb cb);

To set the event_set_fatal_callback(), later, if Libevent encounters a fatal error, the function you provided will be called.

PS: 1. should not return control to Libevent (cause undefined behavior); 2. the Libevent might exit anyway to avoid crashing; 3. any other Libevent function cannot be called.

Memory management

Default: Libevent uses the C library's memory management functions to allocate memory from the heap.

Libevent use another memory manager by providing your own replacements for malloc, realloc, and free.

Or if you have an instrumented allocator that you want Libevent to use in order to look for memory leaks.

Interface

1 void event_set_mem_functions(void *(*malloc_fn)(size_t sz),
2                              void *(*realloc_fn)(void *ptr, size_t sz),
3                              void (*free_fn)(void *ptr));

Simple example

 1 #include <event2/event.h>
 2 #include <sys/types.h>
 3 #include <stdlib.h>
 4 
 5 /* This union's purpose is to be as big as the largest of all the
 6  * types it contains. */
 7 union alignment {
 8     size_t sz;
 9     void *ptr;
10     double dbl;
11 };
12 /* We need to make sure that everything we return is on the right
13    alignment to hold anything, including a double. */
14 #define ALIGNMENT sizeof(union alignment)
15 
16 /* We need to do this cast-to-char* trick on our pointers to adjust
17    them; doing arithmetic on a void* is not standard. */
18 #define OUTPTR(ptr) (((char*)ptr)+ALIGNMENT)
19 #define INPTR(ptr) (((char*)ptr)-ALIGNMENT)
20 
21 static size_t total_allocated = 0;
22 static void *replacement_malloc(size_t sz)
23 {
24     void *chunk = malloc(sz + ALIGNMENT);
25     if (!chunk) return chunk;
26     total_allocated += sz;
27     *(size_t*)chunk = sz;
28     return OUTPTR(chunk);
29 }
30 static void *replacement_realloc(void *ptr, size_t sz)
31 {
32     size_t old_size = 0;
33     if (ptr) {
34         ptr = INPTR(ptr);
35         old_size = *(size_t*)ptr;
36     }
37     ptr = realloc(ptr, sz + ALIGNMENT);
38     if (!ptr)
39         return NULL;
40     *(size_t*)ptr = sz;
41     total_allocated = total_allocated - old_size + sz;
42     return OUTPTR(ptr);
43 }
44 static void replacement_free(void *ptr)
45 {
46     ptr = INPTR(ptr);
47     total_allocated -= *(size_t*)ptr;
48     free(ptr);
49 }
50 void start_counting_bytes(void)
51 {
52     event_set_mem_functions(replacement_malloc,
53                             replacement_realloc,
54                             replacement_free);
55 }

Locks and threading

Libevent structures can generally work three ways with multithreading.

  • Some structures are inherently single-threaded: it is never safe to use them from more than one thread at the same time.

  • Some structures are optionally locked: you can tell Libevent for each object whether you need to use it from multiple threads at once.

  • Some structures are always locked: if Libevent is running with lock support, then they are always safe to use from multiple threads at once.

Interface

1 #ifdef WIN32
2 int evthread_use_windows_threads(void);
3 #define EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
4 #endif
5 #ifdef _EVENT_HAVE_PTHREADS
6 int evthread_use_pthreads(void);
7 #define EVTHREAD_USE_PTHREADS_IMPLEMENTED
8 #endif

Both functions return 0 on success, and -1 on failure.

If you need to use a different threading library, then you have a little more work ahead of you. You need to define functions that use your library to implement:

  • Locks

  • locking

  • unlocking

  • lock allocation

  • lock destruction

  • Conditions

  • condition variable creation

  • condition variable destruction

  • waiting on a condition variable

  • signaling/broadcasting to a condition variable

  • Threads

  • thread ID detection

Then you tell Libevent about these functions, using the evthread_set_lock_callbacks and evthread_set_id_callback interfaces.

Interface

 1 #define EVTHREAD_WRITE  0x04
 2 #define EVTHREAD_READ   0x08
 3 #define EVTHREAD_TRY    0x10
 4 
 5 #define EVTHREAD_LOCKTYPE_RECURSIVE 1
 6 #define EVTHREAD_LOCKTYPE_READWRITE 2
 7 
 8 #define EVTHREAD_LOCK_API_VERSION 1
 9 
10 struct evthread_lock_callbacks {
11        int lock_api_version;
12        unsigned supported_locktypes;
13        void *(*alloc)(unsigned locktype);
14        void (*free)(void *lock, unsigned locktype);
15        int (*lock)(unsigned mode, void *lock);
16        int (*unlock)(unsigned mode, void *lock);
17 };
18 
19 int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *);
20 
21 void evthread_set_id_callback(unsigned long (*id_fn)(void));
22 
23 struct evthread_condition_callbacks {
24         int condition_api_version;
25         void *(*alloc_condition)(unsigned condtype);
26         void (*free_condition)(void *cond);
27         int (*signal_condition)(void *cond, int broadcast);
28         int (*wait_condition)(void *cond, void *lock,
29             const struct timeval *timeout);
30 };
31 
32 int evthread_set_condition_callbacks(
33         const struct evthread_condition_callbacks *);

For the version, struct evthread_lock_callbacks, described above,

lock_api_version is set as EVTHREAD_LOCK_API_VERSION,

supported_locktypes is set as EVTHREAD_LOCKTYPE_*,

alloc function must return a new lock of the specified type,

free function must release all resources held by a lock of the specified type,

lock function must try to acquire the lock in the specified mode, returning 0 on success and nonzero on failure,

unlock function must try to unlock the lock, returning 0 on success and nonzero on failure.

supported_locktypes modes are:

0

A regular, not-necessarily recursive lock.

EVTHREAD_READ

For READWRITE locks only: acquire or release the lock for reading.

EVTHREAD_WRITE

For READWRITE locks only: acquire or release the lock for writing.

EVTHREAD_TRY

For locking only: acquire the lock only if the lock can be acquired immediately.

id_fn must be a function returning an unsigned long identifying what thread is calling the function. It must always return the same number for the same thread, and must not ever return the same number for two different threads if they are both executing at the same time.

The evthread_condition_callbacks structure describes callbacks related to condition variables.

lock_api_version field must be set to EVTHREAD_CONDITION_API_VERSION.

alloc_condition function must return a pointer to a new condition variable. It receives 0 as its argument.

free_condition function must release storage and resources held by a condition variable.

wait_condition function takes three arguments: a condition allocated by alloc_condition, a lock allocated by the evthread_lock_callbacks.alloc function you provided, and an optional timeout.

The lock will be held whenever the function is called; the function must release the lock, and wait until the condition becomes signalled or until the (optional) timeout has elapsed. The wait_condition function should return -1 on an error, 0 if the condition is signalled, and 1 on a timeout.

Before it returns, it should make sure it holds the lock again. Finally, the signal_condition function should cause one thread waiting on the condition to wake up (if its broadcast argument is false) and all threads currently waiting on the condition to wake up (if its broadcast argument is true). It will only be held while holding the lock associated with the condition.

Freeing global Libevent structures

Even when you’ve freed all the objects that you allocated with Libevent, there will be a few globally allocated structures left over. This isn’t usually a problem: once the process exits, they will all get cleaned up anyway.

1 void libevent_global_shutdown(void);

Calling libevent_global_shutdown() will make other Libevent functions behave unpredictably; don’t call it except as the last Libevent function your program invokes.

Creating an event_base

If an event_base is set up to use locking, it is safe to access it between multiple threads. Its loop can only be run in a single thread, however. If you want to have multiple threads polling for IO, you need to have an event_base for each thread.

Each event_base has a "method", or a backend that it uses to determine which events are ready. The recognized methods are:

  • select

  • poll

  • epoll

  • kqueue

  • devpoll

  • evport

  • win32

Setting up a default event_base

Interface

struct event_base *event_base_new(void);

Rerturn a pointer to a new event_base with the default settings when success, NULL the other way.

When choosing among methods, it picks the fastest method that the OS supports.

Setting up a complicated event_base

If you want more control over what kind of event_base you get, you need to use an event_config. An event_config is an opaque structure that holds information about your preferences for an event_base. When you want an event_base, you pass the event_config to event_base_new_with_config().

Interface
1 struct event_config *event_config_new(void);
2 struct event_base *event_base_new_with_config(const struct event_config *cfg);
3 void event_config_free(struct event_config *cfg);

To allocate an event_base with these functions, you call event_config_new() to allocate a new event_config. Then, you call other functions on the event_config to tell it about your needs. Finally, you call event_base_new_with_config() to get a new event_base. When you are done, you can free the event_config with event_config_free().

Interface
 1 int event_config_avoid_method(struct event_config *cfg, const char *method);
 2 
 3 enum event_method_feature {
 4     EV_FEATURE_ET = 0x01,
 5     EV_FEATURE_O1 = 0x02,
 6     EV_FEATURE_FDS = 0x04,
 7 };
 8 int event_config_require_features(struct event_config *cfg,
 9                                   enum event_method_feature feature);
10 
11 enum event_base_config_flag {
12     EVENT_BASE_FLAG_NOLOCK = 0x01,
13     EVENT_BASE_FLAG_IGNORE_ENV = 0x02,
14     EVENT_BASE_FLAG_STARTUP_IOCP = 0x04,
15     EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,
16     EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,
17     EVENT_BASE_FLAG_PRECISE_TIMER = 0x20
18 };
19 int event_config_set_flag(struct event_config *cfg,
20     enum event_base_config_flag flag);

Calling event_config_avoid_method tells Libevent to avoid a specific available backend by name.

Calling event_config_require_feature() tells Libevent not to use any backend that cannot supply all of a set of features.

Calling event_config_set_flag() tells Libevent to set one or more of the run-time flags below when constructing the event base.

The recognized feature values for event_config_require_features are:

EV_FEATURE_ET

Requires a backend method that supports edge-triggered IO.

EV_FEATURE_O1

Requires a backend method where adding or deleting a single event, or having a single event become active, is an O(1) operation.

EV_FEATURE_FDS

Requires a backend method that can support arbitrary file descriptor types, and not just sockets.

The recognized option values for event_config_set_flag() are:

EVENT_BASE_FLAG_NOLOCK

Do not allocate locks for the event_base. Setting this option may save a little time for locking and releasing the event_base, but will make it unsafe and nonfunctional to access it from multiple threads.

EVENT_BASE_FLAG_IGNORE_ENV

Do not check the EVENT_* environment variables when picking which backend method to use. Think hard before using this flag: it can make it harder for users to debug the interactions between your program and Libevent.

EVENT_BASE_FLAG_STARTUP_IOCP

On Windows only, this flag makes Libevent enable any necessary IOCP dispatch logic on startup, rather than on-demand.

EVENT_BASE_FLAG_NO_CACHE_TIME

Instead of checking the current time every time the event loop is ready to run timeout callbacks, check it after every timeout callback. This can use more CPU than you necessarily intended, so watch out!

EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST

Tells Libevent that, if it decides to use the epoll backend, it is safe to use the faster "changelist"-based backend. The epoll-changelist backend can avoid needless system calls in cases where the same fd has its status modified more than once between calls to the backend’s dispatch function, but it also trigger a kernel bug that causes erroneous results if you give Libevent any fds cloned by dup() or its variants. This flag has no effect if you use a backend other than epoll. You can also turn on the epoll-changelist option by setting the EVENT_EPOLL_USE_CHANGELIST environment variable.

EVENT_BASE_FLAG_PRECISE_TIMER

By default, Libevent tries to use the fastest available timing mechanism that the operating system provides. If there is a slower timing mechanism that provides more fine-grained timing precision, this flag tells Libevent to use that timing mechanism instead. If the operating system provides no such slower-but-more-precise mechanism, this flag has no effect.

The above functions that manipulate an event_config all return 0 on success, -1 on failure.

Interface

1 int event_config_set_max_dispatch_interval(struct event_config *cfg,
2     const struct timeval *max_interval, int max_callbacks,
3     int min_priority);

This function prevents priority inversion by limiting how many low-priority event callbacks can be invoked before checking for more high-priority events. If max_interval is non-null, the event loop checks the time after each callback, and re-scans for high-priority events if max_interval has passed. If max_callbacks is nonnegative, the event loop also checks for more events after max_callbacks callbacks have been invoked. These rules apply to any event of min_priority or higher.

Example: Preferring edge-triggered backends

 1 struct event_config *cfg;
 2 struct event_base *base;
 3 int i;
 4 
 5 /* My program wants to use edge-triggered events if at all possible.  So
 6    I'll try to get a base twice: Once insisting on edge-triggered IO, and
 7    once not. */
 8 for (i=0; i<2; ++i) {
 9     cfg = event_config_new();
10 
11     /* I don't like select. */
12     event_config_avoid_method(cfg, "select");
13 
14     if (i == 0)
15         event_config_require_features(cfg, EV_FEATURE_ET);
16 
17     base = event_base_new_with_config(cfg);
18     event_config_free(cfg);
19     if (base)
20         break;
21 
22     /* If we get here, event_base_new_with_config() returned NULL.  If
23        this is the first time around the loop, we'll try again without
24        setting EV_FEATURE_ET.  If this is the second time around the
25        loop, we'll give up. */
26 }

Example: Avoiding priority-inversion

 1 struct event_config *cfg;
 2 struct event_base *base;
 3 
 4 cfg = event_config_new();
 5 if (!cfg)
 6    /* Handle error */;
 7 
 8 /* I'm going to have events running at two priorities.  I expect that
 9    some of my priority-1 events are going to have pretty slow callbacks,
10    so I don't want more than 100 msec to elapse (or 5 callbacks) before
11    checking for priority-0 events. */
12 struct timeval msec_100 = { 0, 100*1000 };
13 event_config_set_max_dispatch_interval(cfg, &msec_100, 5, 1);
14 
15 base = event_base_new_with_config(cfg);
16 if (!base)
17    /* Handle error */;
18 
19 event_base_priority_init(base, 2);

Examining an event_base’s backend method

Sometimes you want to see which features are actually available in an event_base, or which method it’s using.

Interface

1 const char **event_get_supported_methods(void);

The event_get_supported_methods() function returns a pointer to an array of the names of the methods supported in this version of Libevent. The last element in the array is NULL.

1 const char *event_base_get_method(const struct event_base *base);
2 enum event_method_feature event_base_get_features(const struct event_base *base);

The event_base_get_method() call returns the name of the actual method in use by an event_base. The event_base_get_features() call returns a bitmask of the features that it supports.

Example

 1 struct event_base *base;
 2 enum event_method_feature f;
 3 
 4 base = event_base_new();
 5 if (!base) {
 6     puts("Couldn't get an event_base!");
 7 } else {
 8     printf("Using Libevent with backend method %s.",
 9         event_base_get_method(base));
10     f = event_base_get_features(base);
11     if ((f & EV_FEATURE_ET))
12         printf("  Edge-triggered events are supported.");
13     if ((f & EV_FEATURE_O1))
14         printf("  O(1) event notification is supported.");
15     if ((f & EV_FEATURE_FDS))
16         printf("  All FD types are supported.");
17     puts("");
18 }

Deallocating an event_base

1 void event_base_free(struct event_base *base);

Note that this function does not deallocate any of the events that are currently associated with the event_base, or close any of their sockets, or free any of their pointers.

Setting priorities on an event_base

1 int event_base_priority_init(struct event_base *base, int n_priorities);

This function returns 0 on success and -1 on failure. There is a constant, EVENT_MAX_PRIORITIES, that sets the upper bound on the value of n_priorities. It is an error to call this function with a higher value for n_priorities.

1 int event_base_get_npriorities(struct event_base *base);

The return value is equal to the number of priorities configured in the base. So if event_base_get_npriorities() returns 3, then allowable priority values are 0, 1, and 2.

Reinitializing an event_base after fork()

Not all event backends persist cleanly after a call to fork(). Thus, if your program uses fork() or a related system call in order to start a new process, and you want to continue using an event_base after you have forked, you may need to reinitialize it.

Interface

1 int event_reinit(struct event_base *base);

Obsolete event_base functions

Older versions of Libevent relied pretty heavily on the idea of a "current" event_base. The "current" event_base was a global setting shared across all threads. If you forgot to specify which event_base you wanted, you got the current one. Since event_bases weren’t threadsafe, this could get pretty error-prone.

nstead of event_base_new(), there was:

Interface
struct event_base *event_init(void);

This function worked like event_base_new(), and set the current base to the allocated base. There was no other way to change the current base.

Some of the event_base functions in this section had variants that operated on the current base. These functions behaved as the current functions, except that they took no base argument.

Current function

Obsolete current-base version

event_base_priority_init()

event_priority_init()

event_base_get_method()

event_get_method()

 

 

 

 

 ------------------------------------------------<the end.>----------------------------------------------------------------------------

 

Working with an event loop

Running the loop

Once you have an event_base with some events registered (see the next section about how to create and register events), you will want Libevent to wait for events and alert you about them.

Interface
1 #define EVLOOP_ONCE             0x01
2 #define EVLOOP_NONBLOCK         0x02
3 #define EVLOOP_NO_EXIT_ON_EMPTY 0x04
int event_base_loop(struct event_base *base, int flags);

Default: the event_base_loop() function runs an event_base until there are no more events registered in it. Once the registered events triggered, it marks them as "active", and starts to run them.

The behavior of event_base_loop() can be changed by setting one or more flags in its flags argument.

EVLOOP_ONCE is set, then the loop will wait until some events become active, then run active events until there are no more to run, then return.

EVLOOP_NONBLOCK is set, then the loop will not wait for events to trigger: it will only check whether any events are ready to trigger immediately, and run their callbacks if so.

EVLOOP_NO_EXIT_ON_EMPTY is set, the loop will not exit when no pending or active events, the loop will keep running until somebody calls event_base_loopbreak(), or calls event_base_loopexit(), or an error occurs.

Pseudocode:

 1 while (any events are registered with the loop,
 2         or EVLOOP_NO_EXIT_ON_EMPTY was set) {
 3 
 4     if (EVLOOP_NONBLOCK was set, or any events are already active)
 5         If any registered events have triggered, mark them active.
 6     else
 7         Wait until at least one event has triggered, and mark it active.
 8 
 9     for (p = 0; p < n_priorities; ++p) {
10        if (any event with priority of p is active) {
11           Run all active events with priority of p.
12           break; /* Do not run any events of a less important priority */
13        }
14     }
15 
16     if (EVLOOP_ONCE was set or EVLOOP_NONBLOCK was set)
17        break;
18 }

As a convenience, you can also call:

Interface
int event_base_dispatch(struct event_base *base);
The event_base_dispatch() call is the same as event_base_loop(), with no flags set. Thus, it keeps running until there are no more registered events or until event_base_loopbreak() or event_base_loopexit() is called.

Stopping the loop

Interface

1 int event_base_loopexit(struct event_base *base, const struct timeval *tv);
2 int event_base_loopbreak(struct event_base *base);

The event_base_loopexit() function tells an event_base to stop looping after a given time has elapsed. If the tv argument is NULL, the event_base stops looping without a delay. If the event_base is currently running callbacks for any active events, it will continue running them, and not exit until they have all been run.

The event_base_loopbreak() function tells the event_base to exit its loop immediately. It differs from event_base_loopexit(base, NULL) in that if the event_base is currently running callbacks for any active events, it will exit immediately after finishing the one it’s currently processing.

Note also that event_base_loopexit(base,NULL) and event_base_loopbreak(base) act differently when no event loop is running: loopexit schedules the next instance of the event loop to stop right after the next round of callbacks are run (as if it had been invoked with EVLOOP_ONCE) whereas loopbreak only stops a currently running loop, and has no effect if the event loop isn’t running.

Example: Shut down immediately

 1 #include <event2/event.h>
 2 
 3 /* Here's a callback function that calls loopbreak */
 4 void cb(int sock, short what, void *arg)
 5 {
 6     struct event_base *base = arg;
 7     event_base_loopbreak(base);
 8 }
 9 
10 void main_loop(struct event_base *base, evutil_socket_t watchdog_fd)
11 {
12     struct event *watchdog_event;
13 
14     /* Construct a new event to trigger whenever there are any bytes to
15        read from a watchdog socket.  When that happens, we'll call the
16        cb function, which will make the loop exit immediately without
17        running any other active events at all.
18      */
19     watchdog_event = event_new(base, watchdog_fd, EV_READ, cb, base);
20 
21     event_add(watchdog_event, NULL);
22 
23     event_base_dispatch(base);
24 }

Example: Run an event loop for 10 seconds, then exit.

 1 #include <event2/event.h>
 2 
 3 void run_base_with_ticks(struct event_base *base)
 4 {
 5   struct timeval ten_sec;
 6 
 7   ten_sec.tv_sec = 10;
 8   ten_sec.tv_usec = 0;
 9 
10   /* Now we run the event_base for a series of 10-second intervals, printing
11      "Tick" after each.  For a much better way to implement a 10-second
12      timer, see the section below about persistent timer events. */
13   while (1) {
14      /* This schedules an exit ten seconds from now. */
15      event_base_loopexit(base, &ten_sec);
16 
17      event_base_dispatch(base);
18      puts("Tick");
19   }
20 }

Sometimes you may want to tell whether your call to event_base_dispatch() or event_base_loop() exited normally, or because of a call to event_base_loopexit() or event_base_break(). You can use these functions to tell whether loopexit or break was called:

Interface

1 int event_base_got_exit(struct event_base *base);
2 int event_base_got_break(struct event_base *base);

Re-checking for events

Ordinarily, Libevent checks for events, then runs all the active events with the highest priority, then checks for events again, and so on. But sometimes you might want to stop Libevent right after the current callback has been run, and tell it to scan again. By analogy to event_base_loopbreak(), you can do this with the function event_base_loopcontinue().

Interface

1 int event_base_loopcontinue(struct event_base *);

Calling event_base_loopcontinue() has no effect if we aren’t currently running event callbacks.

Checking the internal time cache

Sometimes you want to get an approximate view of the current time inside an event callback, and you want to get it without calling gettimeofday() yourself as a syscall.

Interface

1 int event_base_gettimeofday_cached(struct event_base *base, struct timeval *tv_out);

The event_base_gettimeofday_cached() function sets the value of its tv_out argument to the cached time if the event_base is currently executing callbacks. Otherwise, it calls evutil_gettimeofday() for the actual current time. It returns 0 on success, and negative on failure.

Note that since the timeval is cached when Libevent starts running callbacks, it will be at least a little inaccurate. If your callbacks take a long time to run, it may be very inaccurate. To force an immediate cache update, you can call this function:

Interface

1 int event_base_update_cache_time(struct event_base *base);

Dumping the event_base status

Interface

1 void event_base_dump_events(struct event_base *base, FILE *f);

For help debugging your program (or debugging Libevent!) you might sometimes want a complete list of all events added in the event_base and their status. Calling event_base_dump_events() writes this list to the stdio file provided.

Running a function over every event in an event_base

Interface
typedef int (*event_base_foreach_event_cb)(const struct event_base *, const struct event *, void *);

int event_base_foreach_event(struct event_base *base, event_base_foreach_event_cb fn, void *arg);

You can use event_base_foreach_event() to iterate over every currently active or pending event associated with an event_base(). The provided callback will be invoked exactly once per event, in an unspecified order. The third argument of event_base_foreach_event() will be passed as the third argument to each invocation of the callback.

The callback function must return 0 to continue iteration, or some other integer to stop iterating. Whatever value the callback function finally returns will then be returned by event_base_foreach_function().

Your callback function must not modify any of the events that it receives, or add or remove any events to the event base, or otherwise modify any event associated with the event base, or undefined behavior can occur, up to or including crashes and heap-smashing.

The event_base lock will be held for the duration of the call to event_base_foreach_event() — this will block other threads from doing anything useful with the event_base, so make sure that your callback doesn’t take a long time.

Obsolete event loop functions

Current function

Obsolete current-base version

event_base_dispatch()

event_dispatch()

event_base_loop()

event_loop()

event_base_loopexit()

event_loopexit()

event_base_loopbreak()

event_loopbreak()

转载于:https://www.cnblogs.com/tadeas/p/10115383.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值