1 /**
2 	Contains interfaces and enums for asynchronous drivers.
3 
4 	At the lowest level of Vibe.d sits a library which handle all the
5 	asynchronous I/O operations.
6 	There are currently 3 supported I/O backend: libasync, libevent and libev.
7 	This module define the interface such a library must conform with
8 	to work with Vibe.d
9 
10 	Copyright: © 2012-2015 RejectedSoftware e.K.
11 	Authors: Sönke Ludwig
12 	License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
13 */
14 module vibe.core.driver;
15 
16 public import vibe.core.file;
17 public import vibe.core.net;
18 public import vibe.core.path;
19 public import vibe.core.sync;
20 public import vibe.core.stream;
21 public import vibe.core.task;
22 
23 import core.time;
24 import std.exception;
25 
26 
27 version (VibeUseNativeDriverType) {
28 	import vibe.core.drivers.native;
29 	alias StoredEventDriver = NativeEventDriver;
30 } else alias StoredEventDriver = EventDriver;
31 
32 
33 /**
34 	Returns the active event driver
35 */
36 StoredEventDriver getEventDriver(bool ignore_unloaded = false)
37 @safe nothrow {
38 	assert(ignore_unloaded || s_driver !is null, "No event driver loaded. Did the vibe.core.core module constructor run?");
39 	return s_driver;
40 }
41 
42 /// private
43 package void setupEventDriver(DriverCore core_)
44 {
45 	version (VibeUseNativeDriverType) {}
46 	else import vibe.core.drivers.native;
47 
48 	s_driver = new NativeEventDriver(core_);
49 }
50 
51 package void deleteEventDriver()
52 {
53 	if (s_driver) {
54 		s_driver.dispose();
55 		destroy(s_driver);
56 		s_driver = null;
57 	}
58 }
59 
60 
61 private {
62 	StoredEventDriver s_driver;
63 }
64 
65 
66 /**
67 	Interface for all evented I/O implementations.
68 
69 	This is the low level interface for all event based functionality. It is
70 	not intended to be used directly by users of the library.
71 */
72 interface EventDriver {
73 @safe:
74 
75 	/** Frees all resources of the driver and prepares it for consumption by the GC.
76 
77 		Note that the driver will not be usable after calling this method. Any
78 		further calls are illegal and result in undefined behavior.
79 	*/
80 	void dispose() /*nothrow*/;
81 
82 	/** Starts the event loop.
83 
84 		The loop will continue to run until either no more event listeners are active or until
85 		exitEventLoop() is called.
86 	*/
87 	int runEventLoop() /*nothrow*/;
88 
89 	/* Processes all outstanding events, potentially blocking to wait for the first event.
90 	*/
91 	int runEventLoopOnce() /*nothrow*/;
92 
93 	/** Processes all outstanding events if any, does not block.
94 	*/
95 	bool processEvents() /*nothrow*/;
96 
97 	/** Exits any running event loop.
98 	*/
99 	void exitEventLoop() /*nothrow*/;
100 
101 	/** Opens a file on disk with the speficied file mode.
102 	*/
103 	FileStream openFile(Path path, FileMode mode);
104 
105 	/** Starts watching a directory for changes.
106 	*/
107 	DirectoryWatcher watchDirectory(Path path, bool recursive);
108 
109 	/** Resolves the given host name or IP address string.
110 
111 		'host' can be a DNS name (if use_dns is set) or an IPv4 or IPv6
112 		address string.
113 	*/
114 	NetworkAddress resolveHost(string host, ushort family, bool use_dns);
115 
116 	/** Establiches a tcp connection on the specified host/port.
117 	*/
118 	TCPConnection connectTCP(NetworkAddress address, NetworkAddress bind_address);
119 
120 	/** Listens on the specified port and interface for TCP connections.
121 
122 		'bind_address' must be an IPv4 or IPv6 address string corresponding to a local network
123 		interface. conn_callback is called for every incoming connection, each time from a
124 		new task.
125 	*/
126 	TCPListener listenTCP(ushort port, void delegate(TCPConnection conn) @safe conn_callback, string bind_address, TCPListenOptions options);
127 
128 	/** Creates a new UDP socket and sets the specified address/port as the destination for packets.
129 
130 		If a bind port is specified, the socket will be able to receive UDP packets on that port.
131 		Otherwise, a random bind port is chosen.
132 	*/
133 	UDPConnection listenUDP(ushort port, string bind_address = "0.0.0.0");
134 
135 	/** Creates a new manually triggered event.
136 	*/
137 	ManualEvent createManualEvent() nothrow;
138 
139 	/** Creates an event for waiting on a non-bocking file handle.
140 	*/
141 	FileDescriptorEvent createFileDescriptorEvent(int file_descriptor, FileDescriptorEvent.Trigger triggers, FileDescriptorEvent.Mode mode);
142 
143 	/** Creates a new timer.
144 
145 		The timer can be started by calling rearmTimer() with a timeout.
146 		The initial reference count is 1, use releaseTimer to free all resources
147 		associated with the timer.
148 	*/
149 	size_t createTimer(void delegate() @safe callback);
150 
151 	/// Increases the reference count by one.
152 	void acquireTimer(size_t timer_id);
153 
154 	/// Decreases the reference count by one.
155 	void releaseTimer(size_t timer_id);
156 
157 	/// Queries if the timer is currently active.
158 	bool isTimerPending(size_t timer_id);
159 
160 	/// Resets the timeout of the timer.
161 	void rearmTimer(size_t timer_id, Duration dur, bool periodic);
162 
163 	/// Stops the timer.
164 	void stopTimer(size_t timer_id) nothrow;
165 
166 	/// Waits for the pending timer to expire.
167 	void waitTimer(size_t timer_id);
168 }
169 
170 
171 /**
172 	Provides an event driver with core functions for task/fiber control.
173 */
174 interface DriverCore {
175 @safe:
176 
177 	/** Sets an exception to be thrown on the next call to $(D yieldForEvent).
178 
179 		Note that this only has an effect if $(D yieldForEvent) is called
180 		outside of a task. To throw an exception in a task, use the
181 		$(D event_exception) parameter to $(D resumeTask).
182 	*/
183 	@property void eventException(Exception e);
184 
185 	/** Yields execution until the event loop receives an event.
186 
187 		Throws:
188 			May throw an $(D InterruptException) if the task got interrupted
189 			using $(D vibe.core.task.Task.interrupt()). Rethrows any
190 			exception that is passed to the $(D resumeTask) call that wakes
191 			up the task.
192 	*/
193 	void yieldForEvent() @safe;
194 
195 	/** Yields execution until the event loop receives an event.
196 
197 		Throws:
198 			This method doesn't throw. Any exceptions, such as
199 			$(D InterruptException) or an exception passed to $(D resumeTask),
200 			are stored and thrown on the next call to $(D yieldForEvent).
201 
202 	*/
203 	void yieldForEventDeferThrow() nothrow @safe;
204 
205 	/** Resumes the given task.
206 
207 		This function may only be called outside of a task to resume a
208 		yielded task. The optional $(D event_exception) will be thrown in the
209 		context of the resumed task.
210 
211 		See_also: $(D yieldAndResumeTask)
212 	*/
213 	void resumeTask(Task task, Exception event_exception = null) @safe nothrow;
214 
215 	/** Yields the current task and resumes another one.
216 
217 		This is the same as $(D resumeTask), but also works from within a task.
218 		If called from a task, that task will be yielded first before resuming
219 		the other one.
220 
221 		Throws:
222 			May throw an `InterruptException` if the calling task gets
223 			interrupted using `Task.interrupt()`.
224 
225 		See_also: $(D resumeTask)
226 	*/
227 	void yieldAndResumeTask(Task task, Exception event_exception = null) @safe;
228 
229 	/** Notifies the core that all events have been processed.
230 
231 		This should be called by the driver whenever the event queue has been
232 		fully processed.
233 	*/
234 	void notifyIdle();
235 
236 	bool isScheduledForResume(Task t);
237 }
238 
239 
240 /**
241 	Generic file descriptor event.
242 
243 	This kind of event can be used to wait for events on a non-blocking
244 	file descriptor. Note that this can usually only be used on socket
245 	based file descriptors.
246 */
247 interface FileDescriptorEvent {
248 @safe:
249 
250 	/** Event mask selecting the kind of events to listen for.
251 	*/
252 	enum Trigger {
253 		none = 0,         /// Match no event (invalid value)
254 		read = 1<<0,      /// React on read-ready events
255 		write = 1<<1,     /// React on write-ready events
256 		any = read|write  /// Match any kind of event
257 	}
258 
259 	/** Event waiting mode.
260 	*/
261 	enum Mode {
262 		nonPersistent, /// Indicates that the event is non-persistent
263 		persistent,    /// Indicates that the event is persistent
264 		edgeTriggered  /// Indicates that the event should be edge-triggered
265 	}
266 
267 	/** Waits for the selected event to occur.
268 
269 		Params:
270 			which = Optional event mask to react only on certain events
271 			timeout = Maximum time to wait for an event
272 
273 		Returns:
274 			If events occurs, returns a mask of these events.
275 			If the timeout expired, returns the `Trigger.none`
276 	*/
277 	Trigger wait(Trigger which = Trigger.any);
278 	/// ditto
279 	Trigger wait(Duration timeout, Trigger which = Trigger.any);
280 }