// One of TCL.QUEUE_TAIL, TCL.QUEUE_HEAD or TCL.QUEUE_MARK. public void QueueEvent(TclEvent evt, TCL.QUEUE position) { lock (this) { evt.notifier = this; if (position == TCL.QUEUE.TAIL) { // Append the event on the end of the queue. evt.next = null; if (_firstEvent == null) { _firstEvent = evt; } else { _lastEvent.next = evt; } _lastEvent = evt; } else if (position == TCL.QUEUE.HEAD) { // Push the event on the head of the queue. evt.next = _firstEvent; if (_firstEvent == null) { _lastEvent = evt; } _firstEvent = evt; } else if (position == TCL.QUEUE.MARK) { // Insert the event after the current marker event and advance the marker to the new event. if (_markerEvent == null) { evt.next = _firstEvent; _firstEvent = evt; } else { evt.next = _markerEvent.next; _markerEvent.next = evt; } _markerEvent = evt; if (evt.next == null) { _lastEvent = evt; } } else { // Wrong flag. throw new TclRuntimeError("wrong position \"" + position + "\", must be TCL.QUEUE_HEAD, TCL.QUEUE_TAIL or TCL.QUEUE_MARK"); } if (Thread.CurrentThread != PrimaryThread) { Monitor.PulseAll(this); } } }
// The deleter that checks whether an event should be removed. public void deleteEvents(IEventDeleter deleter) { lock (this) { TclEvent servicedEvent = null; // Handle the special case of deletion of a single event that was just processed by the serviceEvent() method. if (deleter == this) { servicedEvent = _servicedEvent; if (servicedEvent == null) { throw new TclRuntimeError("servicedEvent was not set by serviceEvent()"); } _servicedEvent = null; } for (TclEvent prev = null, evt = _firstEvent; evt != null; evt = evt.next) { if ((servicedEvent == null && deleter.DeleteEvent(evt)) || evt == servicedEvent) { if (evt == _firstEvent) { _firstEvent = evt.next; } else { prev.next = evt.next; } if (evt.next == null) { _lastEvent = prev; } if (evt == _markerEvent) { _markerEvent = prev; } if (evt == servicedEvent) { servicedEvent = null; break; // Just service this one event in the special case } } else { prev = evt; } } if (servicedEvent != null) { throw new TclRuntimeError("servicedEvent was not removed from the queue"); } } }
private int _refCount; // Reference count of the notifier. It's used to tell when a notifier is no longer needed. private Notifier(Thread primaryThread) { PrimaryThread = primaryThread; _firstEvent = null; _lastEvent = null; _markerEvent = null; TimerList = new ArrayList(10); TimerGeneration = 0; IdleList = new ArrayList(10); IdleGeneration = 0; TimerPending = false; _refCount = 0; }
private TclEvent getAvailableEvent(TclEvent skipEvent) // Indicates that the given event should not // be returned. This argument can be null. { lock (this) { TclEvent evt; for (evt = _firstEvent; evt != null; evt = evt.next) { if ((evt.isProcessing == false) && (evt.isProcessed == false) && (evt != skipEvent)) { return(evt); } } return(null); } }
internal int serviceEvent(int flags) // Indicates what events should be processed. // May be any combination of TCL.WINDOW_EVENTS // TCL.FILE_EVENTS, TCL.TIMER_EVENTS, or other // flags defined elsewhere. Events not // matching this will be skipped for processing // later. { TclEvent evt; // No event flags is equivalent to TCL_ALL_EVENTS. if ((flags & TCL.ALL_EVENTS) == 0) { flags |= TCL.ALL_EVENTS; } // Loop through all the events in the queue until we find one // that can actually be handled. evt = null; while ((evt = getAvailableEvent(evt)) != null) { // Call the handler for the event. If it actually handles the // event then free the storage for the event. There are two // tricky things here, both stemming from the fact that the event // code may be re-entered while servicing the event: // // 1. Set the "isProcessing" field to true. This is a signal to // ourselves that we shouldn't reexecute the handler if the // event loop is re-entered. // 2. When freeing the event, must search the queue again from the // front to find it. This is because the event queue could // change almost arbitrarily while handling the event, so we // can't depend on pointers found now still being valid when // the handler returns. evt.isProcessing = true; if (evt.processEvent(flags) != 0) { evt.isProcessed = true; // Don't allocate/grab the monitor for the event unless sync() // has been called in another thread. This is thread safe // since sync() checks the isProcessed flag before calling wait. if (evt.needsNotify) { lock (evt) { System.Threading.Monitor.PulseAll(evt); } } // Remove this specific event from the queue _servicedEvent = evt; deleteEvents(this); return(1); } else { // The event wasn't actually handled, so we have to // restore the isProcessing field to allow the event to be // attempted again. evt.isProcessing = false; } // The handler for this event asked to defer it. Just go on to // the next event. continue; } return(0); }
public bool DeleteEvent(TclEvent evt) { throw new TclRuntimeError("The Notifier.deleteEvent() method should not be called"); }