// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright © 2020-2021 Florian Fischer
#include <sys/eventfd.h>	// for eventfd, EFD_SEMAPHORE

#include <cerrno>		// for errno
#include <cstdint>	// for uint64_t, int32_t

#include "Common.hpp"										 // for DIE_MSG_ERRNO
#include "CountingPrivateSemaphore.hpp"	 // for CPS
#include "emper.hpp"										 // for spawn
#include "io/Future.hpp"								 // for ReadFuture, WriteFuture

using emper::io::ReadFuture;
using emper::io::WriteFuture;

void emperTest() {
	CPS cps;
	int efd = eventfd(0, EFD_SEMAPHORE);
	if (efd == -1) {
		DIE_MSG_ERRNO("eventfd failed");
	}

	uint64_t read_buf;
	ReadFuture read_future(efd, &read_buf, sizeof(read_buf), 0);

	uint64_t write_buf = 1;
	WriteFuture write_future(efd, &write_buf, sizeof(write_buf), 0);

	const int ITERATIONS = 100;

	spawn(
			[&read_future] {
				for (int i = 0; i < ITERATIONS; ++i) {
					int32_t res = read_future.submitAndWait();
					if (res < 0) {
						errno = -res;
						DIE_MSG_ERRNO("read failed");
					}

					if (i != ITERATIONS - 1) {
						// reset the BPS used to signal the completion of this future
						read_future.reset();
					}
				}
			},
			cps);

	spawn(
			[&write_future] {
				for (int i = 0; i < ITERATIONS; ++i) {
					int32_t res = write_future.submitAndWait();
					if (res < 0) {
						errno = -res;
						DIE_MSG_ERRNO("write failed");
					}

					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();
}