mirror of https://github.com/deavmi/libsnooze
Initial implementation
This commit is contained in:
commit
198c987031
|
@ -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
|
|
@ -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"
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
#include<unistd.h>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
module libsnooze.exceptions;
|
||||
|
||||
public class SnoozeError : Exception
|
||||
{
|
||||
this(string msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue