# HG changeset patch # User Olaf Wintermann # Date 1723824545 -7200 # Node ID 4ed0e46aa9dca615d2cedb500c88bba5a833771a # Parent 97039494764b3d2d730a8de30ddc8fe30e8dabc5 add test for sending multiple events to an eventhandler diff -r 97039494764b -r 4ed0e46aa9dc src/server/daemon/event.c --- a/src/server/daemon/event.c Fri Aug 16 16:59:05 2024 +0200 +++ b/src/server/daemon/event.c Fri Aug 16 18:09:05 2024 +0200 @@ -78,11 +78,25 @@ return ret; } +void evhandler_shutdown(EVHandler *h) { + for(int i=0;inumins;i++) { + ev_instance_shutdown(h->instances[i]); + } +} + void evhandler_close(EVHandler *h) { for(int i=0;inumins;i++) { ev_instance_close(h->instances[i]); } - h->numins = 0; +} + +void evhandler_wait_and_destroy(EVHandler *h) { + for(int i=0;inumins;i++) { + ev_instance_wait(h->instances[i]); + } + + free(h->instances); + free(h); } /* diff -r 97039494764b -r 4ed0e46aa9dc src/server/daemon/event.h --- a/src/server/daemon/event.h Fri Aug 16 16:59:05 2024 +0200 +++ b/src/server/daemon/event.h Fri Aug 16 18:09:05 2024 +0200 @@ -89,8 +89,12 @@ } EventHandler; +void evhandler_shutdown(EVHandler *h); + void evhandler_close(EVHandler *h); +void evhandler_wait_and_destroy(EVHandler *h); + int create_event_handler(EventHandlerConfig *cfg); int check_event_handler_cfg(); @@ -110,6 +114,7 @@ EVHandler* evhandler_create(EventHandlerConfig *cfg); void ev_instance_close(EventHandler *h); void ev_instance_shutdown(EventHandler *h); +void ev_instance_wait(EventHandler *h); int ev_pollin(EventHandler *h, int fd, Event *event); int ev_pollout(EventHandler *h, int fd, Event *event); diff -r 97039494764b -r 4ed0e46aa9dc src/server/daemon/event_bsd.c --- a/src/server/daemon/event_bsd.c Fri Aug 16 16:59:05 2024 +0200 +++ b/src/server/daemon/event_bsd.c Fri Aug 16 18:09:05 2024 +0200 @@ -53,17 +53,22 @@ return NULL; } - SYS_THREAD t = systhread_start( + handler->thr = systhread_start( 0, 0, (thrstartfunc)ev_handle_events, handler); - systhread_detach(t); } return ev; } +void ev_instance_wait(EventHandler *h) { + EventHandlerLinux *ev = (EventHandlerLinux*)h; + void *ret; + pthread_join(ev->thr, &ret); +} + static volatile int ev_close = 0; void ev_instance_close(EventHandler *h) { diff -r 97039494764b -r 4ed0e46aa9dc src/server/daemon/event_bsd.h --- a/src/server/daemon/event_bsd.h Fri Aug 16 16:59:05 2024 +0200 +++ b/src/server/daemon/event_bsd.h Fri Aug 16 18:09:05 2024 +0200 @@ -45,6 +45,11 @@ */ EventHandler base; + /* + * eventhandler thread + */ + pthread_t thr; + int kqueue; } EventHandlerKqueue; diff -r 97039494764b -r 4ed0e46aa9dc src/server/daemon/event_linux.c --- a/src/server/daemon/event_linux.c Fri Aug 16 16:59:05 2024 +0200 +++ b/src/server/daemon/event_linux.c Fri Aug 16 18:09:05 2024 +0200 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -92,17 +93,22 @@ return NULL; } - SYS_THREAD t = systhread_start( + handler->thr = systhread_start( 0, 0, (thrstartfunc)ev_handle_events, handler); - systhread_detach(t); } return ev; } +void ev_instance_wait(EventHandler *h) { + EventHandlerLinux *ev = (EventHandlerLinux*)h; + void *ret; + pthread_join(ev->thr, &ret); +} + static volatile int ev_close = 0; void ev_instance_close(EventHandler *h) { @@ -254,7 +260,7 @@ loop_ctn = 0; } } - + // epoll fd is already closed ev_queue_free(ev->queue_begin); diff -r 97039494764b -r 4ed0e46aa9dc src/server/daemon/event_linux.h --- a/src/server/daemon/event_linux.h Fri Aug 16 16:59:05 2024 +0200 +++ b/src/server/daemon/event_linux.h Fri Aug 16 18:09:05 2024 +0200 @@ -49,6 +49,11 @@ EventHandler base; /* + * eventhandler thread + */ + pthread_t thr; + + /* * epoll fd */ int ep; diff -r 97039494764b -r 4ed0e46aa9dc src/server/daemon/event_solaris.c --- a/src/server/daemon/event_solaris.c Fri Aug 16 16:59:05 2024 +0200 +++ b/src/server/daemon/event_solaris.c Fri Aug 16 18:09:05 2024 +0200 @@ -53,17 +53,22 @@ return NULL; } - SYS_THREAD t = systhread_start( + handler->thr = systhread_start( 0, 0, (thrstartfunc)ev_handle_events, handler); - systhread_detach(t); } return ev; } +void ev_instance_wait(EventHandler *h) { + EventHandlerLinux *ev = (EventHandlerLinux*)h; + void *ret; + pthread_join(ev->thr, &ret); +} + static volatile int ev_close = 0; void ev_instance_close(EventHandler *h) { diff -r 97039494764b -r 4ed0e46aa9dc src/server/daemon/event_solaris.h --- a/src/server/daemon/event_solaris.h Fri Aug 16 16:59:05 2024 +0200 +++ b/src/server/daemon/event_solaris.h Fri Aug 16 18:09:05 2024 +0200 @@ -47,6 +47,11 @@ */ EventHandler base; + /* + * eventhandler thread + */ + pthread_t thr; + int port; } EventHandlerSolaris; diff -r 97039494764b -r 4ed0e46aa9dc src/server/test/event.c --- a/src/server/test/event.c Fri Aug 16 16:59:05 2024 +0200 +++ b/src/server/test/event.c Fri Aug 16 18:09:05 2024 +0200 @@ -55,8 +55,12 @@ UCX_TEST_ASSERT(ev2, "evhandler_create (2) failed"); UCX_TEST_ASSERT(ev2->numins == 4, "ev2 wrong number of instances"); - evhandler_close(ev1); - evhandler_close(ev2); + + evhandler_shutdown(ev1); + evhandler_shutdown(ev2); + + evhandler_wait_and_destroy(ev1); + evhandler_wait_and_destroy(ev2); UCX_TEST_END; } @@ -73,6 +77,20 @@ return 0; } +static void testdata_wait_for_completion(EVTest *testdata) { + time_t tstart = time(NULL); + while(!testdata->i1) { + time_t t = time(NULL); + if(t - tstart > 10) { + break; + } + + pthread_mutex_lock(&testdata->mutex); + pthread_cond_wait(&testdata->cond, &testdata->mutex); + pthread_mutex_unlock(&testdata->mutex); + } +} + UCX_TEST(test_event_send) { EventHandlerConfig cfg = { .nthreads = 1}; @@ -87,6 +105,10 @@ UCX_TEST_BEGIN; + // test sending a single event + // the event signals completion in the testdata object + // wait up to 10 seconds for completion (it should be instantly) + Event evt; ZERO(&evt, sizeof(Event)); evt.fn = test_event_send_fn; @@ -95,17 +117,7 @@ int ret = event_send(h, &evt); // wait for event finish - time_t tstart = time(NULL); - while(!testdata.i1) { - time_t t = time(NULL); - if(t - tstart > 10) { - break; - } - - pthread_mutex_lock(&testdata.mutex); - pthread_cond_wait(&testdata.cond, &testdata.mutex); - pthread_mutex_unlock(&testdata.mutex); - } + testdata_wait_for_completion(&testdata); UCX_TEST_ASSERT(!ret, "event_send failed"); UCX_TEST_ASSERT(testdata.i1, "event callback not called"); @@ -116,5 +128,92 @@ pthread_mutex_destroy(&testdata.mutex); pthread_cond_destroy(&testdata.cond); - evhandler_close(ev); + evhandler_shutdown(ev); + evhandler_wait_and_destroy(ev); +} + +#define EV_TEST_NUM_EVENTS 2000 + +static int test_event_send_multi_fn_count(EventHandler *h, Event *event) { + EVTest *test = event->cookie; + + test->i2++; + + return 0; +} + +static int test_event_send_multi_fn_end(EventHandler *h, Event *event) { + EVTest *test = event->cookie; + test->i1 = 1; + + pthread_mutex_lock(&test->mutex); + pthread_cond_signal(&test->cond); + pthread_mutex_unlock(&test->mutex); + + return 0; } + +static int test_event_send_multi_fn1(EventHandler *h, Event *event) { + EVTest *test = event->cookie; + test->i2 = 0; + + for(int i=0;ifn = test_event_send_multi_fn_count; + newevent->finish = ev_free_event; + newevent->cookie = test; + event_send(h, newevent); + } + + Event *finish_event = malloc(sizeof(Event)); + ZERO(finish_event, sizeof(Event)); + finish_event->fn = test_event_send_multi_fn_end; + finish_event->finish = ev_free_event; + finish_event->cookie = test; + event_send(h, finish_event); + + return 0; +} + +UCX_TEST(test_event_send_multi) { + EventHandlerConfig cfg = { .nthreads = 1}; + + EVHandler *ev = evhandler_create(&cfg); + EventHandler *h = ev_instance(ev); + + EVTest testdata; + ZERO(&testdata, sizeof(EVTest)); + testdata.h = h; + pthread_mutex_init(&testdata.mutex, NULL); + pthread_cond_init(&testdata.cond, NULL); + + UCX_TEST_BEGIN; + + // test sending multiple events + // the first callback test_event_send_multi_fn1 adds additional + // EV_TEST_NUM_EVENTS events to the handler + an additional + // finishing event, that notifies completion + + Event evt; + ZERO(&evt, sizeof(Event)); + evt.fn = test_event_send_multi_fn1; + evt.cookie = &testdata; + + int ret = event_send(h, &evt); + + // wait for event finish + testdata_wait_for_completion(&testdata); + + UCX_TEST_ASSERT(!ret, "event_send failed"); + UCX_TEST_ASSERT(testdata.i1, "event callback not called"); + UCX_TEST_ASSERT(testdata.i2 == EV_TEST_NUM_EVENTS, "event callback received wrong event handler pointer"); + + UCX_TEST_END; + + pthread_mutex_destroy(&testdata.mutex); + pthread_cond_destroy(&testdata.cond); + + evhandler_shutdown(ev); + evhandler_wait_and_destroy(ev); +} diff -r 97039494764b -r 4ed0e46aa9dc src/server/test/event.h --- a/src/server/test/event.h Fri Aug 16 16:59:05 2024 +0200 +++ b/src/server/test/event.h Fri Aug 16 18:09:05 2024 +0200 @@ -39,8 +39,9 @@ extern "C" { #endif +UCX_TEST(test_evhandler_create); UCX_TEST(test_event_send); -UCX_TEST(test_evhandler_create); +UCX_TEST(test_event_send_multi); #ifdef __cplusplus diff -r 97039494764b -r 4ed0e46aa9dc src/server/test/main.c --- a/src/server/test/main.c Fri Aug 16 16:59:05 2024 +0200 +++ b/src/server/test/main.c Fri Aug 16 18:09:05 2024 +0200 @@ -83,6 +83,7 @@ // event tests ucx_test_register(suite, test_evhandler_create); ucx_test_register(suite, test_event_send); + ucx_test_register(suite, test_event_send_multi); // object tests ucx_test_register(suite, test_expr_parse_expr_value);