// SPDX-License-Identifier: LGPL-3.0-or-later // Copyright © 2020-2021 Florian Schmaus #include <atomic> // for atomic_thread_fence, memory_... #include <cstdint> // for uint64_t #include <cstdlib> // for exit, EXIT_FAILURE, EXIT_SUC... #include <iostream> // for operator<<, basic_ostream #include "Actor.hpp" // for Actor #include "CountingPrivateSemaphore.hpp" // for CPS #include "Debug.hpp" // for DBG #include "Dispatcher.hpp" // for Dispatcher #include "Fiber.hpp" // for Fiber #include "Runtime.hpp" // for Runtime #include "emper-common.h" // for UNUSED_ARG #include "emper-config.h" // // IWYU pragma: keep #include "emper.hpp" // for spawn class SumActor : public Actor<uint64_t> { private: uint64_t sum = 0; protected: void receive(uint64_t t) override { sum += t; } public: SumActor(Runtime& runtime) : Actor(runtime) {} [[nodiscard]] auto getSum() const -> uint64_t { std::atomic_thread_fence(std::memory_order_acquire); return sum; } void stop() { Actor::stop(); } }; static void mainFiber(void* runtime_ptr) { Runtime& runtime = *(Runtime*)runtime_ptr; const unsigned int FIBER_COUNT = EMPER_LOG_LEVEL > Info ? 500 : 2500; const uint64_t FIBERS_COUNT_TO = 1000; const uint64_t PER_FIBER_SUM = (FIBERS_COUNT_TO * (FIBERS_COUNT_TO + 1)) / 2; const uint64_t EXPECTED_SUM = FIBER_COUNT * PER_FIBER_SUM; SumActor sumActor(runtime); sumActor.start(); CPS cps; for (unsigned int fiberNum = 0; fiberNum < FIBER_COUNT; ++fiberNum) { spawn( [&sumActor, fiberNum] { DBG(Dispatcher::getCurrentFiber() << " (" << fiberNum << ") starts to count to " << FIBERS_COUNT_TO); for (uint64_t i = 1; i <= FIBERS_COUNT_TO; ++i) { sumActor.tell(i); } }, cps); } // Wait for the producer fibers to finish. cps.wait(); // Wait for the actor to become idle. bool actorIdle = sumActor.waitUntilIdle(60); if (!actorIdle) { std::cerr << "FAILURE: Actor did not went idle"; exit(EXIT_FAILURE); } sumActor.stop(); if (sumActor.getSum() != EXPECTED_SUM) { std::cerr << "FAILURE: Actor sum " << sumActor.getSum() << " is not equal to expected sum " << EXPECTED_SUM << std::endl; exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } auto main(UNUSED_ARG int arg, UNUSED_ARG char* argv[]) -> int { Runtime runtime; Fiber* fiber = Fiber::from(mainFiber, (void*)&runtime); runtime.scheduleFromAnywhere(*fiber); runtime.waitUntilFinished(); return EXIT_FAILURE; }