1 module yu.timer.eventlooptimer; 2 3 import core.memory; 4 import core.sys.posix.time; 5 6 import std.socket : socket_t; 7 8 import yu.eventloop; 9 import yu.exception : yuCathException; 10 11 @trusted final class EventLoopTimer : EventCallInterface { 12 this(EventLoop loop) { 13 _loop = loop; 14 _event = AsyncEvent(AsynType.TIMER, this); 15 } 16 17 ~this() { 18 if (isActive) { 19 onClose(); 20 } 21 } 22 23 pragma(inline, true) @property bool isActive() nothrow { 24 return _event.isActive; 25 } 26 27 pragma(inline) void setCallBack(CallBack cback) { 28 _callBack = cback; 29 } 30 31 bool start(ulong msesc) { 32 if (isActive() || msesc <= 0) 33 return false; 34 static if (IOMode == IOMode.kqueue || CustomTimer) { 35 _event.timeOut = cast(long) msesc; 36 } else static if (IOMode == IOMode.epoll) { 37 import yu.eventloop.selector.epoll; 38 39 // _timeout = msesc; 40 auto fd = cast(socket_t) timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); 41 _event = AsyncEvent(AsynType.TIMER, this, fd, true); 42 itimerspec its; 43 ulong sec, nsec; 44 sec = msesc / 1000; 45 nsec = (msesc % 1000) * 1_000_000; 46 its.it_value.tv_sec = cast(typeof(its.it_value.tv_sec)) sec; 47 its.it_value.tv_nsec = cast(typeof(its.it_value.tv_nsec)) nsec; 48 its.it_interval.tv_sec = its.it_value.tv_sec; 49 its.it_interval.tv_nsec = its.it_value.tv_nsec; 50 int err = timerfd_settime(_event.fd, 0, &its, null); 51 if (err == -1) { 52 import core.sys.posix.unistd; 53 54 close(_event.fd); 55 return false; 56 } 57 } 58 return _loop.addEvent(&_event); 59 } 60 61 pragma(inline) void stop() nothrow { 62 onClose(); 63 } 64 65 protected: 66 override void onRead() nothrow { 67 static if (IOMode == IO_MODE.epoll) { 68 import core.sys.posix.unistd; 69 70 ulong value; 71 read(_event.fd, &value, 8); 72 } 73 if (_callBack) { 74 _callBack(); 75 } else { 76 onClose(); 77 } 78 } 79 80 override void onWrite() nothrow { 81 } 82 83 override void onClose() nothrow { 84 if (!isActive) 85 return; 86 _loop.delEvent(&_event); 87 static if (IOMode == IO_MODE.epoll) { 88 import core.sys.posix.unistd; 89 90 close(_event.fd); 91 } 92 } 93 94 private: 95 // ulong _timeout; 96 CallBack _callBack; 97 AsyncEvent _event; 98 EventLoop _loop; 99 } 100 101 unittest { 102 import std.stdio; 103 import std.datetime; 104 import yu.memory.gc; 105 import yu.exception; 106 107 EventLoop loop = new EventLoop(); 108 109 EventLoopTimer tm = new EventLoopTimer(loop); 110 111 int cout = -1; 112 ulong time; 113 114 void timeout() nothrow { 115 yuCathException((){ 116 writeln("time : ", Clock.currTime().toSimpleString()); 117 ++cout; 118 if (cout == 0) { 119 time = Clock.currTime().toUnixTime!long(); 120 return; 121 } 122 123 ++time; 124 assert(time == Clock.currTime().toUnixTime!long()); 125 126 if (cout > 5) { 127 writeln("loop stop!!!"); 128 tm.stop(); 129 loop.stop(); 130 } 131 }()); 132 } 133 134 tm.setCallBack(&timeout); 135 136 tm.start(1000); 137 138 loop.run(); 139 140 gcFree(tm); 141 gcFree(loop); 142 }