1 /* 2 * Geario - A cross-platform abstraction library with asynchronous I/O. 3 * 4 * Copyright (C) 2021-2022 Kerisy.com 5 * 6 * Website: https://www.kerisy.com 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module geario.util.Timer; 13 14 import geario.event; 15 import geario.event.timer; 16 import geario.logging; 17 import geario.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 log.error("the Timer Read is Error: ", this.ErrorMessage); 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 (GEAR_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 (GEAR_DEBUG) 206 Trace("handler thread id: ", thisThreadID()); 207 AbstractNativeTimer timer = cast(AbstractNativeTimer)(param); 208 assert(timer !is null); 209 timer.OnTick(); 210 } 211 }