add test for sending multiple events to an eventhandler

Fri, 16 Aug 2024 18:09:05 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 16 Aug 2024 18:09:05 +0200
changeset 552
4ed0e46aa9dc
parent 551
97039494764b
child 553
a166a15f7b74

add test for sending multiple events to an eventhandler

src/server/daemon/event.c file | annotate | diff | comparison | revisions
src/server/daemon/event.h file | annotate | diff | comparison | revisions
src/server/daemon/event_bsd.c file | annotate | diff | comparison | revisions
src/server/daemon/event_bsd.h file | annotate | diff | comparison | revisions
src/server/daemon/event_linux.c file | annotate | diff | comparison | revisions
src/server/daemon/event_linux.h file | annotate | diff | comparison | revisions
src/server/daemon/event_solaris.c file | annotate | diff | comparison | revisions
src/server/daemon/event_solaris.h file | annotate | diff | comparison | revisions
src/server/test/event.c file | annotate | diff | comparison | revisions
src/server/test/event.h file | annotate | diff | comparison | revisions
src/server/test/main.c file | annotate | diff | comparison | revisions
--- 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;i<h->numins;i++) {
+        ev_instance_shutdown(h->instances[i]);
+    }
+}
+
 void evhandler_close(EVHandler *h) {
     for(int i=0;i<h->numins;i++) {
         ev_instance_close(h->instances[i]);
     }
-    h->numins = 0;
+}
+
+void evhandler_wait_and_destroy(EVHandler *h) {
+    for(int i=0;i<h->numins;i++) {
+        ev_instance_wait(h->instances[i]);
+    }
+    
+    free(h->instances);
+    free(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);
--- 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) {
--- 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;
 
--- 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 <errno.h>
 #include <sys/epoll.h>
 #include <sys/eventfd.h>
+#include <signal.h>
 
 #include <cx/array_list.h>
 #include <cx/linked_list.h>
@@ -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);
--- 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;
--- 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) {
--- 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;
 
--- 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;i<EV_TEST_NUM_EVENTS;i++) {
+        Event *newevent = malloc(sizeof(Event));
+        ZERO(newevent, sizeof(Event));
+        newevent->fn = 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);
+}
--- 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
--- 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);

mercurial