Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
TimerThread.cs
Go to the documentation of this file.
6
7namespace System.Net;
8
9internal static class TimerThread
10{
11 internal abstract class Queue
12 {
13 private readonly int _durationMilliseconds;
14
16
21
22 internal abstract Timer CreateTimer(Callback callback, object context);
23 }
24
25 internal abstract class Timer : IDisposable
26 {
27 private readonly int _startTimeMilliseconds;
28
29 private readonly int _durationMilliseconds;
30
32
34
35 internal abstract bool HasExpired { get; }
36
42
43 internal abstract bool Cancel();
44
45 public void Dispose()
46 {
47 Cancel();
48 }
49 }
50
51 internal delegate void Callback(Timer timer, int timeNoticed, object context);
52
53 private enum TimerThreadState
54 {
55 Idle,
56 Running,
58 }
59
60 private sealed class TimerQueue : Queue
61 {
63
64 private readonly TimerNode _timers;
65
68 {
69 _timers = new TimerNode();
70 _timers.Next = _timers;
71 _timers.Prev = _timers;
72 }
73
74 internal override Timer CreateTimer(Callback callback, object context)
75 {
76 TimerNode timerNode = new TimerNode(callback, context, base.Duration, _timers);
77 bool flag = false;
79 {
80 if (_timers.Next == _timers)
81 {
82 if (_thisHandle == IntPtr.Zero)
83 {
85 }
86 flag = true;
87 }
88 timerNode.Next = _timers;
89 timerNode.Prev = _timers.Prev;
90 _timers.Prev.Next = timerNode;
91 _timers.Prev = timerNode;
92 }
93 if (flag)
94 {
95 Prod();
96 }
97 return timerNode;
98 }
99
100 internal bool Fire(out int nextExpiration)
101 {
102 TimerNode next;
103 do
104 {
105 next = _timers.Next;
106 if (next != _timers)
107 {
108 continue;
109 }
110 lock (_timers)
111 {
112 next = _timers.Next;
113 if (next == _timers)
114 {
115 if (_thisHandle != IntPtr.Zero)
116 {
117 ((GCHandle)_thisHandle).Free();
119 }
120 nextExpiration = 0;
121 return false;
122 }
123 }
124 }
125 while (next.Fire());
127 return true;
128 }
129 }
130
131 private sealed class InfiniteTimerQueue : Queue
132 {
134 : base(-1)
135 {
136 }
137
138 internal override Timer CreateTimer(Callback callback, object context)
139 {
140 return new InfiniteTimer();
141 }
142 }
143
144 private sealed class TimerNode : Timer
145 {
146 private enum TimerState
147 {
148 Ready,
149 Fired,
150 Cancelled,
152 }
153
155
156 private Callback _callback;
157
158 private object _context;
159
160 private readonly object _queueLock;
161
163
165
166 internal override bool HasExpired => _timerState == TimerState.Fired;
167
169 {
170 get
171 {
172 return _next;
173 }
174 set
175 {
176 _next = value;
177 }
178 }
179
181 {
182 get
183 {
184 return _prev;
185 }
186 set
187 {
188 _prev = value;
189 }
190 }
191
192 internal TimerNode(Callback callback, object context, int durationMilliseconds, object queueLock)
194 {
195 if (callback != null)
196 {
197 _callback = callback;
198 _context = context;
199 }
200 _timerState = TimerState.Ready;
202 if (System.Net.NetEventSource.Log.IsEnabled())
203 {
204 System.Net.NetEventSource.Info(this, $"TimerThreadTimer#{base.StartTime}", ".ctor");
205 }
206 }
207
208 internal TimerNode()
209 : base(0)
210 {
211 _timerState = TimerState.Sentinel;
212 }
213
214 internal override bool Cancel()
215 {
216 if (_timerState == TimerState.Ready)
217 {
219 {
220 if (_timerState == TimerState.Ready)
221 {
222 Next.Prev = Prev;
223 Prev.Next = Next;
224 Next = null;
225 Prev = null;
226 _callback = null;
227 _context = null;
228 _timerState = TimerState.Cancelled;
229 if (System.Net.NetEventSource.Log.IsEnabled())
230 {
231 System.Net.NetEventSource.Info(this, $"TimerThreadTimer#{base.StartTime} Cancel (success)", "Cancel");
232 }
233 return true;
234 }
235 }
236 }
237 if (System.Net.NetEventSource.Log.IsEnabled())
238 {
239 System.Net.NetEventSource.Info(this, $"TimerThreadTimer#{base.StartTime} Cancel (failure)", "Cancel");
240 }
241 return false;
242 }
243
244 internal bool Fire()
245 {
246 if (_timerState == TimerState.Sentinel && System.Net.NetEventSource.Log.IsEnabled())
247 {
248 System.Net.NetEventSource.Info(this, "TimerQueue tried to Fire a Sentinel.", "Fire");
249 }
250 if (_timerState != 0)
251 {
252 return true;
253 }
254 int tickCount = Environment.TickCount;
255 if (IsTickBetween(base.StartTime, base.Expiration, tickCount))
256 {
257 if (System.Net.NetEventSource.Log.IsEnabled())
258 {
259 System.Net.NetEventSource.Info(this, $"TimerThreadTimer#{base.StartTime}::Fire() Not firing ({base.StartTime} <= {tickCount} < {base.Expiration})", "Fire");
260 }
261 return false;
262 }
263 bool flag = false;
265 {
266 if (_timerState == TimerState.Ready)
267 {
268 if (System.Net.NetEventSource.Log.IsEnabled())
269 {
270 System.Net.NetEventSource.Info(this, $"TimerThreadTimer#{base.StartTime}::Fire() Firing ({base.StartTime} <= {tickCount} >= " + base.Expiration + ")", "Fire");
271 }
272 _timerState = TimerState.Fired;
273 Next.Prev = Prev;
274 Prev.Next = Next;
275 Next = null;
276 Prev = null;
277 flag = _callback != null;
278 }
279 }
280 if (flag)
281 {
282 try
283 {
284 Callback callback = _callback;
285 object context = _context;
286 _callback = null;
287 _context = null;
288 callback(this, tickCount, context);
289 }
290 catch (Exception ex)
291 {
293 {
294 throw;
295 }
296 if (System.Net.NetEventSource.Log.IsEnabled())
297 {
298 System.Net.NetEventSource.Error(this, $"exception in callback: {ex}", "Fire");
299 }
300 }
301 }
302 return true;
303 }
304 }
305
306 private sealed class InfiniteTimer : Timer
307 {
308 private int _cancelled;
309
310 internal override bool HasExpired => false;
311
312 internal InfiniteTimer()
313 : base(-1)
314 {
315 }
316
317 internal override bool Cancel()
318 {
319 return Interlocked.Exchange(ref _cancelled, 1) == 0;
320 }
321 }
322
324
326
327 private static int s_threadState = 0;
328
329 private static readonly AutoResetEvent s_threadReadyEvent = new AutoResetEvent(initialState: false);
330
331 private static readonly ManualResetEvent s_threadShutdownEvent = new ManualResetEvent(initialState: false);
332
334
335 private static int s_cacheScanIteration;
336
337 private static readonly Hashtable s_queuesCache = new Hashtable();
338
340 {
341 if (durationMilliseconds == -1)
342 {
343 return new InfiniteTimerQueue();
344 }
345 if (durationMilliseconds < 0)
346 {
347 throw new ArgumentOutOfRangeException("durationMilliseconds");
348 }
349 object key = durationMilliseconds;
352 if (weakReference == null || (timerQueue = (TimerQueue)weakReference.Target) == null)
353 {
355 {
357 if (weakReference == null || (timerQueue = (TimerQueue)weakReference.Target) == null)
358 {
361 s_newQueues.AddLast(weakReference);
363 if (++s_cacheScanIteration % 32 == 0)
364 {
367 while (enumerator.MoveNext())
368 {
370 if (((WeakReference)entry.Value).Target == null)
371 {
372 list.Add(entry.Key);
373 }
374 }
375 for (int i = 0; i < list.Count; i++)
376 {
377 s_queuesCache.Remove(list[i]);
378 }
379 }
380 }
381 }
382 }
383 return timerQueue;
384 }
385
386 private static void Prod()
387 {
388 s_threadReadyEvent.Set();
390 {
392 thread.IsBackground = true;
393 thread.Name = ".NET Network Timer";
394 thread.Start();
395 }
396 }
397
398 private static void ThreadProc()
399 {
400 lock (s_queues)
401 {
403 {
404 return;
405 }
406 bool flag = true;
407 while (flag)
408 {
409 try
410 {
411 s_threadReadyEvent.Reset();
412 while (true)
413 {
414 if (s_newQueues.Count > 0)
415 {
417 {
418 for (LinkedListNode<WeakReference> first = s_newQueues.First; first != null; first = s_newQueues.First)
419 {
420 s_newQueues.Remove(first);
421 s_queues.AddLast(first);
422 }
423 }
424 }
425 int tickCount = Environment.TickCount;
426 int num = 0;
427 bool flag2 = false;
429 while (linkedListNode != null)
430 {
432 if (timerQueue == null)
433 {
435 s_queues.Remove(linkedListNode);
436 linkedListNode = next;
437 continue;
438 }
439 if (timerQueue.Fire(out var nextExpiration) && (!flag2 || IsTickBetween(tickCount, num, nextExpiration)))
440 {
441 num = nextExpiration;
442 flag2 = true;
443 }
445 }
447 int num2 = (int)((!flag2) ? 30000 : (IsTickBetween(tickCount, num, tickCount2) ? (Math.Min((uint)(num - tickCount2), 2147483632u) + 15) : 0));
448 if (System.Net.NetEventSource.Log.IsEnabled())
449 {
450 System.Net.NetEventSource.Info(null, $"Waiting for {num2}ms", "ThreadProc");
451 }
453 if (num3 == 0)
454 {
455 if (System.Net.NetEventSource.Log.IsEnabled())
456 {
457 System.Net.NetEventSource.Info(null, "Awoke, cause: Shutdown", "ThreadProc");
458 }
459 flag = false;
460 break;
461 }
462 if (System.Net.NetEventSource.Log.IsEnabled())
463 {
464 System.Net.NetEventSource.Info(null, FormattableStringFactory.Create("Awoke, cause {0}", (num3 == 258) ? "Timeout" : "Prod"), "ThreadProc");
465 }
466 if (num3 == 258 && !flag2)
467 {
469 if (!s_threadReadyEvent.WaitOne(0, exitContext: false) || Interlocked.CompareExchange(ref s_threadState, 1, 0) != 0)
470 {
471 flag = false;
472 break;
473 }
474 }
475 }
476 }
477 catch (Exception ex)
478 {
480 {
481 throw;
482 }
483 if (System.Net.NetEventSource.Log.IsEnabled())
484 {
485 System.Net.NetEventSource.Error(null, ex, "ThreadProc");
486 }
487 Thread.Sleep(1000);
488 }
489 }
490 }
491 if (System.Net.NetEventSource.Log.IsEnabled())
492 {
493 System.Net.NetEventSource.Info(null, "Stop", "ThreadProc");
494 }
495 }
496
497 private static bool IsTickBetween(int start, int end, int comparand)
498 {
499 return start <= comparand == end <= comparand != start <= end;
500 }
501}
static int TickCount
static byte Min(byte val1, byte val2)
Definition Math.cs:912
static bool IsFatal(Exception exception)
static readonly System.Net.NetEventSource Log
static void Info(object thisOrContextObject, FormattableString formattableString=null, [CallerMemberName] string memberName=null)
static void Error(object thisOrContextObject, FormattableString formattableString, [CallerMemberName] string memberName=null)
override Timer CreateTimer(Callback callback, object context)
readonly int _durationMilliseconds
Queue(int durationMilliseconds)
Timer CreateTimer(Callback callback, object context)
TimerNode(Callback callback, object context, int durationMilliseconds, object queueLock)
bool Fire(out int nextExpiration)
override Timer CreateTimer(Callback callback, object context)
TimerQueue(int durationMilliseconds)
readonly int _startTimeMilliseconds
Timer(int durationMilliseconds)
readonly int _durationMilliseconds
static readonly AutoResetEvent s_threadReadyEvent
static void ThreadProc()
delegate void Callback(Timer timer, int timeNoticed, object context)
static readonly Hashtable s_queuesCache
static readonly LinkedList< WeakReference > s_queues
static int s_cacheScanIteration
static Queue GetOrCreateQueue(int durationMilliseconds)
static bool IsTickBetween(int start, int end, int comparand)
static readonly LinkedList< WeakReference > s_newQueues
static readonly WaitHandle[] s_threadEvents
static readonly ManualResetEvent s_threadShutdownEvent
static FormattableString Create(string format, params object?[] arguments)
static int CompareExchange(ref int location1, int value, int comparand)
static int Exchange(ref int location1, int value)
static void Sleep(int millisecondsTimeout)
Definition Thread.cs:658
static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout)
static readonly IntPtr Zero
Definition IntPtr.cs:18
static GCHandle Alloc(object? value)
Definition GCHandle.cs:81