Queue factory. Always synchronized.
internal static Queue GetOrCreateQueue(int durationMilliseconds) { if (durationMilliseconds == Timeout.Infinite) { return new InfiniteTimerQueue(); } if (durationMilliseconds < 0) { throw new ArgumentOutOfRangeException(nameof(durationMilliseconds)); } TimerQueue queue; WeakReference weakQueue = (WeakReference)s_QueuesCache[durationMilliseconds]; if (weakQueue == null || (queue = (TimerQueue)weakQueue.Target) == null) { lock (s_NewQueues) { weakQueue = (WeakReference)s_QueuesCache[durationMilliseconds]; if (weakQueue == null || (queue = (TimerQueue)weakQueue.Target) == null) { queue = new TimerQueue(durationMilliseconds); weakQueue = new WeakReference(queue); s_NewQueues.AddLast(weakQueue); s_QueuesCache[durationMilliseconds] = weakQueue; // Take advantage of this lock to periodically scan the table for garbage. if (++s_CacheScanIteration % c_CacheScanPerIterations == 0) { List<int> garbage = new List<int>(); foreach (DictionaryEntry pair in s_QueuesCache) { if (((WeakReference)pair.Value).Target == null) { garbage.Add((int)pair.Key); } } for (int i = 0; i < garbage.Count; i++) { s_QueuesCache.Remove(garbage[i]); } } } } } return queue; }
internal void Close() { site.Close(); // Can't call AppDomain.Unload() from a user thread. TimerThread.GetOrCreateQueue(0).CreateTimer(new TimerThread.Callback(CloseAppDomainCallback), appDomainIndex); GC.SuppressFinalize(this); }