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