deeds
1.1.1Deeds Extensible Event Delivery System
Table of Contents
About Deeds
Deeds is an Extensible Event Delivery System. It allows for efficient event delivery to multiple handlers with a complex event filtering system.
There are three main components to this system: events, loops, and handlers. Events are certain kinds of messages or data payloads that are to be sent out and processed by other parts in the system. Loops handle the distribution of the events, and handlers then finally do the processing of an event.
There can be multiple independent loops in any application and handlers can be registered on any number of loops simultaneously. However, each event should only be sent out once and only on one loop. If it is necessary to issue an event multiple times or onto multiple loops, it needs to be copied.
The distribution to handlers from the loop follows a strict ordering scheme that is specified on the handlers. Each handler can dictate a list of before
and after
elements that precisely lay out their position in the issuing sequence. Additionally, handlers can specify a filter and event class that limit the type and kind of events that it will receive.
The loop compiles an efficient, tailored function to issue events to handlers and perform the filtering. This means that even with a significant amount of handlers, issuing an event is still going to be very fast.
Finally there are different types of handlers to give the user more control over the context in which the event handling happens and whether the loop should be blocked during the handler's execution.
How To
Load Deeds through Quicklisp or ASDF:
(ql:quickload :deeds)
By default the system will set up and launch a standard event loop on *standard-event-loop*
. You can then add handlers by using define-handler
:
(deeds:define-handler (info-handler deeds:info-event) (event message)
(format T "~&INFO: ~a~%" message))
(deeds:define-handler (smiling-handler deeds:info-event) (event message)
:filter '(search ":)" message)
(format T "~&YAY: ~a~%" message))
Now let's issue some events and see what happens:
(deeds:do-issue deeds:info-event :message "Hello!")
(deeds:do-issue deeds:info-event :message "Hey there :)")
(deeds:do-issue deeds:warning-event :message "Help! It's burning!")
By default events have fields for the issue-time, the origin, and whether they've been cancelled. So let's play around with that.
(deeds:define-handler (simple-handler deeds:event) (event)
(format T "~&Found event: ~a~%" event))
(deeds:define-handler (pre-handler deeds:event) (event)
:before '(:main)
:class 'deeds:locally-blocking-handler
(deeds:cancel event)
(format T "~&Cancelling!~%"))
The first handler simply prints everything it finds. The second one is special in two ways: first it orders itself before every other normal handler by ordering itself before the main category. Second, it uses a different handler class. The default class is the queued-handler
which uses a singular queue in a different thread to process events. This handler on the other hand will not use any threads and instead run directly in the event loop, thus locally blocking it until the handler is done. This allows us to make sure that the event gets cancelled before it reaches anything else:
(deeds:do-issue deeds:event)
As you can see, only the pre-handler is called. If you want to try it out, remove the cancel
call and recompile the pre-handler. Then the event should reach both handlers again. Alternatively you can add the :handle-cancelled T
option to the simple-handler to override the default behaviour.
Internals
This section documents how the particular standard implementation of the various components works. Some to all of this can be changed by subclassing the existing implementations and overriding the behaviour to suit your needs.
Events
In order to allow for any form of optimisation on the event filtering in the event loop, we need to enforce restrictions on what can happen to an event. The most straightforward restriction is to require immutability of the event slots. However, in some cases it is very much desirable to be able to mutate the slots -- as an example if you'd like to filter the text in a message event. As such, the most appropriate solution is to allow manual overriding of the immutability on a per-slot basis. To achieve this, a custom metaclass event-class
along with custom slot classes event-direct-slot-definition
event-effective-slot-definition
have been created that tend to this behaviour.
The slot classes have an additional field accessible through event-slot-mutable
and specifiable through :mutable
, which dictates whether the slot is mutable or not. If it is immutable but a writer has been specified on the slot anyway, an immutable-event-slot-has-writer
warning is signalled upon class initialisation to warn the user of potentially dangerous behaviour. Similarly, if an attempt is made to actually perform a modification on an immutable slot during any time but the event
's initialize-instance
time, a continuable error of type immutable-event-slot-modified
is signalled. This way it is still possible to perform modifications on immutable slots if absolutely necessary, while the accidental case is prevented.
In order to make defining events easier, a simple wrapper around defclass
is provided called define-event
. A bunch of standard events are supplied to make the most common event actions easier: message-event
, info-event
, warning-event
, error-event
, payload-event
, sequence-event
, chunked-payload-event
, identified-event
, stream-event
, stream-begin-event
, stream-payload-event
, and stream-end-event
.
Handlers
The primary distinguishing feature of a handler is the question of how it actually invokes the delivery function when an event is issue
d to the handler from a loop. The most primitive behaviour is to simply call the function directly. This is implemented by the locally-blocking-handler
, which in effect will block the issuing loop, but may still be invoked in parallel if multiple loops are involved. The next idea is to spawn a new thread for each event that is issued. This behaviour is implemented by the parallel-handler
. However, spawning lots of threads will quickly lead to situations where the threads interleave, and as such it is important that the delivery function takes care to lock and synchronise, which can be taxing on the user. Thus the next idea is to queue events and handle them in a separate thread. This avoids most contention and thrashing issues while still getting the benefit of unblocking the loop. This behaviour is implemented by the queued-handler
. Finally there is a variant of the locally-blocking-handler
that blocks all loops that have issued an event until their respective event is done. This is implemented by the globally-blocking-handler
.
Potentially much more complicated schemes that act differently depending on the issuing loop or the event to be processed could be conceived, but such things are too tied to the actual use-case at hand, and as such are left up to the user to implement. Writing such a handler should not prove very difficult, it is merely a matter of subclassing handler
and implementing the appropriate behaviour in issue
and handle
. The handler can then be used by supplying it to define-handler
by the :class
option.
Event Loops
Finally the most complicated piece of machinery is the event loop itself. In order to understand the workings, first the lifecycle of an event must be analysed. From a user's perspective this would go as follows: an event instance is created and issued onto a loop. It is then handled by the appropriate handlers in the order as specified by their dependency restrictions. The most primitive way to handle this would be to build a dependency graph of the handlers and traverse them in their topological order, only invoking them when their filter applies to the event.
However, this can become severely limiting when the amount of events and handlers becomes significant. The first optimisation is to separate the loop out into a dedicated thread with an event queue that buffers events. This unblocks the issuing thread and ensures that nothing is held up waiting. The next obvious improvement is to cache the dependency graph walking by generating the proper order of handlers upon handler registration. Finally we can realise that the event handler filters will share a lot of common tests which can be potentially rather costly if repeated too often. It would be good if those could be cached and bundled together to avoid unnecessary retesting.
The default implementation compiled-event-loop
in Deeds solves these in the following manner: the unblocking of the issuing thread is achieved through a queue and a background processing thread. The dependency graph is calculated through Tarjan's algorithm and cached as a list. It is recalculated every time a new handler is registered by sort-handlers
. Finally, to make the event loop efficient it is treated as a compile
d function that is built dynamically whenever necessary through build-event-loop
. The mechanism of this is rather complicated.
First, in order to optimise and cache tests the loop is separated into three "phases". The first phase establishes lexical bindings for all tests and performs the type tests on the event object. The second phase performs the actual tests on the event as extracted from the handlers' filters if they are applicable under the current event class. Finally, the handlers are called in their sorted-handlers
order if their filter passes. The bulk of this behaviour is done by extract-tests
which uses filter-tests
to extract all tests from a filter. Tests are simply compared through equal
to see if they are the "same". This is a very conservative comparison as several types of tests would return the same result even if their forms are not equal
such as for commutative tests. compile-test
is used to replace the variable references within a test with event slot accessors as discovered by build-fuzzy-slot-accessor
. Finally replace-tests
is used to replace the tests in a filter with the corresponding variables that are outputted to cache the tests. This is then all packed together into a lambda
form that can then be compile
d into a function object.
The optimisations done here are not optimal however. For example, no effort is done to group when
forms together in the outputted form when possible. This could save on branching and repeat tests in the resulting form. Similarly, no effort is done to recognise whether the required type tests of the handlers are actually strictly necessary or could be weakened to allow further grouping and conflating of tests. There are potentially many more possible improvements that could be done to make the event loop function even tighter, however the algorithms necessary to achieve this would quickly explode in complexity. For now we settle on this rather primitive approach as being sufficient.
However, you can of course extend the system on your own by subclassing event-loop
/sorted-event-loop
/compiled-event-loop
and implementing the proper methods such as build-event-loop
, sort-handlers
, register-handler
, and deregister-handler
.
System Information
Definition Index
-
DEEDS
- ORG.SHIRAKUMO.DEEDS
No documentation provided.-
EXTERNAL SPECIAL-VARIABLE *ORIGIN*
The variable designating the current origin. The value of this might not be useful or significant for anything, but if at all possible it should denote some kind of identifier for the place where an event was signalled from. See WITH-ORIGIN
-
EXTERNAL SPECIAL-VARIABLE *STANDARD-EVENT-LOOP*
The default global instance of a compiled-event-loop.
-
EXTERNAL CLASS BLOCKING-EVENT
A blocking event. This event blocks on all handlers it passes through and blocks the issuing thread until it is done being handled. This behaviour is sometimes desired, especially in cases where remote communication is involved and sequential execution on the issuing side must be ensured. This order cannot be guaranteed with standard events, as while the events are issued in order and handled in order by the same handler, they might change order between different handlers. See EVENT
-
EXTERNAL CLASS CACHED-SLOTS-CLASS
A metaclass that caches all the direct slot instances available to it. The cache is renewed on re/initialization of the class. See CLASS-ALL-DIRECT-SLOTS
-
EXTERNAL CLASS CHUNKED-PAYLOAD-EVENT
A payload delivery event for which the payload has been cut up into chunks. See PAYLOAD-EVENT See SEQUENCE-EVENT
-
EXTERNAL CLASS COMMAND-EVENT
Event used for commands See DEFINE-COMMAND
-
EXTERNAL CLASS COMPILED-EVENT-LOOP
An optimised event loop that compiles the issuing function for fast delivery. Implements a standard queued event loop that respects all other constraints. Supports rudimentary optimisation of the event loop handler filter tests to speed up delivery and generates a tight event delivery function that should allow issuing events to handlers very efficiently. See SORTED-EVENT-LOOP See BUILD-EVENT-LOOP See RECOMPILE-EVENT-LOOP
-
EXTERNAL CLASS CONDITION-NOTIFY-HANDLER
Handler that notifies a condition variable once it receives its event. Saves the received event in its slot. See ONE-TIME-HANDLER See CONDITION-VARIABLE See ISSUE-SYNCHRONIZER-LOCK See RESPONSE-EVENT See WITH-RESPONSE
-
EXTERNAL CLASS ERROR-EVENT
Delivers an error message. See MESSAGE-EVENT
-
EXTERNAL CLASS EVENT
Base class for all events. Anything that would like to be processed by an event-delivery must inherit from this class. See ISSUE-TIME See ORIGIN See CANCELLED
-
EXTERNAL CLASS EVENT-CLASS
Metaclass for events. Uses the EVENT-SLOT class for slots, to allow specification of im/mutable slots. See EVENT-SLOT
-
EXTERNAL CLASS EVENT-DELIVERY
A base class for any kind of object that can deliver events. This class must implement START, STOP, ISSUE, and HANDLE. See DELIVERY-FUNCTION
-
EXTERNAL CLASS EVENT-DIRECT-SLOT-DEFINITION
A standard-direct-slot-definition for an event-slot.
-
EXTERNAL CLASS EVENT-EFFECTIVE-SLOT-DEFINITION
A standard-effective-slot-definition for an event-slot.
-
EXTERNAL CLASS EVENT-LOOP
The base class for an event loop. This event loop is incredibly crude and should only serve as a basis for either very specific scenarios or to build a new event-loop on top of it. It does not sort the handlers properly nor optimise the delivery in any way but simply tests and calls each handler in whatever order it might find them in at the moment. On the other hand, de/registering handlers will be very cheap on this handler, as no recompilation or analysis is required. See QUEUED-EVENT-DELIVERY See HANDLERS See EVENT-LOOP-LOCK See SORTED-EVENT-LOOP See COMPILED-EVENT-LOOP
-
EXTERNAL CLASS EVENT-SLOT
Base class for the event-slot classes. Contains one extra field (:MUTABLE) that allows specification of whether the slot is allowed to be mutated through a writer. If the user attempts to specify a writer (or accessor) on the slot while :MUTABLE NIL, a warning of type IMMUTABLE-EVENT-SLOT-HAS-WRITER is signalled. If an attempt is made to write to a slot that has been designated immutable, a continuable error of type IMMUTABLE-EVENT-SLOT-MODIFIED is signalled. By default slots are immutable. See EVENT-SLOT-MUTABLE
-
EXTERNAL CLASS GLOBALLY-BLOCKING-HANDLER
A handler that globally blocks all issuing threads until it is done. The difference to LOCALLY-BLOCKING-HANDLER is only apparent in the case where multiple event loops issue to this same handler at the same time, in which case both are blocked until their individual events are done being processed. See HANDLER See HANDLER-LOCK
-
EXTERNAL CLASS HANDLER
Base class for all handlers to which events can be delivered. In order for an event to be issued to this, the following criteria should apply to the event. First, the event must pass the type test against the value from the handler's EVENT-TYPE slot. Note that the event-type can be a compound type. Second, the event must pass the handler's FILTER test as per TEST-FILTER. See EVENT-DELIVERY See NAME See EVENT-TYPE See FILTER See BEFORE See AFTER See HANDLE-CANCELLED
-
EXTERNAL CLASS IDENTIFIED-EVENT
An event that belongs to a certain identified group. The identifier defaults to the event itself. See EVENT See IDENTIFIER
-
EXTERNAL CLASS INFO-EVENT
Delivers an informational message. See MESSAGE-EVENT
-
EXTERNAL CLASS LOCALLY-BLOCKING-HANDLER
A handler that handles the event in the issuing thread and thus blocks it. This is useful for handlers that need to modify the event they receive, as then it is guaranteed that the modification is done before any further handlers can be called with the event. See HANDLER
-
EXTERNAL CLASS MESSAGE-EVENT
-
EXTERNAL CLASS ONE-TIME-HANDLER
A handler that can only be called until it is successful. If the delivery-function of the handler returns a non-NIL result, the handler immediately deregisters itself from all its loops and stops itself, thus only ever handling one "correct" event. The return test is done to allow the user more sophisticated testing of the event than is possible through the filter mechanism. See QUEUED-HANDLER See WITH-ONE-TIME-HANDLER
-
EXTERNAL CLASS PARALLEL-HANDLER
A handler that starts a new thread to handle each event that it receives through ISSUE. Note that if you use this handler you must care for resource locking yourself. This can potentially be very tricky and inefficient. See HANDLER See THREADS See HANDLER-LOCK
-
EXTERNAL CLASS PAYLOAD-EVENT
-
EXTERNAL CLASS QUEUED-EVENT-DELIVERY
An event delivery that uses a queue and background thread to deliver events. See EVENT-DELIVERY
-
EXTERNAL CLASS QUEUED-HANDLER
A handler that uses an event queue and separate thread to process them. This is the default handler class. Since there is only a single thread per handler, resources on the handler itself should be safe to access. However, you still have to tend after locking of external resources on your own as they might be modified and accessed in any fashion. Also note that since this is a single, queued handler that any event that takes a very long time will block other events on the handler from being processed. It will not however block the event-loop from which the events are issued. See HANDLER See QUEUED-EVENT-DELIVERY
-
EXTERNAL CLASS SEQUENCE-EVENT
-
EXTERNAL CLASS SORTED-EVENT-LOOP
An event loop that respects the sorting order of handlers. This event loop will always make sure the handlers are in proper order to be called in, but does not perform any further optimisation. As such, this handler should still be reasonably fast to de/register handlers on, but will obviously suffer the deficiencies in issuing due to the lack of optimisation. See EVENT-LOOP See SORTED-HANDLERS See COMPILED-EVENT-LOOP
-
EXTERNAL CLASS STREAM-BEGIN-EVENT
Stream event to signal the beginning of a stream. All further stream events that belong to this stream must have the same identifier as this. Events belonging to this stream may appear until a STREAM-END-EVENT has been issued belonging to this stream. See STREAM-EVENT
-
EXTERNAL CLASS STREAM-END-EVENT
Stream event to signal the end of a stream. See STREAM-EVENT
-
EXTERNAL CLASS STREAM-EVENT
Base event for stream events. All stream events that belong to the same stream must have the same identifier. Stream events are insignificant unless they are issued after a STREAM-BEGIN-EVENT of the same identifier and before a STREAM-END-EVENT of the same identifier. See IDENTIFIED-EVENT
-
EXTERNAL CLASS STREAM-PAYLOAD-EVENT
A payload event for a particular stream. See PAYLOAD-EVENT See STREAM-EVENT
-
EXTERNAL CLASS WARNING-EVENT
Delivers a warning message. See MESSAGE-EVENT
-
EXTERNAL CONDITION EVENT-CONDITION
Condition base class for conditions related to events. See EVENT-CONDITION-EVENT
-
EXTERNAL CONDITION EVENT-LOOP-CONDITION
Condition base class for conditions related to event-loops. See EVENT-LOOP-CONDITION-EVENT-LOOP
-
EXTERNAL CONDITION EVENT-LOOP-HANDLER-DEPENDENCY-CYCLE-ERROR
An error that is signalled whenever a dependency cycle is detected within the handlers. See EVENT-LOOP-CONDITION See EVENT-LOOP-CONDITION-HANDLER
-
EXTERNAL CONDITION HANDLER-CONDITION
Condition base class for conditions related to handlers. See HANDLER-CONDITION-HANDLER
-
EXTERNAL CONDITION HANDLER-THREAD-STOP-FAILED-WARNING
A warning that is signalled whenever a thread of a handler fails to stop. See HANDLER-CONDITION See HANDLER-CONDITION-THREAD
-
EXTERNAL CONDITION IMMUTABLE-EVENT-SLOT-HAS-WRITER
A warning that is signalled whenever an immutable slot is specified with a writer. See EVENT-CONDITION See EVENT-CONDITION-SLOT See EVENT-CONDITION-WRITERS
-
EXTERNAL CONDITION IMMUTABLE-EVENT-SLOT-MODIFIED
An error that is signalled whenever an attempt is made to modify an immutable slot. See EVENT-CONDITION See EVENT-CONDITION-SLOT See EVENT-CONDITION-VALUE
-
EXTERNAL FUNCTION BROADCAST
- EVENT-TYPE
- &REST
- ARGS
- &KEY
- LOOP
- &ALLOW-OTHER-KEYS
- &REST
Shorthand function to allow issuing of an event to multiple loops. Supports an extra keyword argument that will not be passed along to the MAKE-INSTANCE call: LOOP will instead denote the event-loop/s to which one instance each will be issued, defaulting to *STANDARD-EVENT-LOOP*. See *STANDARD-EVENT-LOOP*
-
EXTERNAL FUNCTION COMPUTE-ALL-DIRECT-SLOTS
- CLASS
- &REST
Computes all direct slots of the given class, including those of its superclasses. This simply traverses the class hierarchy upwards, gathering all direct-slots instances along the way. If one class along the way is a CACHED-SLOTS-CLASS, the CLASS-ALL-DIRECT-SLOTS value is used directly instead of traversing further. This does not apply for the passed class. See CACHED-SLOTS-CLASS
-
EXTERNAL FUNCTION MAKE-HANDLER
- &REST
- OPTIONS
- &KEY
- LOOP
- CLASS
- &ALLOW-OTHER-KEYS
- &REST
Creates a new handler instance and takes care of registering it. Creating a new handler this way will simply construct the handler object, start it, and register it on the event loop. If a handler with the same name already exists on the event loop, this old handler is stopped and replaced by the new one. Only the :LOOP and :CLASS options are not passed along to the make-instance call, as they are used by make-handler itself. See HANDLER See REGISTER-HANDLER See QUEUED-HANDLER See *STANDARD-EVENT-LOOP* See WITH-HANDLER See DEFINE-HANDLER See WITH-ONE-TIME-HANDLER
-
EXTERNAL FUNCTION TEST-FILTER
- FILTER
- EVENT
- &REST
Test the filter against the event. Note that you must test whether the event is of applicable type as required by the test yourself, since the test form does not contain this information in itself. The structure of a filter is as follows: FILTER ::= COMBINATOR | TEST COMBINATOR ::= (AND TEST*) | (OR TEST*) | (NOT TEST) TEST ::= (function ARGUMENT*) ARGUMENT ::= fuzzy-slot-symbol | atom fuzzy-slot-symbols denote the value of a slot on the event object. The actual slot is figured out per FIND-CLASS-SLOT-FUZZY on the EVENT-TYPE of the handler. See FIND-CLASS-SLOT-FUZZY See FILTER
-
EXTERNAL GENERIC-FUNCTION AFTER
- OBJECT
- &REST
A list of handler names or categories after which this handler should be called.
-
EXTERNAL GENERIC-FUNCTION BEFORE
- OBJECT
- &REST
A list of handler names or categories before which this handler should be called.
-
EXTERNAL GENERIC-FUNCTION BUILD-EVENT-LOOP
- HANDLERS
- COMPILED-EVENT-LOOP
- &REST
Build a lambda form for the event loop delivery function. The handlers must be in the properly sorted order as returned by SORT-HANDLERS on the same EVENT-LOOP object as is used to call this function. See COMPILED-EVENT-LOOP
-
EXTERNAL GENERIC-FUNCTION CANCEL
- EVENT
- &REST
Cancels the event. An event can be cancelled multiple times though the effect does not change. Once an event has been cancelled it can only be handled by handlers that have HANDLE-CANCELLED set to a non-NIL value. See CANCELLED See HANDLE-CANCELLED
-
EXTERNAL GENERIC-FUNCTION CANCELLED
- OBJECT
- &REST
Accessor to whether the event has been cancelled. See CANCEL
-
EXTERNAL GENERIC-FUNCTION (SETF CANCELLED)
- NEW-VALUE
- OBJECT
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION CLASS-ALL-DIRECT-SLOTS
- OBJECT
- &REST
Finds all direct-slot instances that this class will inherit. More explicitly, it traverses the superclass tree and gathers all direct-slots it can find.
-
EXTERNAL GENERIC-FUNCTION (SETF CLASS-ALL-DIRECT-SLOTS)
- NEW-VALUE
- OBJECT
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION DELIVER-EVENT-DIRECTLY
- EVENT
- EVENT-LOOP
- &REST
Performs a primitive, direct delivery of the event on the loop. This means that handler filters are tested directly without any possible room for optimisation. See TEST-FILTER
-
EXTERNAL GENERIC-FUNCTION DELIVERY-FUNCTION
- OBJECT
- &REST
The function that is used to deliver events. See HANDLE
-
EXTERNAL GENERIC-FUNCTION (SETF DELIVERY-FUNCTION)
- NEW-VALUE
- OBJECT
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION DEREGISTER-HANDLER
- HANDLER
- EVENT-LOOP
- &REST
Deregister the given handler so that it no longer receives events from the event-loop. Deregistering an unregistered handler will not cause an error. Deregistering a handler might cause the event loop to be recompiled, which can be a costly operation. See RECOMPILE-EVENT-LOOP
-
EXTERNAL GENERIC-FUNCTION ENSURE-HANDLERS-SORTED
- SORTED-EVENT-LOOP
- &REST
Ensures that the handlers are properly sorted on the event-loop See SORTED-HANDLERS See SORT-HANDLERS See SORTED-EVENT-LOOP
-
EXTERNAL GENERIC-FUNCTION EVENT-CONDITION-EVENT
- CONDITION
- &REST
The event that the event condition is about.
-
EXTERNAL GENERIC-FUNCTION (SETF EVENT-CONDITION-EVENT)
- NEW-VALUE
- CONDITION
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION EVENT-CONDITION-SLOT
- CONDITION
- &REST
The slot that the event condition is about.
-
EXTERNAL GENERIC-FUNCTION (SETF EVENT-CONDITION-SLOT)
- NEW-VALUE
- CONDITION
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION EVENT-CONDITION-VALUE
- CONDITION
- &REST
The value that the event condition is about.
-
EXTERNAL GENERIC-FUNCTION (SETF EVENT-CONDITION-VALUE)
- NEW-VALUE
- CONDITION
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION EVENT-CONDITION-WRITERS
- CONDITION
- &REST
The writers that the event condition is about.
-
EXTERNAL GENERIC-FUNCTION (SETF EVENT-CONDITION-WRITERS)
- NEW-VALUE
- CONDITION
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION EVENT-LOOP
- OBJECT
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION EVENT-LOOP-CONDITION-EVENT-LOOP
- CONDITION
- &REST
The event-loop that the event-loop condition is about.
-
EXTERNAL GENERIC-FUNCTION (SETF EVENT-LOOP-CONDITION-EVENT-LOOP)
- NEW-VALUE
- CONDITION
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION EVENT-LOOP-CONDITION-HANDLER
- CONDITION
- &REST
The handler that the event-loop condition is about.
-
EXTERNAL GENERIC-FUNCTION (SETF EVENT-LOOP-CONDITION-HANDLER)
- NEW-VALUE
- CONDITION
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION EVENT-LOOP-LOCK
- OBJECT
- &REST
A lock used to synchronise access to the event-loop slots. See HANDLERS See SORTED-HANDLERS See DELIVERY-FUNCTION
-
EXTERNAL GENERIC-FUNCTION (SETF EVENT-LOOP-LOCK)
- NEW-VALUE
- OBJECT
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION EVENT-SLOT-MUTABLE
- OBJECT
- &REST
Accessor to whether the given EVENT-SLOT is mutable or not. See EVENT-SLOT
-
EXTERNAL GENERIC-FUNCTION (SETF EVENT-SLOT-MUTABLE)
- NEW-VALUE
- OBJECT
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION EVENT-TYPE
- OBJECT
- &REST
The event-type that the handler accepts.
-
EXTERNAL GENERIC-FUNCTION FILTER
- OBJECT
- &REST
The specification of a filter to figure out which events the handler accepts. See TEST-FILTER
-
EXTERNAL GENERIC-FUNCTION HANDLE
- EVENT
- EVENT-DELIVERY
- &REST
Directly handle the event by sending it to the handlers. This function bypasses all threading, caching, ordering, and other protective or optimisation constructs of the event delivery itself and processes the event immediately. You should not call this function on your own unless for when you are implementing an event-delivery on your own. In that case you should call this function whenever you are ready to actually process an event and send it out. By default this simply calls the DELIVERY-FUNCTION of the event-delivery with the given event. See ISSUE
-
EXTERNAL GENERIC-FUNCTION HANDLE-CANCELLED
- OBJECT
- &REST
Accessor to whether the handler will handle events even if they are marked as being cancelled.
-
EXTERNAL GENERIC-FUNCTION HANDLER
- HANDLER
- EVENT-LOOP
- &REST
Accesses the named handler from the event-loop, if such exists. Handlers that do not have a NAME will be named by themselves.
-
EXTERNAL GENERIC-FUNCTION (SETF HANDLER)
- HANDLER
- EVENT-LOOP
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION HANDLER-CONDITION-HANDLER
- CONDITION
- &REST
The handler that the handler condition is about.
-
EXTERNAL GENERIC-FUNCTION (SETF HANDLER-CONDITION-HANDLER)
- NEW-VALUE
- CONDITION
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION HANDLER-CONDITION-THREAD
- CONDITION
- &REST
The thread that the handler condition is about.
-
EXTERNAL GENERIC-FUNCTION (SETF HANDLER-CONDITION-THREAD)
- NEW-VALUE
- CONDITION
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION HANDLER-LOCK
- OBJECT
- &REST
Handler lock to lock the access to the internal threads list. See THREADS
-
EXTERNAL GENERIC-FUNCTION (SETF HANDLER-LOCK)
- NEW-VALUE
- OBJECT
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION HANDLERS
- OBJECT
- &REST
An EQL hash-table of the registered handlers on the event-loop. Be careful when modifying this table, as it is not synchronised. See EVENT-LOOP-LOCK
-
EXTERNAL GENERIC-FUNCTION (SETF HANDLERS)
- NEW-VALUE
- OBJECT
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION IDENTIFIER
- OBJECT
- &REST
The unique identifier of the group the event belongs to.
-
EXTERNAL GENERIC-FUNCTION INDEX
- OBJECT
- &REST
The position of the event within the sequence.
-
EXTERNAL GENERIC-FUNCTION ISSUE
- EVENT
- EVENT-DELIVERY
- &REST
Issue an event to the delivery so that it is sent out to the handlers. The exact point in time when the issued event is handled and processed is not specified. However, the order in which events are handled must be the same as the order in which they are issued. An event should only ever be issued once. There is no check made to ensure this, but issuing an event multiple times or on multiple deliveries leads to undefined behaviour. There is also no check made to see whether the event delivery is actually started and ready to accept events. If it is not started, the events might pile up or be dropped on the floor. This is, essentially, undefined behaviour.
-
EXTERNAL GENERIC-FUNCTION ISSUE-TIME
- OBJECT
- &REST
The universal-time at which the event has been ISSUEd to an event-delivery. See ISSUE.
-
EXTERNAL GENERIC-FUNCTION (SETF ISSUE-TIME)
- NEW-VALUE
- OBJECT
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION LOOPS
- OBJECT
- &REST
Accessor to all the loops the handler is registered on right now.
-
EXTERNAL GENERIC-FUNCTION (SETF LOOPS)
- NEW-VALUE
- OBJECT
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION MAX-INDEX
- OBJECT
- &REST
The maximum index of the sequence. Might be NIL if the maximum length of the sequence is not yet known.
-
EXTERNAL GENERIC-FUNCTION MESSAGE
- OBJECT
- &REST
The message of the message-event.
-
EXTERNAL GENERIC-FUNCTION NAME
- OBJECT
- &REST
Returns a symbol describing the name of the object.
-
EXTERNAL GENERIC-FUNCTION ORIGIN
- OBJECT
- &REST
Some description of an origin from where the event was issued. See *ORIGIN* See WITH-ORIGIN
-
EXTERNAL GENERIC-FUNCTION PAYLOAD
- OBJECT
- &REST
The payload of to be delivered.
-
EXTERNAL GENERIC-FUNCTION RECOMPILE-EVENT-LOOP
- COMPILED-EVENT-LOOP
- &REST
Cause the event loop to be recompiled. The event-loop's handlers must already be ready in their sorted order before calling this function. This operation is potentially very costly as it involves building a potentially very large lambda and successively invoking COMPILE on it. With a large number of registered handlers and a slow compiler, this might take up to the order of seconds to run. See BUILD-EVENT-LOOP See ENSURE-HANDLERS-SORTED See COMPILED-EVENT-LOOP
-
EXTERNAL GENERIC-FUNCTION REGISTER-HANDLER
- HANDLER
- EVENT-LOOP
- &REST
Register the given handler so that it may receive events from the event-loop. Registering the same handler twice will still result in it receiving events only once, but will not cause an error. Registering a handler might cause the event loop to be recompiled, which can be a costly operation. See RECOMPILE-EVENT-LOOP
-
EXTERNAL GENERIC-FUNCTION RESPONSE-EVENT
- OBJECT
- &REST
Accessor to the response event the handler captures.
-
EXTERNAL GENERIC-FUNCTION (SETF RESPONSE-EVENT)
- NEW-VALUE
- OBJECT
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION RUNNING
- STUFF
- &REST
Returns T if the event delivery is able to process events.
-
EXTERNAL GENERIC-FUNCTION SORT-HANDLERS
- HANDLERS
- SORTED-EVENT-LOOP
- &REST
Sort the given list of handlers into the proper issuing sequence. The returned list of handlers must be ordered in a way that the BEFORE and AFTER lists of all handlers are met. If a dependency cycle is detected, an error of type EVENT-LOOP-HANDLER-DEPENDENCY-CYCLE-ERROR must be signalled. See SORTED-EVENT-LOOP
-
EXTERNAL GENERIC-FUNCTION SORTED-HANDLERS
- OBJECT
- &REST
A list of the registered handlers in their properly sorted order. This function might become temporarily out of sync with HANDLERS. See SORT-HANDLERS See ENSURE-HANDLERS-SORTED See SORTED-EVENT-LOOP
-
EXTERNAL GENERIC-FUNCTION (SETF SORTED-HANDLERS)
- NEW-VALUE
- OBJECT
- &REST
No documentation provided. -
EXTERNAL GENERIC-FUNCTION START
- EVENT-DELIVERY
- &REST
Start the event delivery and make it ready to accept and deliver events. If the delivery is already running this does nothing.
-
EXTERNAL GENERIC-FUNCTION STOP
- EVENT-DELIVERY
- &REST
Stop the event delivery to prevent it from accepting and delivering events. If there are events that the handler has yet to process, there is no guarantee that they will be processed before the event delivery is stopped. If the delivery is already stopped this does nothing.
-
EXTERNAL GENERIC-FUNCTION THREADS
- OBJECT
- &REST
The threads of the parallel-handler.
-
EXTERNAL GENERIC-FUNCTION (SETF THREADS)
- NEW-VALUE
- OBJECT
- &REST
No documentation provided. -
EXTERNAL MACRO DEFINE-CACHED-SLOTS-CLASS
- NAME
- DIRECT-SUPERCLASSES
- DIRECT-SLOTS
- &REST
- OPTIONS
- &REST
Shorthand macro around defclass to define a cached-slots-class. All this does is wrap the defclass in an EVAL-WHEN and add the metaclass option for cached-slots-class. See CACHED-SLOTS-CLASS
-
EXTERNAL MACRO DEFINE-COMMAND
- NAME
- ARGS
- &BODY
- OPTIONS-AND-BODY
- &REST
Define a command. This is a combinging macro that does three things: . Define an event of NAME with the necessary fields from ARGS. . Define a function of NAME with the given ARGS that issues an instance of this newly defined event. . Define a handler of NAME on the NAME event with the given OPTIONS-AND-BODY. A new option is available just for this macro with the name :SUPERCLASSES, which allows you to specify the direct-superclasses to use in the event definition. The first argument in ARGS must be the name for the event as required by DEFINE-HANDLER. The rest are arguments to the function and simultaneously slots on the event class. In order to allow you to specify slot options, arguments have the following structure: ARGS ::= SINGLE* [&optional DEFAULTING*] [&rest SINGLE*] [&key DEFAULTING*] SINGLE ::= symbol | (symbol SLOT-ARG*) DEFAULTING ::= symbol | (symbol value SLOT-ARG*) SLOT-ARG ::= keyword value The purpose of defining commands is to allow something akin to a function definition that can be treated as such for most purposes while still integrating it with the event system and allowing extension through that.
-
EXTERNAL MACRO DEFINE-EVENT
- NAME
- DIRECT-SUPERCLASSES
- DIRECT-SLOTS
- &REST
- OPTIONS
- &REST
Shorthand convenience macro around DEFCLASS to define new event classes. Pushes the EVENT-CLASS as :METACLASS and EVENT as direct-superclass if it does not already appear somewhere as a transitive superclass.
-
EXTERNAL MACRO DEFINE-HANDLER
- NAME
- EVENT-TYPE
- &REST
- ARGS
- &BODY
- OPTIONS-AND-BODY
- &REST
Define and register a new event handler on a particular event loop. This simply expands to a WITH-HANDLER form with a few extra options to make things easier. Most notably, NAME is transformed (quoted) into the :NAME option. If the :SELF option is given, it names the symbol to which the instance of the handler itself is bound, from which it is accessible from within the handler body. See WITH-HANDLER
-
EXTERNAL MACRO DO-ISSUE
- EVENT-TYPE
- &REST
- ARGS
- &KEY
- LOOP
- &ALLOW-OTHER-KEYS
- &REST
Shorthand macro to allow more convenient issuing of events. Supports one extra keyword argument that will not be passed along to the MAKE-INSTANCE call: LOOP will instead denote the event-loop to which the event is issued, defaulting to *STANDARD-EVENT-LOOP*. See *STANDARD-EVENT-LOOP*
-
EXTERNAL MACRO HERE
A macro that tries to figure out the most appropriate identifier for where this is.
-
EXTERNAL MACRO WITH-AWAITING
- RESPONSE
- &KEY
- FILTER
- TIMEOUT
- LOOP
- &REST
- SETUP-FORM
- &BODY
- BODY
- &REST
No documentation provided. -
EXTERNAL MACRO WITH-FUZZY-SLOT-BINDINGS
- VARS
- INSTANCE
- CLASS-ISH
- &REST
- &BODY
- BODY
- &REST
Establishes a binding context similar to WITH-SLOTS and WITH-ACCESSORS but using the most appropriate way to access a slot, and a fuzzy manner of identifying slots. Each VAR can either be a list of NAME SLOT-ISH, or simply the SLOT-ISH which will be used as the name as well. You must pass the class explicitly since we have to be able to analyse the slots of the class during compile time. See BUILD-FUZZY-SLOT-ACCESSOR
-
EXTERNAL MACRO WITH-HANDLER
- EVENT-TYPE
- ARGS
- &BODY
- OPTIONS-AND-BODY
- &REST
Convenient macro to construct a handler. ARGS must be a list of at least one value, which must be a symbol that is bound to the event instance. The rest of the args are slots of the event, bound by WITH-FUZZY-SLOT-BINDINGS. Note that as per the limitation on event-type specifiers arising from FIND-CLASS-SLOT-FOR-COMPOUND, only direct class-name types or compound types consisting of OR and AND are possible for the EVENT-TYPE. The actual body forms are composed into a lambda form which is passed as the :DELIVERY-FUNCTION argument to MAKE-HANDLER alongside with EVENT-TYPE. It is also wrapped in a WITH-ORIGIN environment where the origin is set to the :NAME option. See MAKE-HANDLER See WITH-FUZZY-SLOT-BINDINGS See WITH-ORIGIN
-
EXTERNAL MACRO WITH-IMMUTABLE-SLOTS-UNLOCKED
- &BODY
- BODY
- &REST
Unlocks immutable slots, allowing you to modify them. This simply automatically calls the CONTINUE restart when an error of type IMMUTABLE-EVENT-SLOT-MODIFIED is signalled. See EVENT-SLOT
-
EXTERNAL MACRO WITH-ONE-TIME-HANDLER
- EVENT-TYPE
- ARGS
- &BODY
- OPTIONS-AND-BODY
- &REST
Constructs a handler that can only handle a single event before being deregistered again. Defaults the class to ONE-TIME-HANDLER. See WITH-HANDLER See ONE-TIME-HANDLER See DEREGISTER-HANDLER
-
EXTERNAL MACRO WITH-ORIGIN
- &OPTIONAL
- NEW-ORIGIN
- &REST
- &BODY
- BODY
- &REST
-
EXTERNAL MACRO WITH-RESPONSE
- ISSUE
- RESPONSE
- &KEY
- FILTER
- TIMEOUT
- ISSUE-LOOP
- RESPONSE-LOOP
- &REST
- &BODY
- BODY
- &REST
A macro to de-asynchronise waiting for a response to an event. More specifically, this construct allows you to circumvent having to use callbacks and instead allows the handling of an event that is in response to an issued one in the same thread as if it all happened sequentially. ISSUE ::= event-type | (event-type initarg*) RESPONSE ::= event-type | (event-type [event-symbol slots*]) In detail the following happens when the block generated by this macro is executed: . A handler is instantiated with the given response event-type and filter. . The handler is started up. . The handler's synchronizer lock is acquired. . The handler is registered on the given event-loop. . An event is issued with the event-type and initargs onto the event-loop. . Now the thread waits on the handler's condition variable. . Once the thread is reawakened before the timeout it binds the event from the handler and the specified slot variables, then proceeds to evaluate the body. . As a cleanup, the handler is deregistered and stopped. The handler itself performs the following steps once it HANDLEs an event: . Acquire the one-time-handler exclusive lock. . Save the event on its own slot. . Acquire the synchronizer lock and immediately release it again to ensure that the issuing thread is waiting on the condition variable. . Notify the condition variable. See DO-ISSUE See REGISTER-HANDLER See DEREGISTER-HANDLER See WITH-FUZZY-SLOT-BINDINGS See CONDITION-NOTIFY-HANDLER