aboutsummaryrefslogtreecommitdiff
path: root/test/regress.c
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2023-11-14 23:02:42 +0000
committerCy Schubert <cy@FreeBSD.org>2023-11-14 23:02:42 +0000
commit5223d1d95fddcef6f9a36e264a5800bd907ade8b (patch)
tree818b1eba912c588e39058586485699385c3179fe /test/regress.c
parentcbc620a473ce23d882ba3e9f91ec0c6c12dcd239 (diff)
Diffstat (limited to 'test/regress.c')
-rw-r--r--test/regress.c332
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