Initial implementation

This commit is contained in:
Tristan B. Velloza Kildaire 2023-02-23 15:16:24 +02:00
commit 198c987031
5 changed files with 211 additions and 0 deletions

18
.gitignore vendored Normal file
View File

@ -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

10
dub.json Normal file
View File

@ -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"
}

172
source/libsnooze/app.d Normal file
View File

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

2
source/libsnooze/clib.c Normal file
View File

@ -0,0 +1,2 @@
#include<unistd.h>

View File

@ -0,0 +1,9 @@
module libsnooze.exceptions;
public class SnoozeError : Exception
{
this(string msg)
{
super(msg);
}
}