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 }