mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-11 05:14:46 -04: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 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 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 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:
|
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);
|
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.
|
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);
|
va_list ap);
|
||||||
static void event_log(int severity, const char *msg);
|
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
|
void
|
||||||
event_err(int eval, const char *fmt, ...)
|
event_err(int eval, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
@ -75,7 +92,7 @@ event_err(int eval, const char *fmt, ...)
|
|||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
_warn_helper(_EVENT_LOG_ERR, strerror(errno), fmt, ap);
|
_warn_helper(_EVENT_LOG_ERR, strerror(errno), fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
exit(eval);
|
event_exit(eval);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -97,7 +114,7 @@ event_sock_err(int eval, evutil_socket_t sock, const char *fmt, ...)
|
|||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
_warn_helper(_EVENT_LOG_ERR, evutil_socket_error_to_string(err), fmt, ap);
|
_warn_helper(_EVENT_LOG_ERR, evutil_socket_error_to_string(err), fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
exit(eval);
|
event_exit(eval);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -119,7 +136,7 @@ event_errx(int eval, const char *fmt, ...)
|
|||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
_warn_helper(_EVENT_LOG_ERR, NULL, fmt, ap);
|
_warn_helper(_EVENT_LOG_ERR, NULL, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
exit(eval);
|
event_exit(eval);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -46,9 +46,11 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "event2/event.h"
|
||||||
#include "event2/util.h"
|
#include "event2/util.h"
|
||||||
#include "../ipv6-internal.h"
|
#include "../ipv6-internal.h"
|
||||||
#include "../util-internal.h"
|
#include "../util-internal.h"
|
||||||
|
#include "../log-internal.h"
|
||||||
|
|
||||||
#include "regress.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[] = {
|
struct testcase_t util_testcases[] = {
|
||||||
{ "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL },
|
{ "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL },
|
||||||
{ "ipv6_parse", regress_ipv6_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_snprintf", test_evutil_snprintf, 0, NULL, NULL },
|
||||||
{ "evutil_strtoll", test_evutil_strtoll, 0, NULL, NULL },
|
{ "evutil_strtoll", test_evutil_strtoll, 0, NULL, NULL },
|
||||||
{ "evutil_casecmp", test_evutil_casecmp, 0, NULL, NULL },
|
{ "evutil_casecmp", test_evutil_casecmp, 0, NULL, NULL },
|
||||||
|
{ "log", test_evutil_log, TT_FORK, NULL, NULL },
|
||||||
END_OF_TESTCASES,
|
END_OF_TESTCASES,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user