From cbe2a880f049b78ee0fac894efd3ddd8d2bd7091 Mon Sep 17 00:00:00 2001
From: Florian Fischer <florian.fl.fischer@fau.de>
Date: Thu, 19 Nov 2020 17:29:45 +0100
Subject: [PATCH] [test] add AlarmActorTest

Introduce a new Actor test using BinaryPrivateSemaphores and an Actor.
Multiple fibers are created which create a BPS on the stack, submit it to the actor
and wait on the semaphore.
The Actor simply signals each semaphore it receives.
---
 tests/AlarmActorTest.cpp | 79 ++++++++++++++++++++++++++++++++++++++++
 tests/meson.build        |  5 +++
 2 files changed, 84 insertions(+)
 create mode 100644 tests/AlarmActorTest.cpp

diff --git a/tests/AlarmActorTest.cpp b/tests/AlarmActorTest.cpp
new file mode 100644
index 00000000..e83ac8ec
--- /dev/null
+++ b/tests/AlarmActorTest.cpp
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// Copyright © 2020 Florian Fischer
+#include <cstdlib>	 // for exit, EXIT_FAILURE, EXIT_SUC...
+#include <iostream>	 // for operator<<, basic_ostream
+
+#include "Actor.hpp"										 // for Actor
+#include "BinaryPrivateSemaphore.hpp"		 // for BPS
+#include "CountingPrivateSemaphore.hpp"	 // for CPS
+#include "Fiber.hpp"										 // for Fiber
+#include "Runtime.hpp"									 // for Runtime
+#include "emper.hpp"										 // for spawn
+
+class AlarmActor : public Actor<BPS*> {
+ protected:
+	void receive(BPS* sem) override { sem->signal(); }
+
+ public:
+	AlarmActor(Runtime& runtime) : Actor(runtime) {}
+	void stop() { Actor::stop(); }
+};
+
+auto main(int argc, char* argv[]) -> int {
+	unsigned int sleeper_count = 10;
+	unsigned int sleeps = 1000;
+
+	if (argc > 3) {
+		std::cerr << "Usage: " << argv[0] << " [fiber count] [block count]" << std::endl;
+		exit(EXIT_FAILURE);
+	}
+
+	const int DECIMAL = 10;
+	if (argc > 1) {
+		sleeper_count = strtol(argv[1], nullptr, DECIMAL);
+	}
+
+	if (argc > 2) {
+		sleeps = strtol(argv[2], nullptr, DECIMAL);
+	}
+
+	Runtime runtime;
+
+	AlarmActor alarmActor(runtime);
+	alarmActor.start();
+
+	Fiber* fiber = Fiber::from([&] {
+		CPS cps;
+		for (unsigned int i = 0; i < sleeper_count; ++i) {
+			spawn(
+					[&alarmActor, &sleeps] {
+						for (unsigned int i = 1; i <= sleeps; ++i) {
+							BPS sem;
+							alarmActor.tell(&sem);
+							sem.wait();
+						}
+					},
+					cps);
+		}
+
+		// Wait for the sleeping fibers to finish
+		cps.wait();
+
+		// Wait for the actor to become idle.
+		bool actorIdle = alarmActor.waitUntilIdle(60 * 1000);
+		if (!actorIdle) {
+			std::cerr << "FAILURE: Actor did not went idle";
+			exit(EXIT_FAILURE);
+		}
+
+		alarmActor.stop();
+
+		exit(EXIT_SUCCESS);
+	});
+
+	runtime.schedule(*fiber);
+
+	runtime.waitUntilFinished();
+
+	return EXIT_FAILURE;
+}
diff --git a/tests/meson.build b/tests/meson.build
index 2ac875c0..7722aa1e 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -25,6 +25,11 @@ tests = {
 			'description': 'Simple Actor Test',
 		  },
 
+		  'AlarmActorTest.cpp':
+		  {
+			'description': 'Use an Actor to unblock fibers using BPS',
+		  },
+
 		  'SimpleLawsTest.cpp':
 		  {
 			'description': 'Simple LAWS scheduling strategy test',
-- 
GitLab