diff --git a/CMakeLists.txt b/CMakeLists.txt index bcf2dd1c..cd41d16e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1299,6 +1299,7 @@ if (NOT EVENT__DISABLE_TESTS) test/regress_testutils.h test/regress_util.c test/regress_watch.c + test/regress_timer_timeout.c test/regress_ws.c test/regress_ws.h test/tinytest.c) diff --git a/test/include.am b/test/include.am index 53a68223..e061c937 100644 --- a/test/include.am +++ b/test/include.am @@ -127,6 +127,7 @@ test_regress_SOURCES = \ test/regress_watch.c \ test/regress_ws.c \ test/regress_ws.h \ + test/regress_timer_timeout.c \ test/tinytest.c \ $(regress_thread_SOURCES) \ $(regress_zlib_SOURCES) diff --git a/test/regress.h b/test/regress.h index 0c0edf55..7237f07d 100644 --- a/test/regress.h +++ b/test/regress.h @@ -55,6 +55,7 @@ extern struct testcase_t listener_testcases[]; extern struct testcase_t listener_iocp_testcases[]; extern struct testcase_t thread_testcases[]; extern struct testcase_t watch_testcases[]; +extern struct testcase_t event_timer_testcases[]; extern struct evutil_weakrand_state test_weakrand_state; diff --git a/test/regress_main.c b/test/regress_main.c index a504d6ce..0d9f220f 100644 --- a/test/regress_main.c +++ b/test/regress_main.c @@ -454,6 +454,7 @@ struct testgroup_t testgroups[] = { { "thread/", thread_testcases }, { "listener/", listener_testcases }, { "watch/", watch_testcases }, + { "event_timer/", event_timer_testcases }, #ifdef _WIN32 { "iocp/", iocp_testcases }, { "iocp/bufferevent/", bufferevent_iocp_testcases }, diff --git a/test/regress_timer_timeout.c b/test/regress_timer_timeout.c new file mode 100644 index 00000000..87e8193d --- /dev/null +++ b/test/regress_timer_timeout.c @@ -0,0 +1,127 @@ +// Copyright (c) 2023 Krzysztof Dynowski krzydyn@gmail.com + +#include +#include +#include "regress.h" +#include "time-internal.h" + +#include +#include +#include +#include +#ifndef _WIN32 +#include +#endif + +typedef struct +{ + struct event_base *eb; + struct event *e; + struct timeval tv_tmo; +} EventTimeoutTest; + +static void trigger_timer(evutil_socket_t fd, short events, void * arg) +{ +} + +static void init_test(EventTimeoutTest *test, int flags) +{ + if (flags) { + struct event_config * cfg = event_config_new(); + event_config_set_flag(cfg, flags); + test->eb = event_base_new_with_config(cfg); + event_config_free(cfg); + } else { + test->eb = event_base_new(); + } + test->e = evtimer_new(test->eb, trigger_timer, NULL); +} +static void cleanup_test(EventTimeoutTest *test) +{ + event_del(test->e); + event_free(test->e); + event_base_free(test->eb); +} + +static void set_timer_tv(EventTimeoutTest *test, const struct timeval* delay) +{ + int result; + evutil_gettimeofday(&test->tv_tmo, NULL); + result = evtimer_add(test->e, delay); + if (result == -1) { + perror("evtimer_add"); + exit(1); + } + evutil_timeradd(&test->tv_tmo, delay, &test->tv_tmo); +} +static void set_timer(EventTimeoutTest *test, const long delay_us) +{ + struct timeval tv; + tv.tv_sec = delay_us/1000000; + tv.tv_usec = delay_us%1000000; + set_timer_tv(test, &tv); +} +static long remaining(EventTimeoutTest *test) +{ + struct timeval tv; + struct timeval now, rem; + int result = evtimer_pending(test->e, &tv); + if (result == -1) { + perror("evtimer_pending"); + exit(1); + } + if (result == 0) { + return LONG_MAX; + } + evutil_gettimeofday(&now, NULL); + evutil_timersub(&tv, &now, &rem); + return rem.tv_sec*10000000L + rem.tv_usec; +} + +static int test_with_flags(int flags) +{ + EventTimeoutTest test; + long i; + long err = 0; + int maxdiff = 0; + long rem, dur = 100; + struct timeval sleep_tm = { 0, 1 }; + init_test(&test, flags); + for (i = 0; i < 1000; ++i) { + set_timer(&test, dur); + rem = remaining(&test); + if (rem > dur) { + int d = rem - dur; + ++err; + if (maxdiff < d) maxdiff = d; + } + evutil_usleep_(&sleep_tm); + } + (void)err; + cleanup_test(&test); + return maxdiff; +} + +static void timer_timeout_test(void *arg) +{ + struct basic_test_data *data = arg; + const char *flags_str = data ? data->setup_data : NULL; + int maxdiff; + if (flags_str == NULL) { + maxdiff = test_with_flags(0); + tt_int_op(maxdiff, ==, 0); + } else if (strstr("precise", flags_str)) { + maxdiff = test_with_flags(EVENT_BASE_FLAG_PRECISE_TIMER); + tt_int_op(maxdiff, ==, 0); + } else { + tt_fail_msg("Unsupported clock"); + } +end: + ; +} + +struct testcase_t event_timer_testcases[] = { + { "default_clock", timer_timeout_test, TT_FORK, &basic_setup, NULL }, + { "precise_clock", timer_timeout_test, TT_FORK, &basic_setup, (void *)"precise" }, + END_OF_TESTCASES +};