From 198c98703170c138b6f9aa179a8ba9b3ccad9b03 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Thu, 23 Feb 2023 15:16:24 +0200 Subject: [PATCH] Initial implementation --- .gitignore | 18 ++++ dub.json | 10 ++ source/libsnooze/app.d | 172 ++++++++++++++++++++++++++++++++++ source/libsnooze/clib.c | 2 + source/libsnooze/exceptions.d | 9 ++ 5 files changed, 211 insertions(+) create mode 100644 .gitignore create mode 100644 dub.json create mode 100644 source/libsnooze/app.d create mode 100644 source/libsnooze/clib.c create mode 100644 source/libsnooze/exceptions.d diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ce9b592 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +.dub +docs.json +__dummy.html +docs/ +/libsnooze +libsnooze.so +libsnooze.dylib +libsnooze.dll +libsnooze.a +libsnooze.lib +libsnooze-test-* +*.exe +*.pdb +*.o +*.obj +*.lst +dub.selections.json +liblibsnooze.a diff --git a/dub.json b/dub.json new file mode 100644 index 0000000..07647bf --- /dev/null +++ b/dub.json @@ -0,0 +1,10 @@ +{ + "authors": [ + "Tristan B. Velloza Kildaire" + ], + "copyright": "Copyright © 2023, Tristan B. Velloza Kildaire", + "description": "A wait/notify mechanism for D", + "license": "LGPL v3.0", + "name": "libsnooze", + "targetType": "library" +} \ No newline at end of file diff --git a/source/libsnooze/app.d b/source/libsnooze/app.d new file mode 100644 index 0000000..50a8174 --- /dev/null +++ b/source/libsnooze/app.d @@ -0,0 +1,172 @@ +module libsnooze.app; + +import libsnooze.clib : pipe, write, read; +import core.thread : Thread; +import core.sync.mutex : Mutex; +import libsnooze.exceptions : SnoozeError; + +// TODO: Remove the below import - it is only for testing +import std.stdio : writeln; + +public class Event +{ + /* Array of [readFD, writeFD] pairs/arrays */ + private int[2][Thread] pipes; + private Mutex pipesLock; + + this() + { + internalInit(); + } + + private void internalInit() + { + version(Linux) + { + // TODO: Switch to eventfd in the future + initPipe(); + } + else + { + initPipe(); + } + } + + private void initPipe() + { + /* Create a lock for the pipe-pair array */ + pipesLock = new Mutex(); + } + + /** + * Wait on this event + */ + public final void wait() + { + import core.thread; + + /* Get the thread object (TID) for the calling thread */ + Thread callingThread = Thread.getThis(); + + /* Lock the pipe-pairs */ + pipesLock.lock(); + + /* Checks if a pipe-pair exists, if not creates it */ + int[2] pipePair = pipeExistenceEnsure(callingThread); + + /* Unlock the pipe-pairs */ + pipesLock.unlock(); + + /* Get the read end and read 1 byte (blockingly) */ + int readFD = pipePair[0]; + byte singleBuff; + read(readFD, &singleBuff, 1); + + + } + + private int[2] pipeExistenceEnsure(Thread thread) + { + int[2] pipePair; + + /* Lock the pipe-pairs */ + pipesLock.lock(); + + /* If it is not in the pair, create a pipe-pair and save it */ + if(!(thread in pipes)) + { + pipes[thread] = newPipe(); //TODO: If bad (exception) + } + + /* Grab the pair */ + pipePair = pipes[thread]; + + /* Unlock the pipe-pairs */ + pipesLock.unlock(); + + return pipePair; + } + + public final void notify() + { + /* Lock the pipe-pairs */ + pipesLock.lock(); + + /* Loop through each pipe-pair */ + foreach(int[2] pipePair; pipes) + { + /* Obtain the write FD */ + int pipeWriteEnd = pipePair[1]; + + /* Write a single byte to it */ + byte wakeByte = 69; + write(pipeWriteEnd, &wakeByte, 1); // TODO: Collect status and if bad, unlock, throw exception + } + + /* Unlock the pipe-pairs */ + pipesLock.unlock(); + } + + private int[2] newPipe() + { + + + // writeln(pipes[0]); + + /* Allocate space for the two FDs */ + int[2] pipePair; + + // /* Create a new pipe and put the fd of the read end in [0] and write end in [1] */ + int status = pipe(pipePair.ptr); + + /* If the pipe creation failed */ + if(status != 0) + { + // Throw an exception is pipe creation failed + throw new SnoozeError("Could not initialize the pipe"); + } + + return pipePair; + } +} + +unittest +{ + import std.conv : to; + import core.thread : dur; + + Event event = new Event(); + + class TestThread : Thread + { + private Event event; + + this(Event event) + { + super(&worker); + this.event = event; + } + + public void worker() + { + writeln("("~to!(string)(Thread.getThis().id())~") Thread is waiting..."); + event.wait(); + writeln("("~to!(string)(Thread.getThis().id())~") Thread is waiting... [done]"); + } + } + + TestThread thread1 = new TestThread(event); + thread1.start(); + + TestThread thread2 = new TestThread(event); + thread2.start(); + + Thread.sleep(dur!("seconds")(10)); + writeln("Main thread is going to notify two threads"); + + + // TODO: Add assert to check + + /* Wake up all sleeping on this event */ + event.notify(); +} \ No newline at end of file diff --git a/source/libsnooze/clib.c b/source/libsnooze/clib.c new file mode 100644 index 0000000..d5688bb --- /dev/null +++ b/source/libsnooze/clib.c @@ -0,0 +1,2 @@ +#include + diff --git a/source/libsnooze/exceptions.d b/source/libsnooze/exceptions.d new file mode 100644 index 0000000..20b7b3e --- /dev/null +++ b/source/libsnooze/exceptions.d @@ -0,0 +1,9 @@ +module libsnooze.exceptions; + +public class SnoozeError : Exception +{ + this(string msg) + { + super(msg); + } +} \ No newline at end of file