/SS14.Server/Timing/TimerQueueTimer.cs

https://gitlab.com/matt81093/space-station-14 · C# · 213 lines · 212 code · 1 blank · 0 comment · 10 complexity · 285fc722d43f1dae3255d2f085293e1a MD5 · raw file

  1. using System;
  2. using System.ComponentModel;
  3. using System.Runtime.InteropServices;
  4. using System.Threading;
  5. namespace SS14.Server.Timing
  6. {
  7. public enum TimerQueueTimerFlags : uint
  8. {
  9. ExecuteDefault = 0x0000,
  10. ExecuteInTimerThread = 0x0020,
  11. ExecuteInIoThread = 0x0001,
  12. ExecuteInPersistentThread = 0x0080,
  13. ExecuteLongFunction = 0x0010,
  14. ExecuteOnlyOnce = 0x0008,
  15. TransferImpersonation = 0x0100,
  16. }
  17. public delegate void Win32WaitOrTimerCallback(
  18. IntPtr lpParam,
  19. [MarshalAs(UnmanagedType.U1)]bool bTimedOut);
  20. static public class TQTimerWin32
  21. {
  22. [DllImport("kernel32.dll", SetLastError = true)]
  23. public extern static IntPtr CreateTimerQueue();
  24. [DllImport("kernel32.dll", SetLastError = true)]
  25. public extern static bool DeleteTimerQueue(IntPtr timerQueue);
  26. [DllImport("kernel32.dll", SetLastError = true)]
  27. public extern static bool DeleteTimerQueueEx(IntPtr timerQueue, IntPtr completionEvent);
  28. [DllImport("kernel32.dll", SetLastError = true)]
  29. public extern static bool CreateTimerQueueTimer(
  30. out IntPtr newTimer,
  31. IntPtr timerQueue,
  32. Win32WaitOrTimerCallback callback,
  33. IntPtr userState,
  34. uint dueTime,
  35. uint period,
  36. TimerQueueTimerFlags flags);
  37. [DllImport("kernel32.dll", SetLastError = true)]
  38. public extern static bool ChangeTimerQueueTimer(
  39. IntPtr timerQueue,
  40. ref IntPtr timer,
  41. uint dueTime,
  42. uint period);
  43. [DllImport("kernel32.dll", SetLastError = true)]
  44. public extern static bool DeleteTimerQueueTimer(
  45. IntPtr timerQueue,
  46. IntPtr timer,
  47. IntPtr completionEvent);
  48. }
  49. public class TimerQueue : IDisposable,IMainLoopTimer
  50. {
  51. public IntPtr Handle { get; private set; }
  52. public static TimerQueue Default { get; private set; }
  53. static TimerQueue()
  54. {
  55. Default = new TimerQueue(IntPtr.Zero);
  56. }
  57. private TimerQueue(IntPtr handle)
  58. {
  59. Handle = handle;
  60. }
  61. public TimerQueue()
  62. {
  63. Handle = TQTimerWin32.CreateTimerQueue();
  64. if (Handle == IntPtr.Zero)
  65. {
  66. throw new Win32Exception(Marshal.GetLastWin32Error(), "Error creating timer queue.");
  67. }
  68. }
  69. ~TimerQueue()
  70. {
  71. Dispose(false);
  72. }
  73. public TimerQueueTimer CreateTimer(
  74. TimerCallback callback,
  75. object state,
  76. uint dueTime,
  77. uint period)
  78. {
  79. return CreateTimer(callback, state, dueTime, period, TimerQueueTimerFlags.ExecuteDefault);
  80. }
  81. public TimerQueueTimer CreateTimer(
  82. TimerCallback callback,
  83. object state,
  84. uint dueTime,
  85. uint period,
  86. TimerQueueTimerFlags flags)
  87. {
  88. return new TimerQueueTimer(this, callback, state, dueTime, period, flags);
  89. }
  90. public TimerQueueTimer CreateOneShot(
  91. TimerCallback callback,
  92. object state,
  93. uint dueTime)
  94. {
  95. return CreateOneShot(callback, state, dueTime, TimerQueueTimerFlags.ExecuteDefault);
  96. }
  97. public TimerQueueTimer CreateOneShot(
  98. TimerCallback callback,
  99. object state,
  100. uint dueTime,
  101. TimerQueueTimerFlags flags)
  102. {
  103. return CreateTimer(callback, state, dueTime, 0, (flags | TimerQueueTimerFlags.ExecuteOnlyOnce));
  104. }
  105. private IntPtr CompletionEventHandle = new IntPtr(-1);
  106. public void Dispose()
  107. {
  108. Dispose(true);
  109. GC.SuppressFinalize(this);
  110. }
  111. public void Dispose(WaitHandle completionEvent)
  112. {
  113. CompletionEventHandle = completionEvent.SafeWaitHandle.DangerousGetHandle();
  114. Dispose();
  115. }
  116. private bool Disposed = false;
  117. protected virtual void Dispose(bool disposing)
  118. {
  119. if (!Disposed)
  120. {
  121. if (Handle != IntPtr.Zero)
  122. {
  123. bool rslt = TQTimerWin32.DeleteTimerQueueEx(Handle, CompletionEventHandle);
  124. if (!rslt)
  125. {
  126. int err = Marshal.GetLastWin32Error();
  127. throw new Win32Exception(err, "Error disposing timer queue");
  128. }
  129. }
  130. Disposed = true;
  131. }
  132. }
  133. public Object CreateMainLoopTimer(MainServerLoop mainLoop, uint period)
  134. {
  135. return CreateTimer((s) => {mainLoop();}, null, 0, period);
  136. }
  137. }
  138. public class TimerQueueTimer : IDisposable
  139. {
  140. private TimerQueue MyQueue;
  141. private TimerCallback Callback;
  142. private Win32WaitOrTimerCallback win32WaitOrTimerCallback;
  143. private object UserState;
  144. private IntPtr Handle;
  145. internal TimerQueueTimer(
  146. TimerQueue queue,
  147. TimerCallback cb,
  148. object state,
  149. uint dueTime,
  150. uint period,
  151. TimerQueueTimerFlags flags)
  152. {
  153. MyQueue = queue;
  154. Callback = cb;
  155. win32WaitOrTimerCallback = TimerCallback;
  156. UserState = state;
  157. bool rslt = TQTimerWin32.CreateTimerQueueTimer(
  158. out Handle,
  159. MyQueue.Handle,
  160. win32WaitOrTimerCallback,
  161. IntPtr.Zero,
  162. dueTime,
  163. period,
  164. flags);
  165. if (!rslt)
  166. {
  167. throw new Win32Exception(Marshal.GetLastWin32Error(), "Error creating timer.");
  168. }
  169. }
  170. ~TimerQueueTimer()
  171. {
  172. Dispose(false);
  173. }
  174. public void Change(uint dueTime, uint period)
  175. {
  176. bool rslt = TQTimerWin32.ChangeTimerQueueTimer(MyQueue.Handle, ref Handle, dueTime, period);
  177. if (!rslt)
  178. {
  179. throw new Win32Exception(Marshal.GetLastWin32Error(), "Error changing timer.");
  180. }
  181. }
  182. private void TimerCallback(IntPtr state, bool bExpired)
  183. {
  184. Callback(UserState);
  185. }
  186. public void Dispose()
  187. {
  188. Dispose(true);
  189. GC.SuppressFinalize(this);
  190. }
  191. private IntPtr completionEventHandle = new IntPtr(-1);
  192. public void Dispose(WaitHandle completionEvent)
  193. {
  194. completionEventHandle = completionEvent.SafeWaitHandle.DangerousGetHandle();
  195. this.Dispose();
  196. }
  197. private bool disposed = false;
  198. protected virtual void Dispose(bool disposing)
  199. {
  200. if (!disposed)
  201. {
  202. bool rslt = TQTimerWin32.DeleteTimerQueueTimer(MyQueue.Handle,
  203. Handle, completionEventHandle);
  204. if (!rslt)
  205. {
  206. throw new Win32Exception(Marshal.GetLastWin32Error(), "Error deleting timer.");
  207. }
  208. disposed = true;
  209. }
  210. }
  211. }
  212. }