diff --git a/README.md b/README.md
index c733438..a67e9c3 100644
--- a/README.md
+++ b/README.md
@@ -12,45 +12,44 @@ Eventy
### The _engine_
The first thing every Eventy-based application will need is an instance of the `Engine`.
-This provides the user with the basic event-loop functionality that eventy provides. It's
-the core of the whole framework that exists to have event-triggers ingested into its
-_queues_, checking those _queues_ and one by one dispatching each _signal handler_ that
-is associated with each queue on each item in the queue.
+This provides the user with a single object instance of the [`Engine` class]() by which
+the user can register _event types_, _signal handlers_ for said events and the ability
+to trigger or _push_ events into the engine.
The simplest way to get a new _engine_ up and running is as follow:
```d
Engine engine = new Engine();
-engine.start();
```
-This will create a new engine initializing all of its internals and then start it as well.
+This will create a new engine initializing all of its internals such that it is ready for
+use.
-### Queues
+### Event types
-_Queues_ are as they sound, a list containing items. Each queue has a unique ID which we
-can choose. The items of each queue will be the _events_ that are pushed into the _engine_.
-An _event_ has an ID associated with it which tells the _engine_ which queue it must be
-added to!
+_Event types_ are effectively just numbers. The use of these is to be able to connect events
+pushed into the engine with their respective signal handlers (which are registered to handle
+one or more event types).
-Let's create two queues, with IDs `1` and `2`:
+Let's create two event types, with IDs `1` and `2`:
```d
-engine.addQueue(1);
-engine.addQueue(2);
+engine.addEventType(new EventType(1));
+engine.addEventType(new EventType(2));
```
-This will tell the engine to create two new queues with tags `1` and `2` respectively.
+This will tell the engine to create two new event types with tags `1` and `2` respectively.
-### Event handlers
+### Signal handlers
-We're almost done. So far we have created a new _engine_ for handling our queues and
-the triggering of events. What is missing is something to _handle those queues_ when
-they have something added to them, we call this an _"event handler"_ in computer science
-but this is Eventy, and in Eventy this is known as a `Signal`.
+We're almost done. So far we have created a new _engine_ for handling our event tyoes and
+the triggering of events. What is missing is something to _handle those event types_ when
+an event of one of those types is pushed into the engine. Such handlers are referred to as
+_signal handlers_ and in Eventy these are instances of the [`Signal` class]().
-We're going to create a signal that can handle both the queues and perform the same task
-for both of them. We do this by creating a class that inherits from the `Signal` base type:
+We're going to create a signal that can handle both of the event types `1` and `2` that we
+registered earlier on. We can do this by creating a class that inherits from the `Signal`
+base class:
```d
class SignalHandler1 : Signal
@@ -63,15 +62,15 @@ class SignalHandler1 : Signal
public override void handler(Event e)
{
import std.stdio;
- writeln("Running event", e.id);
+ writeln("Running event", e.getID());
}
}
```
We need to tell the `Signal` class two things:
-1. What _queue IDs_ it will handle
-2. What to _run_ for said queues
+1. What _event typess_ it will handle
+2. What to _run_ for said event types
---
@@ -92,7 +91,7 @@ two IDs, namely `1` and `2`.
As for _what to run_, that is specified by overriding the `void handler(Event)` method
in the `Signal` class. In our case we make it write to the console the ID of the event
(which would end up either being `1` or `2` seeing as this handler is only registered
-for those queue IDs).
+for those event types).
```d
import std.stdio;
@@ -120,8 +119,6 @@ engine.push(eTest);
eTest = new Event(2);
engine.push(eTest);
-
-
```
You will then see something like this:
@@ -138,6 +135,20 @@ Running event1
Running event2
```
-The reason is it depends on which process gets shceduled by the Linux kernel first, this
-is because new threads (special types of processes) are spanwed on the dispatch of each
-event.
+Despite us pushing the events into the engine in the order of `1` and _then_ `2`, the
+scheduling of such threads is up to the Linux kernel and hence one could be run before
+the other.
+
+---
+
+## Release notes
+
+### `v0.4.0`
+
+```
+Completely overhauled Eventy system for the v0.4.0 release
+
+Removed the event-loop for a better system (for now) whereby we just dispatch signal handlers on the call to `push(Event)`.
+
+In a future release I hope to bring the event loop back but in a signal-based manner, such that we can support deferred events and priorities and such
+```
\ No newline at end of file
diff --git a/source/eventy/engine.d b/source/eventy/engine.d
index 6a5c5c6..cf29e08 100644
--- a/source/eventy/engine.d
+++ b/source/eventy/engine.d
@@ -1,6 +1,6 @@
module eventy.engine;
-import eventy.queues : Queue;
+import eventy.types : EventType;
import eventy.signal : Signal;
import eventy.event : Event;
import eventy.config;
@@ -9,20 +9,20 @@ import eventy.exceptions;
import std.container.dlist;
import core.sync.mutex : Mutex;
import core.thread : Thread, dur, Duration;
+import std.conv : to;
unittest
{
import std.stdio;
Engine engine = new Engine();
- engine.start();
/**
* Let the event engine know what typeIDs are
* allowed to be queued
*/
- engine.addQueue(1);
- engine.addQueue(2);
+ engine.addEventType(new EventType(1));
+ engine.addEventType(new EventType(2));
/**
* Create a new Signal Handler that will handles
@@ -38,7 +38,7 @@ unittest
public override void handler(Event e)
{
- writeln("Running event", e.id);
+ writeln("Running event", e.getID());
}
}
@@ -60,7 +60,7 @@ unittest
writeln("done with main thread code");
- while(engine.hasPendingEvents()) {}
+ while(engine.hasEventsRunning()) {}
/* TODO: Before shutting down, actually test it out (i.e. all events ran) */
engine.shutdown();
@@ -72,14 +72,13 @@ unittest
EngineSettings customSettings = {holdOffMode: HoldOffMode.YIELD};
Engine engine = new Engine(customSettings);
- engine.start();
/**
* Let the event engine know what typeIDs are
* allowed to be queued
*/
- engine.addQueue(1);
- engine.addQueue(2);
+ engine.addEventType(new EventType(1));
+ engine.addEventType(new EventType(2));
/**
* Create a new Signal Handler that will handles
@@ -95,7 +94,7 @@ unittest
public override void handler(Event e)
{
- writeln("Running event", e.id);
+ writeln("Running event", e.getID());
}
}
@@ -117,7 +116,7 @@ unittest
writeln("done with main thread code");
- while(engine.hasPendingEvents()) {}
+ while(engine.hasEventsRunning()) {}
/* TODO: Before shutting down, actually test it out (i.e. all events ran) */
engine.shutdown();
@@ -133,14 +132,12 @@ unittest
* handlers, add signal handlers, among many
* other things
*/
-public final class Engine : Thread
+public final class Engine
{
- /* TODO: Or use a queue data structure */
/* Registered queues */
- private DList!(Queue) queues;
- private Mutex queueLock;
+ private DList!(EventType) eventTypes;
+ private Mutex eventTypesLock;
- /* TODO: Or use a queue data structure */
/* Registered signal handlers */
private DList!(Signal) handlers;
private Mutex handlerLock;
@@ -164,9 +161,7 @@ public final class Engine : Thread
*/
this(EngineSettings settings)
{
- super(&run);
-
- queueLock = new Mutex();
+ eventTypesLock = new Mutex();
handlerLock = new Mutex();
threadStoreLock = new Mutex();
@@ -238,74 +233,6 @@ public final class Engine : Thread
handlerLock.unlock();
}
- /**
- * The main event loop
- *
- * This checks at a certain interval (see HoldOffMode) if
- * there are any events in any of the queues, if so,
- * the dispatcher for said event type is called
- */
- private void run()
- {
- running = true;
-
- while (running)
- {
- /**
- * Lock the queue-set
- *
- * TODO: Maybe add sleep support here too?
- */
- while (!queueLock.tryLock_nothrow())
- {
- // Don't waste time spinning on mutex, yield if failed
- if(!settings.agressiveTryLock)
- {
- yield();
- }
- }
-
- foreach (Queue queue; queues)
- {
- /* If the queue has evenets queued */
- if (queue.hasEvents())
- {
- /* TODO: Add different dequeuing techniques */
-
- /* Pop the first Event */
- Event headEvent = queue.popEvent();
-
- /* Get all signal-handlers for this event type */
- Signal[] handlersMatched = getSignalsForEvent(headEvent);
-
- /* Dispatch the signal handlers */
- dispatch(handlersMatched, headEvent);
-
- }
- }
-
- /* Unlock the queue set */
- queueLock.unlock();
-
- /* Activate hold off (dependening on the type) */
- if(settings.holdOffMode == HoldOffMode.YIELD)
- {
- /* Yield to stop mutex starvation */
- yield();
- }
- else if(settings.holdOffMode == HoldOffMode.SLEEP)
- {
- /* Sleep the thread (for given time) to stop mutex starvation */
- sleep(settings.sleepTime);
- }
- else
- {
- /* This should never happen */
- assert(false);
- }
- }
- }
-
/**
* Shuts down the event engine
*/
@@ -319,11 +246,8 @@ public final class Engine : Thread
/* Wait for any pendings events (if configured) */
if(settings.gracefulShutdown)
{
- while(hasPendingEvents()) {}
+ while(hasEventsRunning()) {}
}
-
- /* Stop the loop */
- running = false;
}
/**
@@ -335,12 +259,9 @@ public final class Engine : Thread
*/
private void dispatch(Signal[] signalSet, Event e)
{
- /* TODO: Add ability to dispatch on this thread */
-
foreach (Signal signal; signalSet)
{
/* Create a new Thread */
- // Thread handlerThread = getThread(signal, e);
DispatchWrapper handlerThread = new DispatchWrapper(signal, e);
/**
@@ -407,6 +328,29 @@ public final class Engine : Thread
threadStoreLock.unlock();
}
+ /**
+ * Checks whether or not there are still events
+ * running at the time of calling
+ *
+ * Returns: true
if there are events
+ * still running, false
otherwise
+ */
+ public bool hasEventsRunning()
+ {
+ /* Whether there are events running or not */
+ bool has = false;
+
+ /* Lock the thread store */
+ threadStoreLock.lock();
+
+ has = !threadStore.empty();
+
+ /* Unlock the thread store */
+ threadStoreLock.unlock();
+
+ return has;
+ }
+
/**
* DispatchWrapper
*
@@ -455,7 +399,7 @@ public final class Engine : Thread
/* Find all handlers matching */
foreach (Signal signal; handlers)
{
- if (signal.handles(e.id))
+ if (signal.handles(e.getID()))
{
matchedHandlers ~= signal;
}
@@ -473,7 +417,8 @@ public final class Engine : Thread
*
* Params:
* id = the event ID to check
- * Returns:
+ * Returns: true
if a signal handler does
+ * exist, false
otherwise
*/
public bool isSignalExists(ulong id)
{
@@ -489,78 +434,100 @@ public final class Engine : Thread
*/
public void push(Event e)
{
- Queue matchedQueue = findQueue(e.id);
+ //TODO: New code goes below here
+ /**
+ * What we want to do here is to effectively
+ * wake up a checker thread and also (before that)
+ * perhaps we say what queue was modified
+ *
+ * THEN the checker thread goes to said queue and
+ * executes said event (dispatches it) and then sleep
+ * again till it is interrupted. We need Pids and kill etc for this
+ *
+ * Idea (2)
+ *
+ * If we cannot do a checker thread then we can spwan a thread here
+ * but then we get no control for priorities etc, although actually we could
+ * maybe? It depends, we don't want multiple dispathers at same time then
+ * (A checker thread would ensure we don't get this)
+ */
- if (matchedQueue)
+ /* Obtain all signal handlers for the given event */
+ Signal[] handlersMatched = getSignalsForEvent(e);
+
+ /* If we get signal handlers then dispatch them */
+ if(handlersMatched.length)
{
- /* Append to the queue */
- matchedQueue.add(e);
+ dispatch(handlersMatched, e);
+ }
+ /* If there are no matching events */
+ else
+ {
+ //TODO: Add default handler support
+ //TODO: Add error throwing in case where not true
}
}
/**
- * Creates a new queue with the given id
+ * Registers a new EventType with the engine
* and then adds it.
*
- * Throws EventyException if the id is already
- * in use by another queue
+ * Throws EventyException if the id of the given
+ * EventType is is already in use by another
*
* Params:
- * id = the id of the neq eueue to create
+ * id = the id of the new event type to add
* Throws: EventyException
*/
- public void addQueue(ulong id)
+ public void addEventType(EventType evType)
{
- /* Create a new queue with the given id */
- Queue newQueue = new Queue(id);
-
- /* Lock the queue collection */
- queueLock.lock();
+ /* Lock the event types list */
+ eventTypesLock.lock();
/* If no such queue exists then add it (recursive mutex used) */
- if (!findQueue(id))
+ if (!findEventType(evType.getID()))
{
- /* Add the queue */
- queues ~= newQueue;
+ /* Add the event types list */
+ eventTypes ~= evType;
}
else
{
- throw new EventyException("Failure to add queue with ID already in use");
+ throw new EventyException("Failure to add EventType with id '"~to!(string)(evType.getID())~"\' as it is already in use");
}
- /* Unlock the queue collection */
- queueLock.unlock();
+ /* Unlock the event types list */
+ eventTypesLock.unlock();
}
/**
- * Given an if, this will return the Queue
+ * Given an if, this will return the EventType
* associated with said id
*
* Params:
- * id = the id of the Queue
- * Returns: The Queue if found, otherwise
+ * id = the id of the EventType
+ * Returns: The EventType if found, otherwise
* null
*/
- public Queue findQueue(ulong id)
+ public EventType findEventType(ulong id)
{
- /* Lock the queue collection */
- queueLock.lock();
+ /* Lock the EventType list */
+ eventTypesLock.lock();
- /* Find the matching queue */
- Queue matchedQueue;
- foreach (Queue queue; queues)
+ /* Find the matching EventType */
+ EventType matchedEventType;
+ foreach (EventType eventType; eventTypes)
{
- if (queue.id == id)
+ if (eventType.getID() == id)
{
- matchedQueue = queue;
+ matchedEventType = eventType;
break;
}
}
- /* Unlock the queue collection */
- queueLock.unlock();
+ /* Unlock the EventType list */
+ eventTypesLock.unlock();
- return matchedQueue;
+ return matchedEventType;
}
/* TODO: Add coumentation */
@@ -569,34 +536,4 @@ public final class Engine : Thread
/* TODO: Implement me */
return null;
}
-
-
- /**
- * Checks if any of the queues in the event engine
- * have any pending events in them waiting dispatch
- *
- * Returns: true
if there are pending events,
- * false
otherwise
- */
- public bool hasPendingEvents()
- {
- bool isPending = false;
-
- /* Lock the queues */
- queueLock.lock();
-
- foreach (Queue queue; queues)
- {
- if (queue.hasEvents())
- {
- isPending = true;
- break;
- }
- }
-
- /* Unlock the queues */
- queueLock.unlock();
-
- return isPending;
- }
}
\ No newline at end of file
diff --git a/source/eventy/event.d b/source/eventy/event.d
index 4f8781c..e3f1f88 100644
--- a/source/eventy/event.d
+++ b/source/eventy/event.d
@@ -5,23 +5,30 @@ module eventy.event;
*
* An Event represents a trigger for a given signal(s)
* handlers which associate with the given typeID
- *
- * It can optionally take a payload with it as well
*/
public class Event
{
- /**
- * Creates a new Event, optionally taking with is a
- * payload
- */
- this(ulong typeID, ubyte[] payload = null)
+ /* The event's type id */
+ private ulong id;
+
+ /**
+ * Creates a new Event with the given typeID
+ *
+ * Params:
+ * typeID = the new Event's type ID
+ */
+ this(ulong typeID)
{
this.id = typeID;
- this.payload = payload;
}
- ulong id;
- ubyte[] payload;
-
- // TODO: Remove the requirement for the payload
+ /**
+ * Returns the type ID of this Event
+ *
+ * Returns: The Event's type ID
+ */
+ public final ulong getID()
+ {
+ return id;
+ }
}
diff --git a/source/eventy/package.d b/source/eventy/package.d
index d11f790..c5d0926 100644
--- a/source/eventy/package.d
+++ b/source/eventy/package.d
@@ -3,6 +3,6 @@ module eventy;
public import eventy.event;
public import eventy.exceptions;
public import eventy.engine;
-public import eventy.queues;
+public import eventy.types;
public import eventy.signal;
public import eventy.config;
\ No newline at end of file
diff --git a/source/eventy/queues.d b/source/eventy/queues.d
deleted file mode 100644
index de72426..0000000
--- a/source/eventy/queues.d
+++ /dev/null
@@ -1,75 +0,0 @@
-module eventy.queues;
-
-import eventy.event : Event;
-import core.sync.mutex : Mutex;
-import std.container.dlist;
-import std.range;
-
-/**
-* Queue
-*
-* Represents a queue with a given ID that can
-* have Event-s enqueued to it
-*/
-public final class Queue
-{
- public ulong id;
- /* TODO: Add queue of Event's here */
-
- private DList!(Event) queue;
- private Mutex queueLock;
-
-
- this(ulong id)
- {
- this.id = id;
- queueLock = new Mutex();
- }
-
- public DList!(Event).Range getKak()
- {
- return queue[];
- }
-
- public void add(Event e)
- {
- /* Lock the queue */
- queueLock.lock();
-
- queue.insert(e);
-
- /* Unlock the queue */
- queueLock.unlock();
- }
-
- public bool hasEvents()
- {
- bool has;
-
- /* Lock the queue */
- queueLock.lock();
-
- has = !(queue[]).empty();
-
- /* Unlock the queue */
- queueLock.unlock();
-
- return has;
- }
-
- public Event popEvent()
- {
- Event poppedEvent;
-
- /* Lock the queue */
- queueLock.lock();
-
- poppedEvent = (queue[]).front();
- queue.removeFront();
-
- /* Unlock the queue */
- queueLock.unlock();
-
- return poppedEvent;
- }
-}
\ No newline at end of file
diff --git a/source/eventy/types.d b/source/eventy/types.d
new file mode 100644
index 0000000..e35a620
--- /dev/null
+++ b/source/eventy/types.d
@@ -0,0 +1,40 @@
+module eventy.types;
+
+import eventy.event : Event;
+import core.sync.mutex : Mutex;
+import std.container.dlist;
+import std.range;
+
+/**
+* EventType
+*
+* Represents a type of event. Every Event has an EventType
+* and Signal(s)-handlers register to one or more of these
+* types to handle
+*/
+public final class EventType
+{
+ /* The EventType's ID */
+ private ulong id;
+
+ /**
+ * Instantiates a new EventType with the given id
+ *
+ * Params:
+ * id = The EventType's id
+ */
+ this(ulong id)
+ {
+ this.id = id;
+ }
+
+ /**
+ * Returns the id of this EventType
+ *
+ * Returns: The id of this EventType
+ */
+ public ulong getID()
+ {
+ return id;
+ }
+}
\ No newline at end of file