UNIXworkcode

/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2024 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "event.h" #include "../daemon/event.h" typedef struct EVTest { EventHandler *h; pthread_mutex_t mutex; pthread_cond_t cond; void *data1; void *data2; int i1; int i2; } EVTest; UCX_TEST(test_evhandler_create) { EventHandlerConfig cfg1 = { .nthreads = 1}; EventHandlerConfig cfg4 = { .nthreads = 4}; UCX_TEST_BEGIN; EVHandler *ev1 = evhandler_create(&cfg1); UCX_TEST_ASSERT(ev1, "evhandler_create (1) failed"); UCX_TEST_ASSERT(ev1->numins == 1, "ev1 wrong number of instances"); EVHandler *ev2 = evhandler_create(&cfg4); UCX_TEST_ASSERT(ev2, "evhandler_create (2) failed"); UCX_TEST_ASSERT(ev2->numins == 4, "ev2 wrong number of instances"); evhandler_shutdown(ev1); evhandler_shutdown(ev2); evhandler_wait_and_destroy(ev1); evhandler_wait_and_destroy(ev2); UCX_TEST_END; } static int test_event_send_fn(EventHandler *h, Event *event) { EVTest *test = event->cookie; test->i1 = 1; test->i2 = h == test->h; pthread_mutex_lock(&test->mutex); pthread_cond_signal(&test->cond); pthread_mutex_unlock(&test->mutex); 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}; 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 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; 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, "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); } #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); }