1 /* 2 * Hunt - A refined core library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.util.Timer; 13 14 import hunt.event; 15 import hunt.event.timer; 16 import hunt.logging; 17 import hunt.Exceptions; 18 19 import core.time; 20 import std.datetime; 21 22 /** 23 */ 24 class Timer : AbstractTimer { 25 26 this(Selector loop) { 27 super(loop); 28 this.interval = 1000; 29 } 30 31 this(Selector loop, size_t interval) { 32 super(loop); 33 this.interval = interval; 34 } 35 36 this(Selector loop, Duration duration) { 37 super(loop); 38 this.interval = duration; 39 } 40 41 protected: 42 43 override void onRead() { 44 bool canRead = true; 45 while (canRead && _isRegistered) { 46 canRead = readTimer((Object obj) { 47 BaseTypeObject!uint tm = cast(BaseTypeObject!uint) obj; 48 if (tm is null) 49 return; 50 while (tm.data > 0) { 51 if (ticked !is null) 52 ticked(this); 53 tm.data--; 54 } 55 }); 56 if (this.isError) { 57 canRead = false; 58 this.close(); 59 error("the Timer Read is error: ", this.erroString); 60 } 61 } 62 } 63 64 } 65 66 // dfmt off 67 version (HAVE_IOCP) : 68 69 // dfmt on 70 71 import std.datetime; 72 import std.exception; 73 import std.process; 74 75 import hunt.logging; 76 import core.sys.windows.windows; 77 import core.thread; 78 import core.time; 79 80 /** 81 */ 82 abstract class AbstractNativeTimer : ITimer { 83 protected bool _isActive = false; 84 protected size_t _interval = 1000; 85 86 /// Timer tick handler 87 TickedEventHandler ticked; 88 89 this() { 90 this(1000); 91 } 92 93 this(size_t interval) { 94 this.interval = interval; 95 } 96 97 this(Duration duration) { 98 this.interval = duration; 99 } 100 101 /// 102 @property bool isActive() { 103 return _isActive; 104 } 105 106 /// in ms 107 @property size_t interval() { 108 return _interval; 109 } 110 111 /// ditto 112 @property ITimer interval(size_t v) { 113 _interval = v; 114 return this; 115 } 116 117 /// ditto 118 @property ITimer interval(Duration duration) { 119 _interval = cast(size_t) duration.total!("msecs"); 120 return this; 121 } 122 123 /// The handler will be handled in another thread. 124 ITimer onTick(TickedEventHandler handler) { 125 this.ticked = handler; 126 return this; 127 } 128 129 /// immediately: true to call first event immediately 130 /// once: true to call timed event only once 131 abstract void start(bool immediately = false, bool once = false); 132 void start(uint interval) { 133 this.interval = interval; 134 start(); 135 } 136 137 abstract void stop(); 138 139 abstract void reset(bool immediately = false, bool once = false); 140 141 void reset(size_t interval) { 142 this.interval = interval; 143 reset(); 144 } 145 146 void reset(Duration duration) { 147 this.interval = duration; 148 reset(); 149 } 150 151 protected void onTick() { 152 // trace("tick thread id: ", getTid()); 153 if (ticked !is null) 154 ticked(this); 155 } 156 } 157 158 /** 159 * See_also: 160 * https://www.codeproject.com/articles/146617/simple-c-timer-wrapper 161 * https://msdn.microsoft.com/en-us/library/ms687003(v=vs.85) 162 */ 163 class NativeTimer : AbstractNativeTimer { 164 protected HANDLE _handle = null; 165 166 this() { 167 super(1000); 168 } 169 170 this(size_t interval) { 171 super(interval); 172 } 173 174 this(Duration duration) { 175 super(duration); 176 } 177 178 /// immediately: true to call first event immediately 179 /// once: true to call timed event only once 180 override void start(bool immediately = false, bool once = false) { 181 version (HUNT_DEBUG) 182 trace("main thread id: ", thisThreadID()); 183 if (_isActive) 184 return; 185 BOOL r = CreateTimerQueueTimer(&_handle, null, &timerProc, 186 cast(PVOID) this, immediately ? 0 : cast(int) interval, once ? 0 187 : cast(int) interval, WT_EXECUTEINTIMERTHREAD); 188 assert(r != 0); 189 _isActive = true; 190 } 191 192 override void stop() { 193 if (_isActive) { 194 DeleteTimerQueueTimer(null, _handle, null); 195 _isActive = false; 196 } 197 } 198 199 override void reset(bool immediately = false, bool once = false) { 200 if (_isActive) { 201 assert(ChangeTimerQueueTimer(null, _handle, immediately ? 0 202 : cast(int) interval, once ? 0 : cast(int) interval) != 0); 203 } 204 } 205 206 /// https://msdn.microsoft.com/en-us/library/ms687066(v=vs.85) 207 extern (Windows) static private void timerProc(PVOID param, bool timerCalled) { 208 version (HUNT_DEBUG) 209 trace("handler thread id: ", thisThreadID()); 210 AbstractNativeTimer timer = cast(AbstractNativeTimer)(param); 211 assert(timer !is null); 212 timer.onTick(); 213 } 214 }