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.ConsoleLogger; 17 import hunt.Exceptions; 18 19 import core.time; 20 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.errorMessage); 60 } 61 } 62 } 63 64 } 65 66 // dfmt off 67 version (HAVE_IOCP) : 68 // dfmt on 69 70 import std.datetime; 71 import std.exception; 72 import std.process; 73 74 import core.sys.windows.windows; 75 import core.thread; 76 import core.time; 77 78 /** 79 */ 80 abstract class AbstractNativeTimer : ITimer { 81 protected bool _isActive = false; 82 protected size_t _interval = 1000; 83 84 /// Timer tick handler 85 TickedEventHandler ticked; 86 87 this() { 88 this(1000); 89 } 90 91 this(size_t interval) { 92 this.interval = interval; 93 } 94 95 this(Duration duration) { 96 this.interval = duration; 97 } 98 99 /// 100 @property bool isActive() { 101 return _isActive; 102 } 103 104 /// in ms 105 @property size_t interval() { 106 return _interval; 107 } 108 109 /// ditto 110 @property ITimer interval(size_t v) { 111 _interval = v; 112 return this; 113 } 114 115 /// ditto 116 @property ITimer interval(Duration duration) { 117 _interval = cast(size_t) duration.total!("msecs"); 118 return this; 119 } 120 121 /// The handler will be handled in another thread. 122 ITimer onTick(TickedEventHandler handler) { 123 this.ticked = handler; 124 return this; 125 } 126 127 /// immediately: true to call first event immediately 128 /// once: true to call timed event only once 129 abstract void start(bool immediately = false, bool once = false); 130 void start(uint interval) { 131 this.interval = interval; 132 start(); 133 } 134 135 abstract void stop(); 136 137 abstract void reset(bool immediately = false, bool once = false); 138 139 void reset(size_t interval) { 140 this.interval = interval; 141 reset(); 142 } 143 144 void reset(Duration duration) { 145 this.interval = duration; 146 reset(); 147 } 148 149 protected void onTick() { 150 // trace("tick thread id: ", getTid()); 151 if (ticked !is null) 152 ticked(this); 153 } 154 } 155 156 /** 157 * See_also: 158 * https://www.codeproject.com/articles/146617/simple-c-timer-wrapper 159 * https://msdn.microsoft.com/en-us/library/ms687003(v=vs.85) 160 */ 161 class NativeTimer : AbstractNativeTimer { 162 protected HANDLE _handle = null; 163 164 this() { 165 super(1000); 166 } 167 168 this(size_t interval) { 169 super(interval); 170 } 171 172 this(Duration duration) { 173 super(duration); 174 } 175 176 /// immediately: true to call first event immediately 177 /// once: true to call timed event only once 178 override void start(bool immediately = false, bool once = false) { 179 version (HUNT_DEBUG) 180 trace("main thread id: ", thisThreadID()); 181 if (_isActive) 182 return; 183 BOOL r = CreateTimerQueueTimer(&_handle, null, &timerProc, 184 cast(PVOID) this, immediately ? 0 : cast(int) interval, once ? 0 185 : cast(int) interval, WT_EXECUTEINTIMERTHREAD); 186 assert(r != 0); 187 _isActive = true; 188 } 189 190 override void stop() { 191 if (_isActive) { 192 DeleteTimerQueueTimer(null, _handle, null); 193 _isActive = false; 194 } 195 } 196 197 override void reset(bool immediately = false, bool once = false) { 198 if (_isActive) { 199 assert(ChangeTimerQueueTimer(null, _handle, immediately ? 0 200 : cast(int) interval, once ? 0 : cast(int) interval) != 0); 201 } 202 } 203 204 /// https://msdn.microsoft.com/en-us/library/ms687066(v=vs.85) 205 extern (Windows) static private void timerProc(PVOID param, bool timerCalled) { 206 version (HUNT_DEBUG) 207 trace("handler thread id: ", thisThreadID()); 208 AbstractNativeTimer timer = cast(AbstractNativeTimer)(param); 209 assert(timer !is null); 210 timer.onTick(); 211 } 212 }