Example #1
0
 // 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);
         }
     }
 }
Example #2
0
 // 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");
         }
     }
 }
Example #3
0
        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;
        }
Example #4
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);
            }
        }
Example #5
0
        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);
        }
Example #6
0
 public bool DeleteEvent(TclEvent evt)
 {
     throw new TclRuntimeError("The Notifier.deleteEvent() method should not be called");
 }