1 /** 2 A `select` based event driver implementation. 3 4 This driver works on all BSD socket compatible operating systems, including 5 Windows. It has a good performance for small numbers of cuncurrently open 6 files/sockets, but is not suited for larger amounts. 7 */ 8 module eventcore.drivers.posix.select; 9 @safe: /*@nogc:*/ nothrow: 10 11 public import eventcore.drivers.posix.driver; 12 import eventcore.internal.utils; 13 14 import core.time : Duration; 15 16 version (Posix) { 17 import core.sys.posix.sys.time : timeval; 18 import core.sys.posix.sys.select; 19 } 20 21 version (Windows) { 22 import core.sys.windows.winsock2; 23 } 24 25 26 alias SelectEventDriver = PosixEventDriver!SelectEventLoop; 27 28 final class SelectEventLoop : PosixEventLoop { 29 @safe: nothrow: 30 override bool doProcessEvents(Duration timeout) 31 { 32 //assert(Fiber.getThis() is null, "processEvents may not be called from within a fiber!"); 33 //scope (failure) assert(false); import std.stdio; writefln("%.3f: process %s ms", Clock.currAppTick.usecs * 1e-3, timeout.total!"msecs"); 34 //scope (success) writefln("%.3f: process out", Clock.currAppTick.usecs * 1e-3); 35 36 auto ts = timeout.toTimeVal; 37 38 fd_set readfds, writefds, statusfds; 39 40 () @trusted { 41 FD_ZERO(&readfds); 42 FD_ZERO(&writefds); 43 FD_ZERO(&statusfds); 44 } (); 45 enumerateFDs!(EventType.read)((fd) @trusted { FD_SET(cast(sock_t)fd, &readfds); }); 46 enumerateFDs!(EventType.write)((fd) @trusted { FD_SET(cast(sock_t)fd, &writefds); }); 47 enumerateFDs!(EventType.status)((fd) @trusted { FD_SET(cast(sock_t)fd, &statusfds); }); 48 49 //print("Wait for event... %s", timeout); 50 //writefln("%.3f: select in", Clock.currAppTick.usecs * 1e-3); 51 auto ret = () @trusted { return select(this.maxFD+1, &readfds, &writefds, &statusfds, timeout == Duration.max ? null : &ts); } (); 52 //writefln("%.3f: select out", Clock.currAppTick.usecs * 1e-3); 53 //print("Done wait for event..."); 54 if (ret > 0) { 55 enumerateFDs!(EventType.read)((fd) @trusted { 56 if (FD_ISSET(cast(sock_t)fd, &readfds)) 57 notify!(EventType.read)(fd); 58 }); 59 enumerateFDs!(EventType.write)((fd) @trusted { 60 if (FD_ISSET(cast(sock_t)fd, &writefds)) 61 notify!(EventType.write)(fd); 62 }); 63 enumerateFDs!(EventType.status)((fd) @trusted { 64 if (FD_ISSET(cast(sock_t)fd, &statusfds)) 65 notify!(EventType.status)(fd); 66 }); 67 return true; 68 } else { 69 // NOTE: In particular, EINTR needs to cause true to be returned 70 // here, so that user code has a chance to handle any effects 71 // of the signal handler before waiting again. 72 // 73 // Other errors are very likely to to reoccur for the next 74 // loop iteration, so there is no value in attempting to 75 // wait again. 76 return ret < 0; 77 } 78 } 79 80 override void dispose() 81 { 82 super.dispose(); 83 } 84 85 override void registerFD(FD fd, EventMask mask, bool edge_triggered = true) 86 { 87 } 88 89 override void unregisterFD(FD fd, EventMask mask) 90 { 91 } 92 93 override void updateFD(FD fd, EventMask old_mask, EventMask mask, bool edge_triggered = true) 94 { 95 } 96 } 97 98 private timeval toTimeVal(Duration dur) 99 { 100 timeval tvdur; 101 dur.split!("seconds", "usecs")(tvdur.tv_sec, tvdur.tv_usec); 102 return tvdur; 103 }