diff --git a/emper/Actor.hpp b/emper/Actor.hpp index 2a7bf281a3561903d42907aeaf30491e7b2a34f9..4065ee2c8ff74916ede9e851126249424d8f1431 100644 --- a/emper/Actor.hpp +++ b/emper/Actor.hpp @@ -57,7 +57,7 @@ class Actor { void stop() { setState(Stopped); } public: - virtual ~Actor() = default; + virtual ~Actor() { stop(); } template <CallerEnvironment callerEnvironment = CallerEnvironment::EMPER> void start() { diff --git a/emper/Runtime.cpp b/emper/Runtime.cpp index af097e0f731dace5057d76f7ebd74e324f1db72b..51f87515a17395e18036695431d19478804af675 100644 --- a/emper/Runtime.cpp +++ b/emper/Runtime.cpp @@ -67,6 +67,7 @@ using emper::io::IoContext; Runtime::Runtime(workerid_t workerCount, RuntimeStrategyFactory& strategyFactory, unsigned int seed) : workerCount(workerCount), workerLatch(workerCount), + workerThreadExitLatch(workerCount), strategy(strategyFactory.constructRuntimeStrategy(*this)), scheduler(strategy->getScheduler()), dispatcher(strategy->getDispatcher()), @@ -229,6 +230,12 @@ auto Runtime::workerLoop(Worker* worker) -> void* { // Threads return here if Context::switchToOriginalStack() is called. + // Ensure that all worker threads exit "at the same" time. Otherwise + // it would be possible that one thread is work-stealing, + // potentially accessing a work stealing queue of an worker thread + // that already exited, causing an invalid access. + workerThreadExitLatch.count_down_and_wait(); + return nullptr; } diff --git a/emper/Runtime.hpp b/emper/Runtime.hpp index 24a8c52adc5126119cba00adf683a926f12e862e..621eda413c7a46cd1121d1845b6e25646b873ecf 100644 --- a/emper/Runtime.hpp +++ b/emper/Runtime.hpp @@ -51,6 +51,7 @@ class Runtime : public Logger<LogSubsystem::RUNTI> { std::vector<std::function<void(workerid_t)>> newWorkerHooks; Latch workerLatch; + Latch workerThreadExitLatch; RuntimeStrategy* const strategy; Scheduler& scheduler; diff --git a/tests/AlarmFutureTest.cpp b/tests/AlarmFutureTest.cpp index b14830a48c871b63470181f5b8c21e544e8c4267..7ff4e6f278b658633c37784b1129ceb56616ad19 100644 --- a/tests/AlarmFutureTest.cpp +++ b/tests/AlarmFutureTest.cpp @@ -4,7 +4,6 @@ #include <cerrno> // for ETIME #include <chrono> // for microseconds, duration_cast, operator- #include <cstdint> // for int32_t -#include <cstdlib> // for exit, EXIT_SUCCESS #include "emper-config.h" #include "io/Future.hpp" // for AlarmFuture @@ -28,6 +27,4 @@ void emperTest() { assert(std::chrono::duration_cast<std::chrono::microseconds>(end - start) >= std::chrono::seconds(1)); - - exit(EXIT_SUCCESS); } diff --git a/tests/CancelFutureTest.cpp b/tests/CancelFutureTest.cpp index 21eaa79fa71d56267be77fe6a907a1fa5f6e5809..0ff9b09f38367b7a8b37a2ebd9662472847fb371 100644 --- a/tests/CancelFutureTest.cpp +++ b/tests/CancelFutureTest.cpp @@ -5,7 +5,6 @@ #include <cassert> // for assert #include <cerrno> // for ECANCELED, ETIME #include <cstdint> // for uint64_t, int32_t -#include <cstdlib> // for exit, EXIT_SUCCESS #include "Common.hpp" // for DIE_MSG_ERRNO #include "io/Future.hpp" // for ReadFuture, WriteFuture @@ -57,6 +56,4 @@ void emperTest() { int r = readFuture2.cancel(); assert(r == -EINTR || r == -ECANCELED); assert(readFuture.wait() == sizeof(write_buf) && read_buf == write_buf); - - exit(EXIT_SUCCESS); } diff --git a/tests/IncrementalCompletionTest.cpp b/tests/IncrementalCompletionTest.cpp index 229ce1783c013b0ba8b63e31fc8e3c017da3fd61..0f102fd63230f127e388e008ba55e6e420bdf593 100644 --- a/tests/IncrementalCompletionTest.cpp +++ b/tests/IncrementalCompletionTest.cpp @@ -48,6 +48,4 @@ void emperTest() { delete[] memOut; delete[] memIn; - - exit(EXIT_SUCCESS); } diff --git a/tests/LinkFutureTest.cpp b/tests/LinkFutureTest.cpp index b9859ec5c4bc132641058518cca02e62b1633e91..f0f2d04df8fe8a2b69d509715bc881d901145ea8 100644 --- a/tests/LinkFutureTest.cpp +++ b/tests/LinkFutureTest.cpp @@ -8,7 +8,6 @@ #include <cassert> // for assert #include <cerrno> // for EBADF, ECANCELED #include <cstdint> // for uint64_t, int32_t -#include <cstdlib> // for exit, EXIT_SUCCESS #include "Common.hpp" // for DIE_MSG_ERRNO, DIE_MSG #include "io.hpp" @@ -126,6 +125,4 @@ void emperTest() { successLoop(); failureChainInvCor(); failureChainCorInvCor(); - - exit(EXIT_SUCCESS); } diff --git a/tests/ReuseBpsTest.cpp b/tests/ReuseBpsTest.cpp index 82d8a06aea05509f2d38fd21780b2f090fb3c1a9..7eddfb9174917198c06e6b66c6a0608ccb8139b2 100644 --- a/tests/ReuseBpsTest.cpp +++ b/tests/ReuseBpsTest.cpp @@ -1,7 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright © 2020 Florian Schmaus -#include <cstdlib> // for exit, EXIT_SUC... - +// Copyright © 2020-2021 Florian Schmaus #include "BinaryPrivateSemaphore.hpp" // for BPS #include "CountingPrivateSemaphore.hpp" // for CPS #include "emper.hpp" // for spawn @@ -34,6 +32,4 @@ void emperTest() { // Wait for the fibers to finish. cps.wait(); - - exit(EXIT_SUCCESS); } diff --git a/tests/ReuseFutureTest.cpp b/tests/ReuseFutureTest.cpp index 7bc930c8885ee7872a2f323fa60a23a3b4bd9472..f08dccf0a69a598fa30bcaca8fd8831cc9dc7d99 100644 --- a/tests/ReuseFutureTest.cpp +++ b/tests/ReuseFutureTest.cpp @@ -4,7 +4,6 @@ #include <cerrno> // for errno #include <cstdint> // for uint64_t, int32_t -#include <cstdlib> // for exit, EXIT_SUCCESS #include "Common.hpp" // for DIE_MSG_ERRNO #include "CountingPrivateSemaphore.hpp" // for CPS @@ -38,8 +37,10 @@ void emperTest() { DIE_MSG_ERRNO("read failed"); } - // reset the BPS used to signal the completion of this future - read_future.reset(); + if (i != ITERATIONS - 1) { + // reset the BPS used to signal the completion of this future + read_future.reset(); + } } }, cps); @@ -53,14 +54,14 @@ void emperTest() { DIE_MSG_ERRNO("write failed"); } - // reset the BPS used to signal the completion of this future - write_future.reset(); + if (i != ITERATIONS - 1) { + // reset the BPS used to signal the completion of this future + write_future.reset(); + } } }, cps); // Wait for the fibers to finish. cps.wait(); - - exit(EXIT_SUCCESS); } diff --git a/tests/TellActorFromAnywhereTest.cpp b/tests/TellActorFromAnywhereTest.cpp index 70800ac153e3fa9fce342659631138f7a75d805c..3e63f1f1a4b9c49d41d6bb11a5c00d093886bfcb 100644 --- a/tests/TellActorFromAnywhereTest.cpp +++ b/tests/TellActorFromAnywhereTest.cpp @@ -18,14 +18,16 @@ class SignallingActor : public Actor<unsigned int> { }; void emperTest() { - BinaryPrivateSemaphore bps; - SignallingActor signallingActor(bps); - signallingActor.start(); + // Heap allocate the Actor and the BPS until we have a way to + // cleanly terminate the Actor. + auto* bps = new BinaryPrivateSemaphore(); + auto* signallingActor = new SignallingActor(*bps); + signallingActor->start(); // TODO: Use std::jthread once EMPER uses C++20. - std::thread signallingThread([&] { signallingActor.tellFromAnywhere(1); }); + std::thread signallingThread([&] { signallingActor->tellFromAnywhere(1); }); - bps.wait(); + bps->wait(); // TODO: Remove this once we use std::jthread when EMPER uses C++20. signallingThread.join(); diff --git a/tests/TimeoutWrapperTest.cpp b/tests/TimeoutWrapperTest.cpp index 8211b3766d8ccac16d1c4c632395e5cf91d39e81..ef7e3b36eda94e864ace3c20ac47d4935dce47ea 100644 --- a/tests/TimeoutWrapperTest.cpp +++ b/tests/TimeoutWrapperTest.cpp @@ -5,7 +5,6 @@ #include <cassert> // for assert #include <cerrno> // for ECANCELED, ETIME #include <cstdint> // for uint64_t, int32_t -#include <cstdlib> // for exit, EXIT_SUCCESS #include "Common.hpp" // for DIE_MSG_ERRNO #include "io/Future.hpp" // for ReadFuture, TimeoutWrapper @@ -30,6 +29,4 @@ void emperTest() { res = readFuture.wait(); assert(res == -ECANCELED); - - exit(EXIT_SUCCESS); } diff --git a/tests/TooLongFutureChain.cpp b/tests/TooLongFutureChain.cpp index 8f861e0a6cb0d82c7754ea2f9ea8930f7844f5db..7a1bb3ea49a6e3b3e38d2c641f536751025fee1e 100644 --- a/tests/TooLongFutureChain.cpp +++ b/tests/TooLongFutureChain.cpp @@ -23,5 +23,4 @@ void emperTest() { } futures[links - 1]->submitAndWait(); - exit(EXIT_SUCCESS); } diff --git a/tests/YieldToAnywhereTest.cpp b/tests/YieldToAnywhereTest.cpp index ee0fb8ef89552e30b4119c41e0017e25494e0a47..e9248ca166f338e110694278a83eb3a25e71d8b5 100644 --- a/tests/YieldToAnywhereTest.cpp +++ b/tests/YieldToAnywhereTest.cpp @@ -1,7 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright © 2020 Florian Schmaus -#include <cstdlib> - +// Copyright © 2020-2021 Florian Schmaus #include "CountingPrivateSemaphore.hpp" #include "emper.hpp" @@ -18,5 +16,4 @@ void emperTest() { cps); } cps.wait(); - exit(EXIT_SUCCESS); } diff --git a/tests/test-runner/test-runner.cpp b/tests/test-runner/test-runner.cpp index b78c7615eeda81ebc88ab6b7e81967cd02de896f..ca3b1d64628764806fa95c915e4ea31980131ec7 100644 --- a/tests/test-runner/test-runner.cpp +++ b/tests/test-runner/test-runner.cpp @@ -7,11 +7,12 @@ #include "Fiber.hpp" #include "Runtime.hpp" +#include "lib/sync/Semaphore.hpp" -void invokeTest() { +static void invokeTest(emper::lib::sync::Semaphore* successSem) { emperTest(); - exit(EXIT_SUCCESS); + successSem->notify(); } auto testMain() -> int { @@ -21,12 +22,13 @@ auto testMain() -> int { } Runtime runtime; + emper::lib::sync::Semaphore successSem; - Fiber* alphaFiber = Fiber::from(&invokeTest); + Fiber* alphaFiber = Fiber::from([&successSem] { invokeTest(&successSem); }); runtime.scheduleFromAnywhere(*alphaFiber); - runtime.waitUntilFinished(); + successSem.wait(); - return EXIT_FAILURE; + return EXIT_SUCCESS; } diff --git a/tests/test-runner/test-runner.hpp b/tests/test-runner/test-runner.hpp index 3819bafcee771741d98fbaafd14fbaa160658cc8..a871918c09ab756bbb87bdf1ba652f513823884b 100644 --- a/tests/test-runner/test-runner.hpp +++ b/tests/test-runner/test-runner.hpp @@ -3,6 +3,4 @@ #pragma once void emperTest() __attribute__((weak)); -void invokeTest(); - auto testMain() -> int;