public TimerHandler(Notifier n, int milliseconds) { int i; atTime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000 + milliseconds; notifier = (Notifier)n; isCancelled = false; /* * Add the event to the queue in the correct position (ordered by * event firing time). * * NOTE: it's very important that if two timer handlers have the * same atTime, the newer timer handler always goes after the * older handler in the list. See comments in * Notifier.TimerEvent.processEvent() for details. */ lock (notifier) { generation = notifier.TimerGeneration; for (i = 0; i < notifier.TimerList.Count; i++) { TimerHandler q = (TimerHandler)notifier.TimerList[i]; if (atTime < q.atTime) { break; } } notifier.TimerList.Insert(i, this); if (System.Threading.Thread.CurrentThread != notifier.PrimaryThread) { System.Threading.Monitor.PulseAll(notifier); } } }
public int doOneEvent(int flags) // Miscellaneous flag values: may be any // combination of TCL.DONT_WAIT, // TCL.WINDOW_EVENTS, TCL.FILE_EVENTS, // TCL.TIMER_EVENTS, TCL.IDLE_EVENTS, // or others defined by event sources. { int result = 0; // No event flags is equivalent to TCL_ALL_EVENTS. if ((flags & TCL.ALL_EVENTS) == 0) { flags |= TCL.ALL_EVENTS; } // The core of this procedure is an infinite loop, even though // we only service one event. The reason for this is that we // may be processing events that don't do anything inside of Tcl. while (true) { // If idle events are the only things to service, skip the // main part of the loop and go directly to handle idle // events (i.e. don't wait even if TCL_DONT_WAIT isn't set). if ((flags & TCL.ALL_EVENTS) == TCL.IDLE_EVENTS) { return(serviceIdle()); } long sysTime = (System.DateTime.Now.Ticks - 621355968000000000) / 10000; // If some timers have been expired, queue them into the // event queue. We can't process expired times right away, // because there may already be other events on the queue. if (!TimerPending && (TimerList.Count > 0)) { TimerHandler h = (TimerHandler)TimerList[0]; if (h.atTime <= sysTime) { TimerEvent Tevent = new TimerEvent(); Tevent.notifier = this; QueueEvent(Tevent, TCL.QUEUE.TAIL); TimerPending = true; } } // Service a queued event, if there are any. if (serviceEvent(flags) != 0) { result = 1; break; } // There is no event on the queue. Check for idle events. if ((flags & TCL.IDLE_EVENTS) != 0) { if (serviceIdle() != 0) { result = 1; break; } } if ((flags & TCL.DONT_WAIT) != 0) { break; } // We don't have any event to service. We'll wait if // TCL.DONT_WAIT. When the following wait() call returns, // one of the following things may happen: // // (1) waitTime milliseconds has elasped (if waitTime != 0); // // (2) The primary notifier has been notify()'ed by other threads: // (a) an event is queued by queueEvent(). // (b) a timer handler was created by new TimerHandler(); // (c) an idle handler was created by new IdleHandler(); // (3) We receive an InterruptedException. // try { // Don't acquire the monitor until we are about to wait // for notification from another thread. It is critical // that this entire method not be synchronized since // a call to processEvent via serviceEvent could take // a very long time. We don't want the monitor held // during that time since that would force calls to // queueEvent in other threads to wait. lock (this) { if (TimerList.Count > 0) { TimerHandler h = (TimerHandler)TimerList[0]; long waitTime = h.atTime - sysTime; if (waitTime > 0) { System.Threading.Monitor.Wait(this, TimeSpan.FromMilliseconds(waitTime)); } } else { System.Threading.Monitor.Wait(this); } } // synchronized (this) } catch (System.Threading.ThreadInterruptedException e) { // We ignore any InterruptedException and loop continuously // until we receive an event. } } return(result); }