Libevent中的日志消息
Ibevent会记录内部发生的错误和警告,当然,我们也可以自己实现日志函数覆盖框架原本提供的
typedefvoid (*event_log_cb)(intseverity, constchar *msg);
void event_set_log_callback(event_log_cb cb);
可见,我们可以通过给event_set_log_callback 函数传递参数的形式使框架调用我们的函数。如果想恢复使用默认函数,那么给此函数传递NULL就行
处理致命错误
Libevent框架处理致命错误的方式一般是调用 exit 或是abort ,这种错误意味着程序中存在着bug,无论是在你写的程序还是libevent里。
因此,如果我们希望程序可以更明智的处理发生的这类问题,我们可以自己提供处理这种错误的函数:
typedefvoid (*event_fatal_cb)(int err); void event_set_fatal_callback(event_fatal_cb cb);
既然发生了这类错误,且调用自己的函数去处理了,我们就不能再把控制权转给libevent了,因为这回导致libevent不确定的行为。
内存管理
Libevent使用的是C中的malloc, realloc,free
如果你有更好的,也可以替代
void event_set_mem_functions(void *(*malloc_fn)(size_t sz),
void *(*realloc_fn)(void *ptr, size_t sz),
void (*free_fn)(void *ptr));
书上给了一个替换了例子,例子里替换这三个函数主要是为了计算当前已经申请了多少空间
#include <event2/event.h> #include <sys/types.h> #include <stdlib.h> /* This union's purpose is to be as big as the largest of all the * types it contains. */ union alignment { size_t sz; void *ptr; double dbl; }; /* We need to make sure that everything we return is on the right alignment to hold anything, including a double. */ #define ALIGNMENT sizeof(union alignment) /* We need to do this cast-to-char* trick on our pointers to adjust them; doing arithmetic on a void* is not standard. */ //void类型指针不适合作计算; 指针做加法是往后移; 减法往前挪 #define OUTPTR(ptr) (((char*)ptr)+ALIGNMENT) #define INPTR(ptr) (((char*)ptr)-ALIGNMENT) static size_t total_allocated = 0; staticvoid *replacement_malloc(size_t sz) { //故意躲分配一个size_t的空间,用于记录本段内存的大小 void *chunk = malloc(sz + ALIGNMENT); if (!chunk) return chunk; total_allocated += sz; //这里记录下本段空间的大小 *(size_t*)chunk = sz; //这里返回的是客户要用的空间,而本段空间之前的size_t大小的空间就一直留着以后用 return OUTPTR(chunk); } staticvoid *replacement_realloc(void *ptr, size_t sz) { size_t old_size = 0; //如果本段空间是本就存在的,那么先得到它的大小 if (ptr) { ptr = INPTR(ptr); old_size = *(size_t*)ptr; } //重新申请的空间也要多申请,用于记录空间大小 ptr = realloc(ptr, sz + ALIGNMENT); if (!ptr) return NULL; *(size_t*)ptr = sz; //最后总大小就是total减去原本ptr指向空间大小,加上现在重新申请的空间的大小 total_allocated = total_allocated - old_size + sz; return OUTPTR(ptr); } staticvoid replacement_free(void *ptr) { //因为之前申请都是申请客户需要的大小加上一个size_t大小的内存,所以现在free也要都free掉,ptr往前挪之后 *(size_t*)ptr就注明了本段空间的大小 ptr = INPTR(ptr); total_allocated -= *(size_t*)ptr; free(ptr); } void start_counting_bytes(void) { event_set_mem_functions(replacement_malloc, replacement_realloc, replacement_free); }
要注意的是:
1、 内存分配是个普遍需求,一定要在调用任何其他libevent函数之前就声明好我们自己的空间配置函数
2、 Your realloc function needs to handle realloc(NULL, sz) correctly(that is, by treating it as malloc(sz))
3、 要配套,别只替换三个中的某(两)个函数
锁和线程
要注意的是:
1、 某些结构体总是只能在单线程操作的,多线程中处理总是不安全的
2、 某些结构体可选锁,可告知libevent是否需要在多线程中使用每个对象
3、 某些结构体总是锁定的,如果libevent在支持锁的配置下运行,总是安全的
如果使用pthread 或windows下的锁,那么是提供的:
#ifdef WIN32 int evthread_use_windows_threads(void); #define EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED #endif #ifdef _EVENT_HAVE_PTHREADS int evthread_use_pthreads(void); #define EVTHREAD_USE_PTHREADS_IMPLEMENTED #endif
否则提供自己的线程实现。这里不再继续