mirror of
https://github.com/libevent/libevent.git
synced 2025-01-31 09:12:55 +08:00
API to replace all calls to exit() with a user-supplied fatal-error handler.
Also, add unit tests for logging. svn:r1462
This commit is contained in:
parent
38aec9ec7c
commit
a8267663de
@ -32,6 +32,7 @@ Changes in 2.0.3-alpha:
|
||||
o Fix a bug when using a specialized memory allocator on win32.
|
||||
o Have the win32 select() backend label TCP-socket-connected events as EV_WRITE, not EV_READ. This should bring it in line with the other backends, and improve portability. Patch from Christopher Davis.
|
||||
o Stop using enums as arguments or return values when what we mean is a bitfield of enum values. C++ doesn't believe that you can OR two enum values together and get another enum, and C++ takes its typing seriously. Patch from Christopher Davis.
|
||||
o Add an API to replace all fatal calls to exit() with a user-provided panic function.
|
||||
|
||||
|
||||
Changes in 2.0.2-alpha:
|
||||
|
@ -240,6 +240,21 @@ typedef void (*event_log_cb)(int severity, const char *msg);
|
||||
*/
|
||||
void event_set_log_callback(event_log_cb cb);
|
||||
|
||||
/**
|
||||
Override Libevent's behavior in the event of a fatal internal error.
|
||||
|
||||
By default, Libevent will call exit(1) if a programming error makes it
|
||||
impossible to continue correct operation. This function allows you to supply
|
||||
another callback instead. Note that if the function is ever invoked,
|
||||
something is wrong with your program, or with Libevent: any subsequent calls
|
||||
to Libevent may result in undefined behavior.
|
||||
|
||||
Libevent will (almost) always log an _EVENT_LOG_ERR message before calling
|
||||
this function; look at the last log message to see why Libevent has died.
|
||||
*/
|
||||
typedef void (*event_fatal_cb)(int err);
|
||||
void event_set_fatal_callback(event_fatal_cb cb);
|
||||
|
||||
/**
|
||||
Associate a different event base with an event.
|
||||
|
||||
|
23
log.c
23
log.c
@ -67,6 +67,23 @@ static void _warn_helper(int severity, const char *errstr, const char *fmt,
|
||||
va_list ap);
|
||||
static void event_log(int severity, const char *msg);
|
||||
|
||||
static event_fatal_cb fatal_fn = NULL;
|
||||
|
||||
void
|
||||
event_set_fatal_callback(event_fatal_cb cb)
|
||||
{
|
||||
fatal_fn = cb;
|
||||
}
|
||||
|
||||
static void
|
||||
event_exit(int errcode)
|
||||
{
|
||||
if (fatal_fn)
|
||||
fatal_fn(errcode);
|
||||
else
|
||||
exit(errcode);
|
||||
}
|
||||
|
||||
void
|
||||
event_err(int eval, const char *fmt, ...)
|
||||
{
|
||||
@ -75,7 +92,7 @@ event_err(int eval, const char *fmt, ...)
|
||||
va_start(ap, fmt);
|
||||
_warn_helper(_EVENT_LOG_ERR, strerror(errno), fmt, ap);
|
||||
va_end(ap);
|
||||
exit(eval);
|
||||
event_exit(eval);
|
||||
}
|
||||
|
||||
void
|
||||
@ -97,7 +114,7 @@ event_sock_err(int eval, evutil_socket_t sock, const char *fmt, ...)
|
||||
va_start(ap, fmt);
|
||||
_warn_helper(_EVENT_LOG_ERR, evutil_socket_error_to_string(err), fmt, ap);
|
||||
va_end(ap);
|
||||
exit(eval);
|
||||
event_exit(eval);
|
||||
}
|
||||
|
||||
void
|
||||
@ -119,7 +136,7 @@ event_errx(int eval, const char *fmt, ...)
|
||||
va_start(ap, fmt);
|
||||
_warn_helper(_EVENT_LOG_ERR, NULL, fmt, ap);
|
||||
va_end(ap);
|
||||
exit(eval);
|
||||
event_exit(eval);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -46,9 +46,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "event2/event.h"
|
||||
#include "event2/util.h"
|
||||
#include "../ipv6-internal.h"
|
||||
#include "../util-internal.h"
|
||||
#include "../log-internal.h"
|
||||
|
||||
#include "regress.h"
|
||||
|
||||
@ -325,6 +327,122 @@ end:
|
||||
;
|
||||
}
|
||||
|
||||
static int logsev = 0;
|
||||
static char *logmsg = NULL;
|
||||
|
||||
static void
|
||||
logfn(int severity, const char *msg)
|
||||
{
|
||||
logsev = severity;
|
||||
tt_want(msg);
|
||||
if (msg)
|
||||
logmsg = strdup(msg);
|
||||
}
|
||||
|
||||
static int exited = 0;
|
||||
static int exitcode = 0;
|
||||
static void
|
||||
fatalfn(int c)
|
||||
{
|
||||
exited = 1;
|
||||
exitcode = c;
|
||||
}
|
||||
|
||||
static void
|
||||
test_evutil_log(void *ptr)
|
||||
{
|
||||
evutil_socket_t fd = -1;
|
||||
char buf[128];
|
||||
|
||||
event_set_log_callback(logfn);
|
||||
event_set_fatal_callback(fatalfn);
|
||||
#define RESET() do { \
|
||||
logsev = exited = exitcode = 0; \
|
||||
if (logmsg) free(logmsg); \
|
||||
logmsg = NULL; \
|
||||
} while (0)
|
||||
#define LOGEQ(sev,msg) do { \
|
||||
tt_int_op(logsev,==,sev); \
|
||||
tt_assert(logmsg != NULL); \
|
||||
tt_str_op(logmsg,==,msg); \
|
||||
} while (0)
|
||||
|
||||
event_errx(2, "Fatal error; too many kumquats (%d)", 5);
|
||||
LOGEQ(_EVENT_LOG_ERR, "Fatal error; too many kumquats (5)");
|
||||
tt_int_op(exitcode,==,2);
|
||||
RESET();
|
||||
|
||||
event_warnx("Far too many %s (%d)", "wombats", 99);
|
||||
LOGEQ(_EVENT_LOG_WARN, "Far too many wombats (99)");
|
||||
tt_int_op(exited,==,0);
|
||||
RESET();
|
||||
|
||||
event_msgx("Connecting lime to coconut");
|
||||
LOGEQ(_EVENT_LOG_MSG, "Connecting lime to coconut");
|
||||
tt_int_op(exited,==,0);
|
||||
RESET();
|
||||
|
||||
event_debug("A millisecond passed! We should log that!");
|
||||
#ifdef USE_DEBUG
|
||||
LOGEQ(_EVENT_LOG_DEBUG, "A millisecond passed! We should log that!");
|
||||
#else
|
||||
tt_int_op(logsev,==,0);
|
||||
tt_ptr_op(logmsg,==,NULL);
|
||||
#endif
|
||||
RESET();
|
||||
|
||||
/* Try with an errno. */
|
||||
errno = ENOENT;
|
||||
event_warn("Couldn't open %s", "/bad/file");
|
||||
evutil_snprintf(buf, sizeof(buf),
|
||||
"Couldn't open /bad/file: %s",strerror(ENOENT));
|
||||
LOGEQ(_EVENT_LOG_WARN,buf);
|
||||
tt_int_op(exited, ==, 0);
|
||||
RESET();
|
||||
|
||||
errno = ENOENT;
|
||||
event_err(5,"Couldn't open %s", "/very/bad/file");
|
||||
evutil_snprintf(buf, sizeof(buf),
|
||||
"Couldn't open /very/bad/file: %s",strerror(ENOENT));
|
||||
LOGEQ(_EVENT_LOG_ERR,buf);
|
||||
tt_int_op(exitcode, ==, 5);
|
||||
RESET();
|
||||
|
||||
/* Try with a socket errno. */
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
#ifdef WIN32
|
||||
evutil_snprintf(buf, sizeof(buf),
|
||||
"Unhappy socket: Resource temporarily unavailable");
|
||||
EVUTIL_SET_SOCKET_ERROR(fd, WSAEWOULDBLOCK);
|
||||
#else
|
||||
evutil_snprintf(buf, sizeof(buf),
|
||||
"Unhappy socket: %s", strerror(EAGAIN));
|
||||
errno = EAGAIN;
|
||||
#endif
|
||||
event_sock_warn(fd, "Unhappy socket");
|
||||
LOGEQ(_EVENT_LOG_WARN, buf);
|
||||
tt_int_op(exited,==,0);
|
||||
RESET();
|
||||
|
||||
#ifdef WIN32
|
||||
EVUTIL_SET_SOCKET_ERROR(fd, WSAEWOULDBLOCK);
|
||||
#else
|
||||
errno = EAGAIN;
|
||||
#endif
|
||||
event_sock_err(200, fd, "Unhappy socket");
|
||||
LOGEQ(_EVENT_LOG_ERR, buf);
|
||||
tt_int_op(exitcode,==,200);
|
||||
RESET();
|
||||
|
||||
#undef RESET
|
||||
#undef LOGEQ
|
||||
end:
|
||||
if (logmsg)
|
||||
free(logmsg);
|
||||
if (fd >= 0)
|
||||
EVUTIL_CLOSESOCKET(fd);
|
||||
}
|
||||
|
||||
struct testcase_t util_testcases[] = {
|
||||
{ "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL },
|
||||
{ "ipv6_parse", regress_ipv6_parse, 0, NULL, NULL },
|
||||
@ -332,6 +450,7 @@ struct testcase_t util_testcases[] = {
|
||||
{ "evutil_snprintf", test_evutil_snprintf, 0, NULL, NULL },
|
||||
{ "evutil_strtoll", test_evutil_strtoll, 0, NULL, NULL },
|
||||
{ "evutil_casecmp", test_evutil_casecmp, 0, NULL, NULL },
|
||||
{ "log", test_evutil_log, TT_FORK, NULL, NULL },
|
||||
END_OF_TESTCASES,
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user