Newer
Older
// 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:
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);
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();
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);
}
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 {
Fiber* fiber = Fiber::from(mainFiber, (void*)&runtime);
runtime.scheduleFromAnywhere(*fiber);
runtime.waitUntilFinished();
return EXIT_FAILURE;
}