diff options
author | Cy Schubert <cy@FreeBSD.org> | 2023-11-14 23:02:42 +0000 |
---|---|---|
committer | Cy Schubert <cy@FreeBSD.org> | 2023-11-14 23:02:42 +0000 |
commit | 5223d1d95fddcef6f9a36e264a5800bd907ade8b (patch) | |
tree | 818b1eba912c588e39058586485699385c3179fe /test/regress.c | |
parent | cbc620a473ce23d882ba3e9f91ec0c6c12dcd239 (diff) |
Diffstat (limited to 'test/regress.c')
-rw-r--r-- | test/regress.c | 332 |
1 files changed, 237 insertions, 95 deletions
diff --git a/test/regress.c b/test/regress.c index d8a6b9b85485..08c30fab9b9b 100644 --- a/test/regress.c +++ b/test/regress.c @@ -31,10 +31,6 @@ #include <windows.h> #endif -#ifdef EVENT__HAVE_PTHREADS -#include <pthread.h> -#endif - #include "event2/event-config.h" #include <sys/types.h> @@ -46,6 +42,7 @@ #ifndef _WIN32 #include <sys/socket.h> #include <sys/wait.h> +#include <limits.h> #include <signal.h> #include <unistd.h> #include <netdb.h> @@ -72,6 +69,7 @@ #include "time-internal.h" #include "regress.h" +#include "regress_thread.h" #ifndef _WIN32 #include "regress.gen.h" @@ -389,7 +387,7 @@ record_event_cb(evutil_socket_t s, short what, void *ptr) } static void -test_simpleclose(void *ptr) +test_simpleclose_rw(void *ptr) { /* Test that a close of FD is detected as a read and as a write. */ struct event_base *base = event_base_new(); @@ -471,6 +469,56 @@ end: event_base_free(base); } +static void +test_simpleclose(void *ptr) +{ + struct basic_test_data *data = ptr; + struct event_base *base = data->base; + evutil_socket_t *pair = data->pair; + const char *flags = (const char *)data->setup_data; + int et = !!strstr(flags, "ET"); + int persist = !!strstr(flags, "persist"); + short events = EV_CLOSED | (et ? EV_ET : 0) | (persist ? EV_PERSIST : 0); + struct event *ev = NULL; + short got_event; + + if (!(event_base_get_features(data->base) & EV_FEATURE_EARLY_CLOSE)) + tt_skip(); + + /* XXX: should this code moved to regress_et.c ? */ + if (et && !(event_base_get_features(data->base) & EV_FEATURE_ET)) + tt_skip(); + + ev = event_new(base, pair[0], events, record_event_cb, &got_event); + tt_assert(ev); + tt_assert(!event_add(ev, NULL)); + + got_event = 0; + if (strstr(flags, "close")) { + tt_assert(!evutil_closesocket(pair[1])); + /* avoid closing in setup routines */ + pair[1] = -1; + } else if (strstr(flags, "shutdown")) { + tt_assert(!shutdown(pair[1], EVUTIL_SHUT_WR)); + } else { + tt_abort_msg("unknown flags"); + } + + /* w/o edge-triggerd but w/ persist it will not stop */ + if (!et && persist) { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 10000; + tt_assert(!event_base_loopexit(base, &tv)); + } + + tt_int_op(event_base_loop(base, EVLOOP_NONBLOCK), ==, !persist); + tt_int_op(got_event, ==, (events & ~EV_PERSIST)); + +end: + if (ev) + event_free(ev); +} static void test_multiple(void) @@ -848,18 +896,36 @@ simple_child_read_cb(evutil_socket_t fd, short event, void *arg) called++; } + +#define TEST_FORK_EXIT_SUCCESS 76 +static void fork_wait_check(int pid) +{ + int status; + + TT_BLATHER(("Before waitpid")); + +#ifdef WNOWAIT + if ((waitpid(pid, &status, WNOWAIT) == -1 && errno == EINVAL) && +#else + if ( +#endif + waitpid(pid, &status, 0) == -1) { + perror("waitpid"); + exit(1); + } + TT_BLATHER(("After waitpid")); + + if (WEXITSTATUS(status) != TEST_FORK_EXIT_SUCCESS) { + fprintf(stdout, "FAILED (exit): %d\n", WEXITSTATUS(status)); + exit(1); + } +} static void test_fork(void) { char c; - int status; struct event ev, sig_ev, usr_ev, existing_ev; pid_t pid; - int wait_flags = 0; - -#ifdef EVENT__HAVE_WAITPID_WITH_WNOWAIT - wait_flags |= WNOWAIT; -#endif setup_test("After fork: "); @@ -910,8 +976,8 @@ test_fork(void) evsignal_set(&usr_ev, SIGUSR1, fork_signal_cb, &usr_ev); evsignal_add(&usr_ev, NULL); - raise(SIGUSR1); - raise(SIGUSR2); + kill(getpid(), SIGUSR1); + kill(getpid(), SIGUSR2); called = 0; @@ -922,7 +988,7 @@ test_fork(void) /* we do not send an EOF; simple_read_cb requires an EOF * to set test_ok. we just verify that the callback was * called. */ - exit(test_ok != 0 || called != 2 ? -2 : 76); + exit(test_ok != 0 || called != 2 ? -2 : TEST_FORK_EXIT_SUCCESS); } /** wait until client read first message */ @@ -933,17 +999,7 @@ test_fork(void) tt_fail_perror("write"); } - TT_BLATHER(("Before waitpid")); - if (waitpid(pid, &status, wait_flags) == -1) { - perror("waitpid"); - exit(1); - } - TT_BLATHER(("After waitpid")); - - if (WEXITSTATUS(status) != 76) { - fprintf(stdout, "FAILED (exit): %d\n", WEXITSTATUS(status)); - exit(1); - } + fork_wait_check(pid); /* test that the current event loop still works */ if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { @@ -954,8 +1010,8 @@ test_fork(void) evsignal_set(&usr_ev, SIGUSR1, fork_signal_cb, &usr_ev); evsignal_add(&usr_ev, NULL); - raise(SIGUSR1); - raise(SIGUSR2); + kill(getpid(), SIGUSR1); + kill(getpid(), SIGUSR2); event_dispatch(); @@ -970,7 +1026,7 @@ test_fork(void) evutil_closesocket(child_pair[1]); } -#ifdef EVENT__HAVE_PTHREADS +#ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED static void* del_wait_thread(void *arg) { struct timeval tv_start, tv_end; @@ -989,23 +1045,23 @@ static void del_wait_cb(evutil_socket_t fd, short event, void *arg) { struct timeval delay = { 0, 300*1000 }; - TT_BLATHER(("Sleeping")); + TT_BLATHER(("Sleeping: %i", test_ok)); evutil_usleep_(&delay); - test_ok = 1; + ++test_ok; } static void test_del_wait(void) { struct event ev; - pthread_t thread; + THREAD_T thread; setup_test("event_del will wait: "); - event_set(&ev, pair[1], EV_READ, del_wait_cb, &ev); + event_set(&ev, pair[1], EV_READ|EV_PERSIST, del_wait_cb, &ev); event_add(&ev, NULL); - pthread_create(&thread, NULL, del_wait_thread, NULL); + THREAD_START(thread, del_wait_thread, NULL); if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { tt_fail_perror("write"); @@ -1024,11 +1080,41 @@ test_del_wait(void) test_timeval_diff_eq(&tv_start, &tv_end, 270); } - pthread_join(thread, NULL); + THREAD_JOIN(thread); + + tt_int_op(test_ok, ==, 1); end: ; } + +static void null_cb(evutil_socket_t fd, short what, void *arg) {} +static void* test_del_notify_thread(void *arg) +{ + event_dispatch(); + return NULL; +} +static void +test_del_notify(void) +{ + struct event ev; + THREAD_T thread; + + test_ok = 1; + + event_set(&ev, -1, EV_READ, null_cb, &ev); + event_add(&ev, NULL); + + THREAD_START(thread, test_del_notify_thread, NULL); + + { + struct timeval delay = { 0, 1000 }; + evutil_usleep_(&delay); + } + + event_del(&ev); + THREAD_JOIN(thread); +} #endif static void @@ -1127,7 +1213,7 @@ test_immediatesignal(void) test_ok = 0; evsignal_set(&ev, SIGUSR1, signal_cb, &ev); evsignal_add(&ev, NULL); - raise(SIGUSR1); + kill(getpid(), SIGUSR1); event_loop(EVLOOP_NONBLOCK); evsignal_del(&ev); cleanup_test(); @@ -1200,7 +1286,7 @@ test_signal_switchbase(void) test_ok = 0; /* can handle signal before loop is called */ - raise(SIGUSR1); + kill(getpid(), SIGUSR1); event_base_loop(base2, EVLOOP_NONBLOCK); if (is_kqueue) { if (!test_ok) @@ -1213,7 +1299,7 @@ test_signal_switchbase(void) /* set base1 to handle signals */ event_base_loop(base1, EVLOOP_NONBLOCK); - raise(SIGUSR1); + kill(getpid(), SIGUSR1); event_base_loop(base1, EVLOOP_NONBLOCK); event_base_loop(base2, EVLOOP_NONBLOCK); } @@ -1242,7 +1328,7 @@ test_signal_assert(void) */ evsignal_del(&ev); - raise(SIGCONT); + kill(getpid(), SIGCONT); #if 0 /* only way to verify we were in evsig_handler() */ /* XXXX Now there's no longer a good way. */ @@ -1286,7 +1372,7 @@ test_signal_restore(void) evsignal_add(&ev, NULL); evsignal_del(&ev); - raise(SIGUSR1); + kill(getpid(), SIGUSR1); /* 1 == signal_cb, 2 == signal_cb_sa, we want our previous handler */ if (test_ok != 2) test_ok = 0; @@ -1301,7 +1387,7 @@ signal_cb_swp(int sig, short event, void *arg) { called++; if (called < 5) - raise(sig); + kill(getpid(), sig); else event_loopexit(NULL); } @@ -1313,7 +1399,7 @@ timeout_cb_swp(evutil_socket_t fd, short event, void *arg) called = 0; evtimer_add((struct event *)arg, &tv); - raise(SIGUSR1); + kill(getpid(), SIGUSR1); return; } test_ok = 0; @@ -1351,18 +1437,14 @@ test_free_active_base(void *ptr) struct event ev1; base1 = event_init(); - if (base1) { - event_assign(&ev1, base1, data->pair[1], EV_READ, - dummy_read_cb, NULL); - event_add(&ev1, NULL); - event_base_free(base1); /* should not crash */ - } else { - tt_fail_msg("failed to create event_base for test"); - } + tt_assert(base1); + event_assign(&ev1, base1, data->pair[1], EV_READ, dummy_read_cb, NULL); + event_add(&ev1, NULL); + event_base_free(base1); /* should not crash */ base1 = event_init(); tt_assert(base1); - event_assign(&ev1, base1, 0, 0, dummy_read_cb, NULL); + event_assign(&ev1, base1, data->pair[0], 0, dummy_read_cb, NULL); event_active(&ev1, EV_READ, 1); event_base_free(base1); end: @@ -1840,7 +1922,8 @@ static void send_a_byte_cb(evutil_socket_t fd, short what, void *arg) { evutil_socket_t *sockp = arg; (void) fd; (void) what; - (void) write(*sockp, "A", 1); + if (write(*sockp, "A", 1) < 0) + tt_fail_perror("write"); } struct read_not_timeout_param { @@ -2070,60 +2153,48 @@ re_add_read_cb(evutil_socket_t fd, short event, void *arg) if (n_read < 0) { tt_fail_perror("read"); event_base_loopbreak(event_get_base(ev_other)); - return; } else { event_add(ev_other, NULL); ++test_ok; } } - static void -test_nonpersist_readd(void) +test_nonpersist_readd(void *_data) { struct event ev1, ev2; + struct basic_test_data *data = _data; - setup_test("Re-add nonpersistent events: "); - event_set(&ev1, pair[0], EV_READ, re_add_read_cb, &ev2); - event_set(&ev2, pair[1], EV_READ, re_add_read_cb, &ev1); + memset(&ev1, 0, sizeof(ev1)); + memset(&ev2, 0, sizeof(ev2)); - if (write(pair[0], "Hello", 5) < 0) { - tt_fail_perror("write(pair[0])"); - } + tt_assert(!event_assign(&ev1, data->base, data->pair[0], EV_READ, re_add_read_cb, &ev2)); + tt_assert(!event_assign(&ev2, data->base, data->pair[1], EV_READ, re_add_read_cb, &ev1)); - if (write(pair[1], "Hello", 5) < 0) { - tt_fail_perror("write(pair[1])\n"); - } + tt_int_op(write(data->pair[0], "Hello", 5), ==, 5); + tt_int_op(write(data->pair[1], "Hello", 5), ==, 5); + + tt_int_op(event_add(&ev1, NULL), ==, 0); + tt_int_op(event_add(&ev2, NULL), ==, 0); + tt_int_op(event_base_loop(data->base, EVLOOP_ONCE), ==, 0); + tt_int_op(test_ok, ==, 2); - if (event_add(&ev1, NULL) == -1 || - event_add(&ev2, NULL) == -1) { - test_ok = 0; - } - if (test_ok != 0) - exit(1); - event_loop(EVLOOP_ONCE); - if (test_ok != 2) - exit(1); /* At this point, we executed both callbacks. Whichever one got * called first added the second, but the second then immediately got * deleted before its callback was called. At this point, though, it * re-added the first. */ - if (!readd_test_event_last_added) { - test_ok = 0; - } else if (readd_test_event_last_added == &ev1) { - if (!event_pending(&ev1, EV_READ, NULL) || - event_pending(&ev2, EV_READ, NULL)) - test_ok = 0; + tt_assert(readd_test_event_last_added); + if (readd_test_event_last_added == &ev1) { + tt_assert(event_pending(&ev1, EV_READ, NULL) && !event_pending(&ev2, EV_READ, NULL)); } else { - if (event_pending(&ev1, EV_READ, NULL) || - !event_pending(&ev2, EV_READ, NULL)) - test_ok = 0; + tt_assert(event_pending(&ev2, EV_READ, NULL) && !event_pending(&ev1, EV_READ, NULL)); } - event_del(&ev1); - event_del(&ev2); - - cleanup_test(); +end: + if (event_initialized(&ev1)) + event_del(&ev1); + if (event_initialized(&ev2)) + event_del(&ev2); } struct test_pri_event { @@ -3041,6 +3112,7 @@ test_many_events(void *arg) * instance of that. */ sock[i] = socket(AF_INET, SOCK_DGRAM, 0); tt_assert(sock[i] >= 0); + tt_assert(!evutil_make_socket_nonblocking(sock[i])); called[i] = 0; ev[i] = event_new(base, sock[i], EV_WRITE|evflags, many_event_cb, &called[i]); @@ -3094,7 +3166,7 @@ test_get_assignment(void *arg) event_get_assignment(ev1, &b, &s, &what, &cb, &cb_arg); tt_ptr_op(b, ==, base); - tt_int_op(s, ==, data->pair[1]); + tt_fd_op(s, ==, data->pair[1]); tt_int_op(what, ==, EV_READ); tt_ptr_op(cb, ==, dummy_read_cb); tt_ptr_op(cb_arg, ==, str); @@ -3280,6 +3352,46 @@ tabf_cb(evutil_socket_t fd, short what, void *arg) } static void +test_evmap_invalid_slots(void *arg) +{ + struct basic_test_data *data = arg; + struct event_base *base = data->base; + struct event *ev1 = NULL, *ev2 = NULL; + int e1, e2; +#ifndef _WIN32 + struct event *ev3 = NULL, *ev4 = NULL; + int e3, e4; +#endif + + ev1 = evsignal_new(base, -1, dummy_read_cb, (void *)base); + ev2 = evsignal_new(base, NSIG, dummy_read_cb, (void *)base); + tt_assert(ev1); + tt_assert(ev2); + e1 = event_add(ev1, NULL); + e2 = event_add(ev2, NULL); + tt_int_op(e1, !=, 0); + tt_int_op(e2, !=, 0); +#ifndef _WIN32 + ev3 = event_new(base, INT_MAX, EV_READ, dummy_read_cb, (void *)base); + ev4 = event_new(base, INT_MAX / 2, EV_READ, dummy_read_cb, (void *)base); + tt_assert(ev3); + tt_assert(ev4); + e3 = event_add(ev3, NULL); + e4 = event_add(ev4, NULL); + tt_int_op(e3, !=, 0); + tt_int_op(e4, !=, 0); +#endif + +end: + event_free(ev1); + event_free(ev2); +#ifndef _WIN32 + event_free(ev3); + event_free(ev4); +#endif +} + +static void test_active_by_fd(void *arg) { struct basic_test_data *data = arg; @@ -3330,6 +3442,7 @@ test_active_by_fd(void *arg) /* Trigger 2, 3, 4 */ event_base_active_by_fd(base, data->pair[0], EV_WRITE); event_base_active_by_fd(base, data->pair[1], EV_READ); + event_base_active_by_fd(base, data->pair[1], EV_TIMEOUT); #ifndef _WIN32 event_base_active_by_signal(base, SIGHUP); #endif @@ -3342,7 +3455,7 @@ test_active_by_fd(void *arg) tt_int_op(e2, ==, EV_WRITE | 0x10000); tt_int_op(e3, ==, EV_READ | 0x10000); /* Mask out EV_WRITE here, since it could be genuinely writeable. */ - tt_int_op((e4 & ~EV_WRITE), ==, EV_READ | 0x10000); + tt_int_op((e4 & ~EV_WRITE), ==, EV_READ | EV_TIMEOUT | 0x10000); #ifndef _WIN32 tt_int_op(es, ==, EV_SIGNAL | 0x10000); #endif @@ -3377,17 +3490,18 @@ struct testcase_t main_testcases[] = { BASIC(event_assign_selfarg, TT_FORK|TT_NEED_BASE), BASIC(event_base_get_num_events, TT_FORK|TT_NEED_BASE), BASIC(event_base_get_max_events, TT_FORK|TT_NEED_BASE), + BASIC(evmap_invalid_slots, TT_FORK|TT_NEED_BASE), BASIC(bad_assign, TT_FORK|TT_NEED_BASE|TT_NO_LOGS), BASIC(bad_reentrant, TT_FORK|TT_NEED_BASE|TT_NO_LOGS), - BASIC(active_later, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR), + BASIC(active_later, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR|TT_RETRIABLE), BASIC(event_remove_timeout, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR), /* These are still using the old API */ LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE), { "persistent_timeout_jump", test_persistent_timeout_jump, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, { "persistent_active_timeout", test_persistent_active_timeout, - TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, + TT_FORK|TT_NEED_BASE|TT_RETRIABLE, &basic_setup, NULL }, LEGACY(priorities, TT_FORK|TT_NEED_BASE), BASIC(priority_active_inversion, TT_FORK|TT_NEED_BASE), { "common_timeout", test_common_timeout, TT_FORK|TT_NEED_BASE, @@ -3397,8 +3511,35 @@ struct testcase_t main_testcases[] = { LEGACY(simpleread, TT_ISOLATED), LEGACY(simpleread_multiple, TT_ISOLATED), LEGACY(simplewrite, TT_ISOLATED), - { "simpleclose", test_simpleclose, TT_FORK, &basic_setup, - NULL }, + { "simpleclose_rw", test_simpleclose_rw, TT_FORK, &basic_setup, NULL }, + /* simpleclose */ + { "simpleclose_close", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"close" }, + { "simpleclose_shutdown", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"shutdown" }, + /* simpleclose_*_persist */ + { "simpleclose_close_persist", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"close_persist" }, + { "simpleclose_shutdown_persist", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"shutdown_persist" }, + /* simpleclose_*_et */ + { "simpleclose_close_et", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"close_ET" }, + { "simpleclose_shutdown_et", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"shutdown_ET" }, + /* simpleclose_*_persist_et */ + { "simpleclose_close_persist_et", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"close_persist_ET" }, + { "simpleclose_shutdown_persist_et", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"shutdown_persist_ET" }, LEGACY(multiple, TT_ISOLATED), LEGACY(persistent, TT_ISOLATED), LEGACY(combined, TT_ISOLATED), @@ -3406,7 +3547,7 @@ struct testcase_t main_testcases[] = { LEGACY(loopbreak, TT_ISOLATED), LEGACY(loopexit, TT_ISOLATED), LEGACY(loopexit_multiple, TT_ISOLATED), - LEGACY(nonpersist_readd, TT_ISOLATED), + { "nonpersist_readd", test_nonpersist_readd, TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, &basic_setup, NULL }, LEGACY(multiple_events_for_same_fd, TT_ISOLATED), LEGACY(want_only_once, TT_ISOLATED), { "event_once", test_event_once, TT_ISOLATED, &basic_setup, NULL }, @@ -3438,9 +3579,10 @@ struct testcase_t main_testcases[] = { #ifndef _WIN32 LEGACY(fork, TT_ISOLATED), #endif -#ifdef EVENT__HAVE_PTHREADS - /** TODO: support win32 */ - LEGACY(del_wait, TT_ISOLATED|TT_NEED_THREADS), + +#ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED + LEGACY(del_wait, TT_ISOLATED|TT_NEED_THREADS|TT_RETRIABLE), + LEGACY(del_notify, TT_ISOLATED|TT_NEED_THREADS), #endif END_OF_TESTCASES |