diff --git a/test/rt/nosv/CMakeLists.txt b/test/rt/nosv/CMakeLists.txt index 311a485..c45926c 100644 --- a/test/rt/nosv/CMakeLists.txt +++ b/test/rt/nosv/CMakeLists.txt @@ -12,9 +12,9 @@ if(NOT NOSV_FOUND) return() endif() -# Needed for the new nosv_attach() function. -if("${NOSV_VERSION}" VERSION_LESS "2.0.0") - message(FATAL_ERROR "nOS-V version ${NOSV_VERSION} too old, required at least 2.0.0") +# Needed for nesting nosv_init/nosv_shutdown +if("${NOSV_VERSION}" VERSION_LESS "2.1.2") + message(FATAL_ERROR "nOS-V version ${NOSV_VERSION} too old, required at least 2.1.2") endif() message(STATUS "Enabling nOS-V RT tests") @@ -39,6 +39,7 @@ endfunction() nosv_test(attach.c SORT) nosv_test(waitfor.c SORT) nosv_test(several-tasks.c SORT) +nosv_test(init-nested.c SORT) # Test multiple instrumentation levels nosv_test(several-tasks.c SORT NAME several-tasks-level-0 LEVEL 0) diff --git a/test/rt/nosv/init-nested.c b/test/rt/nosv/init-nested.c new file mode 100644 index 0000000..138396a --- /dev/null +++ b/test/rt/nosv/init-nested.c @@ -0,0 +1,121 @@ +/* Copyright (c) 2024 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +/* This test checks the correct emulation of a process that nests + * nosv_init/nosv_shutdown calls. This is a common behavior when combining + * multiple libraries that enable nosv on its own. */ + +#include +#include +#include + +#include "common.h" +#include "compat.h" +#include "ovni.h" + +static inline void +instr_thread_start(int32_t cpu, int32_t creator_tid, uint64_t tag) +{ + ovni_thread_init(get_tid()); + + struct ovni_ev ev = {0}; + + ovni_ev_set_mcv(&ev, "OHx"); + ovni_ev_set_clock(&ev, ovni_clock_now()); + ovni_payload_add(&ev, (uint8_t *) &cpu, sizeof(cpu)); + ovni_payload_add(&ev, (uint8_t *) &creator_tid, sizeof(creator_tid)); + ovni_payload_add(&ev, (uint8_t *) &tag, sizeof(tag)); + ovni_ev_emit(&ev); +} + +static inline void +instr_thread_end(void) +{ + struct ovni_ev ev = {0}; + + ovni_ev_set_mcv(&ev, "OHe"); + ovni_ev_set_clock(&ev, ovni_clock_now()); + ovni_ev_emit(&ev); + + /* Flush the events to disk before killing the thread */ + ovni_flush(); + + /* Free the thread */ + ovni_thread_free(); +} + +static void * +thread(void *arg) +{ + nosv_task_t task; + intptr_t attach = (intptr_t) arg; + + if (attach) { + instr_thread_start(-1, -1, 0); + if (nosv_attach(&task, NULL, "thread", NOSV_ATTACH_NONE) != 0) + die("nosv_attach failed"); + } + + if (nosv_init() != 0) + die("nosv_init failed: Thread %s: Call 1", + attach ? "attach" : "no-attach"); + + if (nosv_init() != 0) + die("nosv_init failed: Thread %s: Call 2", + attach ? "attach" : "no-attach"); + + + if (nosv_shutdown() != 0) + die("nosv_shutdown failed: Thread %s: Call 3", + attach ? "attach" : "no-attach"); + + if (nosv_shutdown() != 0) + die("nosv_shutdown failed: Thread %s: Call 4", + attach ? "attach" : "no-attach"); + + if (attach) { + if (nosv_detach(NOSV_DETACH_NONE) != 0) + die("nosv_detach failed"); + instr_thread_end(); + } + + return NULL; +} + +int main(void) +{ + int rc; + pthread_t pthread; + + if (nosv_init() != 0) + die("nosv_init failed: Thread main: Call 1"); + + if (nosv_init() != 0) + die("nosv_init failed: Thread main: Call 2"); + + if ((rc = pthread_create(&pthread, NULL, thread, NULL))) + die("pthread_create failed: Thread main: %s\n", strerror(rc)); + + if ((rc = pthread_join(pthread, NULL))) + die("pthread_join failed: Thread main: %s\n", strerror(rc)); + + if ((rc = pthread_create(&pthread, NULL, thread, (void *) 1))) + die("pthread_create failed: Thread main: %s\n", strerror(rc)); + + if ((rc = pthread_join(pthread, NULL))) + die("pthread_join failed: Thread main: %s\n", strerror(rc)); + + if (nosv_shutdown() != 0) + die("nosv_shutdown failed: Thread main: Call 3"); + + if (nosv_init() != 0) + die("nosv_init failed: Thread main: Call 4)"); + + if (nosv_shutdown() != 0) + die("nosv_shutdown failed: Thread main: Call 5"); + + if (nosv_shutdown() != 0) + die("nosv_shutdown failed: Thread main: Call 6"); + + return 0; +}