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