public void deleteEvents(EventDeleter deleter) // The deleter that checks whether an event // should be removed. { lock (this) { TclEvent evt, prev; 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 = this.servicedEvent; if (servicedEvent == null) { throw new TclRuntimeError("servicedEvent was not set by serviceEvent()"); } this.servicedEvent = null; } for (prev = null, evt = firstEvent; evt != null; evt = evt.next) { if (((servicedEvent == null) && (deleter.deleteEvent(evt) == 1)) || (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 Notifier(System.Threading.Thread primaryTh) { primaryThread = primaryTh; 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); } }
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 int deleteEvent(TclEvent evt) { throw new TclRuntimeError("The Notifier.deleteEvent() method should not be called"); }
public void deleteEvents(EventDeleter deleter) // The deleter that checks whether an event // should be removed. { lock (this) { TclEvent evt, prev; 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 = this.servicedEvent; if (servicedEvent == null) throw new TclRuntimeError("servicedEvent was not set by serviceEvent()"); this.servicedEvent = null; } for (prev = null, evt = firstEvent; evt != null; evt = evt.next) { if (((servicedEvent == null) && (deleter.deleteEvent(evt) == 1)) || (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"); } } }
public void queueEvent(TclEvent evt, int position) // One of TCL.QUEUE_TAIL, // TCL.QUEUE_HEAD or TCL.QUEUE_MARK. { 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 (System.Threading.Thread.CurrentThread != primaryThread) { System.Threading.Monitor.PulseAll(this); } } }
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); }