Add basic documentation for the driver interface.

This commit is contained in:
Sönke Ludwig 2017-01-22 11:39:01 +01:00
parent 58c89a7369
commit f5b514899a

View file

@ -1,3 +1,20 @@
/** Definition of the core event driver interface.
This module contains all declarations necessary for defining and using
event drivers. Event driver implementations will usually inherit from
`EventDriver` using a `final` class to avoid virtual function overhead.
Callback_Behavior:
All callbacks follow the same rules to enable generic implementation
of high-level libraries, such as vibe.d. Except for "listen" style
callbacks, each callback will only ever be called at most once.
If the operation does not get canceled, the callback will be called
exactly once. In case it gets manually canceled using the corresponding
API function, the callback is guaranteed to not be called. However,
the associated operation might still finish - either before the
cancellation function returns, or afterwards.
*/
module eventcore.driver; module eventcore.driver;
@safe: /*@nogc:*/ nothrow: @safe: /*@nogc:*/ nothrow:
@ -5,22 +22,40 @@ import core.time : Duration;
import std.socket : Address; import std.socket : Address;
/** Encapsulates a full event driver.
This interface provides access to the individual driver features, as well as
a central `dispose` method that must be called before the driver gets
destroyed or before the process gets terminated.
*/
interface EventDriver { interface EventDriver {
@safe: /*@nogc:*/ nothrow: @safe: /*@nogc:*/ nothrow:
/// Core event loop functionality
@property EventDriverCore core(); @property EventDriverCore core();
/// Single shot and recurring timers
@property EventDriverTimers timers(); @property EventDriverTimers timers();
/// Cross-thread events (thread local access)
@property EventDriverEvents events(); @property EventDriverEvents events();
/// Cross-thread events (cross-thread access)
@property shared(EventDriverEvents) events() shared; @property shared(EventDriverEvents) events() shared;
/// UNIX/POSIX signal reception
@property EventDriverSignals signals(); @property EventDriverSignals signals();
/// Stream and datagram sockets
@property EventDriverSockets sockets(); @property EventDriverSockets sockets();
/// DNS queries
@property EventDriverDNS dns(); @property EventDriverDNS dns();
/// Local file operations
@property EventDriverFiles files(); @property EventDriverFiles files();
/// Directory change watching
@property EventDriverWatchers watchers(); @property EventDriverWatchers watchers();
/// Releases all resources associated with the driver /// Releases all resources associated with the driver
void dispose(); void dispose();
} }
/** Provides generic event loop control.
*/
interface EventDriverCore { interface EventDriverCore {
@safe: /*@nogc:*/ nothrow: @safe: /*@nogc:*/ nothrow:
/** The number of pending callbacks. /** The number of pending callbacks.
@ -48,7 +83,7 @@ interface EventDriverCore {
/** Causes `processEvents` to return with `ExitReason.exited` as soon as /** Causes `processEvents` to return with `ExitReason.exited` as soon as
possible. possible.
A call to `processEvents` that is currently in progress will be notfied A call to `processEvents` that is currently in progress will be notified
so that it returns immediately. If no call is in progress, the next call so that it returns immediately. If no call is in progress, the next call
to `processEvents` will immediately return with `ExitReason.exited`. to `processEvents` will immediately return with `ExitReason.exited`.
*/ */
@ -79,35 +114,150 @@ interface EventDriverCore {
} }
} }
/** Provides access to socket functionality.
The interface supports two classes of sockets - stream sockets and datagram
sockets.
*/
interface EventDriverSockets { interface EventDriverSockets {
@safe: /*@nogc:*/ nothrow: @safe: /*@nogc:*/ nothrow:
/** Connects to a stream listening socket.
*/
StreamSocketFD connectStream(scope Address peer_address, scope Address bind_address, ConnectCallback on_connect); StreamSocketFD connectStream(scope Address peer_address, scope Address bind_address, ConnectCallback on_connect);
/** Adopts an existing stream socket.
The given socket must be in a connected state. It will be automatically
switched to non-blocking mode if necessary. Beware that this may have
side effects in other code that uses the socket and assumes blocking
operations.
Params:
socket: Socket file descriptor to adopt
Returns:
Returns a socket handle corresponding to the passed socket
descriptor. If the same file descriptor is already registered,
`StreamSocketFD.invalid` will be returned instead.
*/
StreamSocketFD adoptStream(int socket); StreamSocketFD adoptStream(int socket);
/// Creates a socket listening for incoming stream connections.
StreamListenSocketFD listenStream(scope Address bind_address, AcceptCallback on_accept); StreamListenSocketFD listenStream(scope Address bind_address, AcceptCallback on_accept);
/// Starts to wait for incoming connections on a listening socket.
void waitForConnections(StreamListenSocketFD sock, AcceptCallback on_accept); void waitForConnections(StreamListenSocketFD sock, AcceptCallback on_accept);
/// Determines the current connection state.
ConnectionState getConnectionState(StreamSocketFD sock); ConnectionState getConnectionState(StreamSocketFD sock);
/// Retrieves the bind address of a socket.
bool getLocalAddress(StreamSocketFD sock, scope RefAddress dst); bool getLocalAddress(StreamSocketFD sock, scope RefAddress dst);
/// Sets the `TCP_NODELAY` option on a socket
void setTCPNoDelay(StreamSocketFD socket, bool enable); void setTCPNoDelay(StreamSocketFD socket, bool enable);
/// Sets to `SO_KEEPALIVE` socket option on a socket.
void setKeepAlive(StreamSocketFD socket, bool enable); void setKeepAlive(StreamSocketFD socket, bool enable);
/** Reads data from a stream socket.
Note that only a single read operation is allowed at once. The caller
needs to make sure that either `on_read_finish` got called, or
`cancelRead` was called before issuing the next call to `read`.
However, concurrent writes are legal.
Waiting_for_data_availability:
With the special combination of a zero-length buffer and `mode`
set to either `IOMode.once` or `IOMode.all`, this function will
wait until data is available on the socket without reading
anything.
Note that in this case the `IOStatus` parameter of the callback
will not reliably reflect a passive connection close. It is
necessary to actually read some data to make sure this case
is detected.
*/
void read(StreamSocketFD socket, ubyte[] buffer, IOMode mode, IOCallback on_read_finish); void read(StreamSocketFD socket, ubyte[] buffer, IOMode mode, IOCallback on_read_finish);
/** Cancels an ongoing read operation.
After this function has been called, the `IOCallback` specified in
the call to `read` is guaranteed to not be called.
*/
void cancelRead(StreamSocketFD socket); void cancelRead(StreamSocketFD socket);
/** Reads data from a stream socket.
Note that only a single write operation is allowed at once. The caller
needs to make sure that either `on_write_finish` got called, or
`cancelWrite` was called before issuing the next call to `write`.
However, concurrent reads are legal.
*/
void write(StreamSocketFD socket, const(ubyte)[] buffer, IOMode mode, IOCallback on_write_finish); void write(StreamSocketFD socket, const(ubyte)[] buffer, IOMode mode, IOCallback on_write_finish);
/** Cancels an ongoing write operation.
After this function has been called, the `IOCallback` specified in
the call to `write` is guaranteed to not be called.
*/
void cancelWrite(StreamSocketFD socket); void cancelWrite(StreamSocketFD socket);
/** Waits for incoming data without actually reading it.
*/
void waitForData(StreamSocketFD socket, IOCallback on_data_available); void waitForData(StreamSocketFD socket, IOCallback on_data_available);
/** Initiates a connection close.
*/
void shutdown(StreamSocketFD socket, bool shut_read, bool shut_write); void shutdown(StreamSocketFD socket, bool shut_read, bool shut_write);
/** Creates a connection-less datagram socket.
Params:
bind_address: The local bind address to use for the socket. It
will be able to receive any messages sent to this address.
target_address: Optional default target address. If this is
specified and the target address parameter of `send` is
left to `null`, it will be used instead.
Returns:
Returns a datagram socket handle if the socket was created
successfully. Otherwise returns `DatagramSocketFD.invalid`.
*/
DatagramSocketFD createDatagramSocket(scope Address bind_address, scope Address target_address); DatagramSocketFD createDatagramSocket(scope Address bind_address, scope Address target_address);
/** Adopts an existing datagram socket.
The socket must be properly bound before this function is called.
Params:
socket: Socket file descriptor to adopt
Returns:
Returns a socket handle corresponding to the passed socket
descriptor. If the same file descriptor is already registered,
`DatagramSocketFD.invalid` will be returned instead.
*/
DatagramSocketFD adoptDatagramSocket(int socket); DatagramSocketFD adoptDatagramSocket(int socket);
/// Sets the `SO_BROADCAST` socket option.
bool setBroadcast(DatagramSocketFD socket, bool enable); bool setBroadcast(DatagramSocketFD socket, bool enable);
/// Receives a single datagram.
void receive(DatagramSocketFD socket, ubyte[] buffer, IOMode mode, DatagramIOCallback on_receive_finish); void receive(DatagramSocketFD socket, ubyte[] buffer, IOMode mode, DatagramIOCallback on_receive_finish);
/// Cancels an ongoing wait for an incoming datagram.
void cancelReceive(DatagramSocketFD socket); void cancelReceive(DatagramSocketFD socket);
/// Sends a single datagram.
void send(DatagramSocketFD socket, const(ubyte)[] buffer, IOMode mode, Address target_address, DatagramIOCallback on_send_finish); void send(DatagramSocketFD socket, const(ubyte)[] buffer, IOMode mode, Address target_address, DatagramIOCallback on_send_finish);
/// Cancels an ongoing wait for an outgoing datagram.
void cancelSend(DatagramSocketFD socket); void cancelSend(DatagramSocketFD socket);
/** Increments the reference count of the given resource. /** Increments the reference count of the given socket.
*/ */
void addRef(SocketFD descriptor); void addRef(SocketFD descriptor);
/** Decrements the reference count of the given resource.
/** Decrements the reference count of the given socket.
Once the reference count reaches zero, all associated resources will be Once the reference count reaches zero, all associated resources will be
freed and the resource descriptor gets invalidated. freed and the resource descriptor gets invalidated.
@ -118,12 +268,21 @@ interface EventDriverSockets {
bool releaseRef(SocketFD descriptor); bool releaseRef(SocketFD descriptor);
} }
/** Performs asynchronous DNS queries.
*/
interface EventDriverDNS { interface EventDriverDNS {
@safe: /*@nogc:*/ nothrow: @safe: /*@nogc:*/ nothrow:
/// Looks up addresses corresponding to the given DNS name.
DNSLookupID lookupHost(string name, DNSLookupCallback on_lookup_finished); DNSLookupID lookupHost(string name, DNSLookupCallback on_lookup_finished);
/// Cancels an ongoing DNS lookup.
void cancelLookup(DNSLookupID handle); void cancelLookup(DNSLookupID handle);
} }
/** Provides read/write operations on the local file system.
*/
interface EventDriverFiles { interface EventDriverFiles {
@safe: /*@nogc:*/ nothrow: @safe: /*@nogc:*/ nothrow:
FileFD open(string path, FileOpenMode mode); FileFD open(string path, FileOpenMode mode);
@ -137,11 +296,11 @@ interface EventDriverFiles {
void cancelWrite(FileFD file); void cancelWrite(FileFD file);
void cancelRead(FileFD file); void cancelRead(FileFD file);
/** Increments the reference count of the given resource. /** Increments the reference count of the given file.
*/ */
void addRef(FileFD descriptor); void addRef(FileFD descriptor);
/** Decrements the reference count of the given resource. /** Decrements the reference count of the given file.
Once the reference count reaches zero, all associated resources will be Once the reference count reaches zero, all associated resources will be
freed and the resource descriptor gets invalidated. freed and the resource descriptor gets invalidated.
@ -152,19 +311,40 @@ interface EventDriverFiles {
bool releaseRef(FileFD descriptor); bool releaseRef(FileFD descriptor);
} }
/** Cross-thread notifications
"Events" can be used to wake up the event loop of a foreign thread. This is
the basis for all kinds of thread synchronization primitives, such as
mutexes, condition variables, message queues etc. Such primitives, in case
of extended wait periods, should use events rather than traditional means
to block, such as busy loops or kernel based wait mechanisms to avoid
stalling the event loop.
*/
interface EventDriverEvents { interface EventDriverEvents {
@safe: /*@nogc:*/ nothrow: @safe: /*@nogc:*/ nothrow:
/// Creates a new cross-thread event.
EventID create(); EventID create();
/// Triggers an event owned by the current thread.
void trigger(EventID event, bool notify_all); void trigger(EventID event, bool notify_all);
/// Triggers an event possibly owned by a different thread.
void trigger(EventID event, bool notify_all) shared; void trigger(EventID event, bool notify_all) shared;
/** Waits until an event gets triggered.
Multiple concurrent waits are allowed.
*/
void wait(EventID event, EventCallback on_event); void wait(EventID event, EventCallback on_event);
/// Cancels an ongoing wait operation.
void cancelWait(EventID event, EventCallback on_event); void cancelWait(EventID event, EventCallback on_event);
/** Increments the reference count of the given resource. /** Increments the reference count of the given event.
*/ */
void addRef(EventID descriptor); void addRef(EventID descriptor);
/** Decrements the reference count of the given resource. /** Decrements the reference count of the given event.
Once the reference count reaches zero, all associated resources will be Once the reference count reaches zero, all associated resources will be
freed and the resource descriptor gets invalidated. freed and the resource descriptor gets invalidated.
@ -175,8 +355,29 @@ interface EventDriverEvents {
bool releaseRef(EventID descriptor); bool releaseRef(EventID descriptor);
} }
/** Handling of POSIX signals.
*/
interface EventDriverSignals { interface EventDriverSignals {
@safe: /*@nogc:*/ nothrow: @safe: /*@nogc:*/ nothrow:
/** Starts listening for the specified POSIX signal.
Note that if a default signal handler exists for the signal, it will be
disabled by using this function.
Params:
sig: The number of the signal to listen for
on_signal: Callback that gets called whenever a matching signal gets
received
Returns:
Returns an identifier that identifies the resource associated with
the signal. Giving up ownership of this resource using `releaseRef`
will re-enable the default signal handler, if any was present.
For any error condition, `SignalListenID.invalid` will be returned
instead.
*/
SignalListenID listen(int sig, SignalCallback on_signal); SignalListenID listen(int sig, SignalCallback on_signal);
/** Increments the reference count of the given resource. /** Increments the reference count of the given resource.
@ -221,6 +422,7 @@ interface EventDriverTimers {
interface EventDriverWatchers { interface EventDriverWatchers {
@safe: /*@nogc:*/ nothrow: @safe: /*@nogc:*/ nothrow:
/// Watches a directory or a directory sub tree for changes.
WatcherID watchDirectory(string path, bool recursive, FileChangesCallback callback); WatcherID watchDirectory(string path, bool recursive, FileChangesCallback callback);
/** Increments the reference count of the given resource. /** Increments the reference count of the given resource.
@ -238,6 +440,8 @@ interface EventDriverWatchers {
bool releaseRef(WatcherID descriptor); bool releaseRef(WatcherID descriptor);
} }
// Helper class to enable fully stack allocated `std.socket.Address` instances.
final class RefAddress : Address { final class RefAddress : Address {
version (Posix) import core.sys.posix.sys.socket : sockaddr, socklen_t; version (Posix) import core.sys.posix.sys.socket : sockaddr, socklen_t;
version (Windows) import core.sys.windows.winsock2 : sockaddr, socklen_t; version (Windows) import core.sys.windows.winsock2 : sockaddr, socklen_t;