1 module concurrency.timer; 2 3 import concurrency.stoptoken; 4 import core.time : Duration; 5 6 version (OSX) {} else 7 /// waits for dur and returns true 8 /// or false when stoptoken is triggered 9 deprecated("use delay or scheduleAfter") 10 bool wait(StopToken stopToken, Duration dur) nothrow @trusted { 11 // this is a optimisation, 12 // it will still work if a stop is triggered before the 13 // onStop handler is set 14 if (stopToken.isStopRequested) 15 return false; 16 17 try { 18 version (Windows) { 19 import core.sync.mutex : Mutex; 20 import core.sync.condition : Condition; 21 22 auto m = new Mutex(); 23 auto cond = new Condition(m); 24 auto cb = stopToken.onStop(cast(void delegate() shared nothrow @safe)() nothrow @trusted { 25 m.lock_nothrow(); 26 scope (exit) 27 m.unlock_nothrow(); 28 try { 29 cond.notify(); 30 } 31 catch (Exception e) { 32 assert(false, e.msg); 33 } 34 }); 35 scope (exit) 36 cb.dispose(); 37 38 /// wait returns true if notified, we want to return false in that case as it signifies cancellation 39 m.lock_nothrow(); 40 scope(exit) m.unlock_nothrow(); 41 return !cond.wait(dur); 42 } else version (Posix) { 43 import core.sys.linux.timerfd; 44 import core.sys.linux.sys.eventfd; 45 import core.sys.posix.sys.select; 46 import std.exception : ErrnoException; 47 import core.sys.posix.unistd; 48 import core.stdc.errno; 49 50 shared int stopfd = eventfd(0, EFD_CLOEXEC); 51 if (stopfd == -1) 52 throw new ErrnoException("eventfd failed"); 53 54 auto cb = stopToken.onStop(() shared @trusted { 55 ulong b = 1; 56 write(stopfd, &b, typeof(b).sizeof); 57 }); 58 scope (exit) { 59 cb.dispose(); 60 close(stopfd); 61 } 62 63 auto when = dur.split!("seconds", "usecs"); 64 fd_set read_fds; 65 FD_ZERO(&read_fds); 66 FD_SET(stopfd, &read_fds); 67 timeval tv; 68 tv.tv_sec = when.seconds; 69 tv.tv_usec = when.usecs; 70 retry: 71 const ret = select(stopfd + 1, &read_fds, null, null, &tv); 72 if (ret == 0) { 73 return true; 74 } else if (ret == -1) { 75 if (errno == EINTR || errno == EAGAIN) 76 goto retry; 77 throw new Exception("wtf select"); 78 } else { 79 return false; 80 } 81 } 82 } catch (Exception e) { 83 assert(false, e.msg); 84 } 85 }