Nick Mathewson 著
晨星 翻譯
老衣 整理
libevent有一些被整個進程共享的、影響整個庫的全局設置。必須在調用libevent庫的任何其餘部分以前修改這些設置,不然,libevent會進入不一致的狀態。安全
1 Libevent中的日誌消息
libevent能夠記錄內部錯誤和警告。若是編譯進日誌支持,還會記錄調試信息。默認配置下這些信息被寫到stderr。經過提供定製的日誌函數能夠覆蓋默認行爲。函數
接口
示例
- #include <event2/event.h>
- #include <stdio.h>
-
- static void discard_cb(int severity, const char *msg)
- {
- /* This callback does nothing. */
- }
-
- static FILE *logfile = NULL;
- static void write_to_file_cb(int severity, const char *msg)
- {
- const char *s;
- if (!logfile)
- return;
- switch (severity) {
- case _EVENT_LOG_DEBUG: s = "debug"; break;
- case _EVENT_LOG_MSG: s = "msg"; break;
- case _EVENT_LOG_WARN: s = "warn"; break;
- case _EVENT_LOG_ERR: s = "error"; break;
- default: s = "?"; break; /* never reached */
- }
- fprintf(logfile, "[%s] %s/n", s, msg);
- }
-
- /* Turn off all logging from Libevent. */
- void suppress_logging(void)
- {
- event_set_log_callback(discard_cb);
- }
-
- /* Redirect all Libevent log messages to the C stdio file 'f'. */
- void set_logfile(FILE *f)
- {
- logfile = f;
- event_set_log_callback(write_to_file_cb);
- }
注意
在用戶提供的event_log_cb回調函數中調用libevent函數是不安全的。好比說,若是試圖編寫一個使用bufferevent將警告信息發送給某個套接字的日誌回調函數,可能會遇到奇怪而難以診斷的bug。將來版本libevent的某些函數可能會移除這個限制。工具
這個函數在<event2/event.h>中聲明,在libevent 1.0c版本中首次出現。this
2 處理致命錯誤
libevent在檢測到不可恢復的內部錯誤時的默認行爲是調用exit()或者abort(),退出正在運行的進程。這類錯誤一般意味着某處有bug:要麼在你的代碼中,要麼在libevent中。.net
若是但願更優雅地處理致命錯誤,能夠爲libevent提供在退出時應該調用的函數,覆蓋默認行爲。線程
接口
- typedef void (*event_fatal_cb)(int err);
- void event_set_fatal_callback(event_fatal_cb cb);
3 內存管理
默認狀況下,libevent使用C庫的內存管理函數在堆上分配內存。經過提供malloc、realloc和free的替代函數,可讓libevent使用其餘的內存管理器。但願libevent使用一個更高效的分配器時,或者但願libevent使用一個工具分配器以便檢查內存泄漏時,可能須要這樣作。翻譯
接口
- void event_set_mem_functions(void *(*malloc_fn)(size_t sz),
- void *(*realloc_fn)(void *ptr, size_t sz),
- void (*free_fn)(void *ptr));
這裏有個替換libevent分配器函數的示例,它能夠計算已經分配的字節數。實際應用中可能須要添加鎖,以免運行在多個線程中時發生錯誤。debug
示例
- #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. */
- #define OUTPTR(ptr) (((char*)ptr)+ALIGNMENT)
- #define INPTR(ptr) (((char*)ptr)-ALIGNMENT)
-
- static size_t total_allocated = 0;
- static void *replacement_malloc(size_t sz)
- {
- void *chunk = malloc(sz + ALIGNMENT);
- if (!chunk) return chunk;
- total_allocated += sz;
- *(size_t*)chunk = sz;
- return OUTPTR(chunk);
- }
- static void *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_allocated = total_allocated - old_size + sz;
- return OUTPTR(ptr);
- }
- static void replacement_free(void *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);
- }
注意
² 替換內存管理函數影響libevent隨後的全部分配、調整大小和釋放內存操做。因此,必須保證在調用任何其餘libevent函數以前進行替換。不然,libevent可能用你的free函數釋放用C庫的malloc分配的內存。調試
² 你的malloc和realloc函數返回的內存塊應該具備和C庫返回的內存塊同樣的地址對齊。日誌
² 你的realloc函數應該正確處理realloc(NULL,sz)(也就是看成malloc(sz)處理)
² 你的realloc函數應該正確處理realloc(ptr,0)(也就是看成free(ptr)處理)
² 你的free函數沒必要處理free(NULL)
² 你的malloc函數沒必要處理malloc(0)
² 若是在多個線程中使用libevent,替代的內存管理函數須要是線程安全的。
² libevent將使用這些函數分配返回給你的內存。因此,若是要釋放由libevent函數分配和返回的內存,而你已經替換malloc和realloc函數,那麼應該使用替代的free函數。
event_set_mem_functions函數聲明在<event2/event.h>中,在libevent 2.0.1-alpha版本中首次出現。
能夠在禁止event_set_mem_functions函數的配置下編譯libevent。這時候使用event_set_mem_functions將不會編譯或者連接。在2.0.2-alpha及之後版本中,能夠經過檢查是否認義了EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED宏來肯定event_set_mem_functions函數是否存在。