public static Timer CreateTimer(ClrSyncManager manager, Original::TimerCallback timerCallback, object state, TimeSpan dueTime, TimeSpan period) { TimerRoutineArg argument = new TimerRoutineArg(); argument.callback = timerCallback; argument.state = state; argument.dueTime = dueTime; argument.Period = period; argument.selfSemaphore = new Semaphore(0, 1); argument.parentSemaphore = new Semaphore(0, 1); argument.disposed = false; argument.changed = true; Timer ret = new Timer(TimerCreateWrapper, argument, 0, Timeout.Infinite); argument.timer = ret; timer2tra.Add(ret, argument); int child = manager.TaskFork(); argument.parentSemaphore.WaitOne(); manager.RegisterTaskSemaphore(child, argument.selfSemaphore, false); manager.TaskResume(child); return(ret); }
// dueTime: the amount of time to delay before callback is invoked, in milliseconds. // Specify Timeout.Infinite to prevent the timer from starting. // Specify zero (0) to start the timer immediately. // period: The time interval between invocations of callback, in milliseconds. // Specify Timeout.Infinite to disable periodic signaling. // The method specified for callback should be reentrant, because it is called on ThreadPool threads. // The method can be executed simultaneously on two thread pool threads if the timer interval is less // than the time required to execute the method, or if all thread pool threads are in use and the method // is queued multiple times. public static void TimerCreateWrapper(object start) { try { TimerRoutineArg argument = (TimerRoutineArg)start; argument.inLoop = true; argument.changed = false; argument.parentSemaphore.Release(); ClrSyncManager manager = ClrSyncManager.SyncManager; manager.ThreadBegin(argument.selfSemaphore); Exception exception = null; while (true) { manager.SetMethodInfo("Timer.read"); manager.SyncVarAccess(argument.timer, MSyncVarOp.RWVAR_READWRITE); manager.CommitSyncVarAccess(); if (timer2tra[argument.timer].disposed) { // the timer only goes away when it is disposed of // it may be disabled, but a Change can reenable it break; } manager.TaskYield(); // until fairness deals with unbounded thread creation manager.TaskYield(); // we yield twice if (!argument.dueTime.Equals(TimeSpan.FromTicks(Timeout.Infinite))) { MChessChess.LeaveChess(); try { argument.callback(argument.state); } catch (Exception e) // catch recoverable exception in monitored code { exception = e; } MChessChess.EnterChess(); // If period is zero (0) or Infinite and dueTime is not Infinite, callback is invoked once; // the periodic behavior of the timer is disabled, but can be re-enabled using the Change method. } if (exception != null) { break; } if (argument.changed) { argument.changed = false; continue; } if (argument.Period.Equals(TimeSpan.FromTicks(Timeout.Infinite)) || argument.Period.Equals(TimeSpan.FromTicks(0))) { break; } } argument.inLoop = false; if (timer2tra[argument.timer].disposed) { timer2tra.Remove(argument.timer); } if (manager.BreakDeadlockMode) { MChessChess.WakeNextDeadlockedThread(false, true); } else if (exception == null) { manager.ThreadEnd(System.Threading.Thread.CurrentThread); } else { manager.Shutdown(exception); } } catch (Exception e) // catch fatal error in our code { ClrSyncManager manager = ClrSyncManager.SyncManager; manager.Shutdown(e); } }