//
        // Removes a timer from the timer list.
        //

        private static void RemoveTimerFromList(RawTimer tmr) {
            RawTimer next = tmr.next;
            RawTimer prev = tmr.prev;

            prev.next = next;
            next.prev = prev;
        }
        //
        // Inserts a timer at the head of the timer list.
        //

        private static void InsertHeadTimerList(RawTimer head, RawTimer tmr) {
            RawTimer first = head.next;
            
            tmr.next = first;
            tmr.prev = head;
            first.prev = tmr;
            head.next = tmr;
        }
        //
        // Inserts a timer at the tail of the list defined by *head*.
        //

        private static void InsertTailTimerList(RawTimer head, RawTimer tmr) {
            RawTimer tail = head.prev;

            tmr.next = head;
            tmr.prev = tail;
            tail.next = tmr;
            head.prev = tmr;
        }
示例#4
0
        //
        // Removes a timer from the timer list.
        //

        private static void RemoveTimerFromList(RawTimer tmr)
        {
            RawTimer next = tmr.next;
            RawTimer prev = tmr.prev;

            prev.next = next;
            next.prev = prev;
        }
示例#5
0
        //
        // Tries to cancel a raw timer, if it's still active.
        //

        private static bool TryCancelRawTimer(RawTimer tmr)
        {
            if (tmr.parker.TryCancel())
            {
                UnlinkRawTimer(tmr);
                return(true);
            }
            return(false);
        }
示例#6
0
        //
        // Inserts a timer at the tail of the list defined by *head*.
        //

        private static void InsertTailTimerList(RawTimer head, RawTimer tmr)
        {
            RawTimer tail = head.prev;

            tmr.next  = head;
            tmr.prev  = tail;
            tail.next = tmr;
            head.prev = tmr;
        }
示例#7
0
        //
        // Inserts a timer at the head of the timer list.
        //

        private static void InsertHeadTimerList(RawTimer head, RawTimer tmr)
        {
            RawTimer first = head.next;

            tmr.next   = first;
            tmr.prev   = head;
            first.prev = tmr;
            head.next  = tmr;
        }
示例#8
0
        //
        // Enables the unpark callback.
        //

        internal int EnableCallback(int timeout, RawTimer tmr)
        {
            //
            // If the unpark method was already called, return immediately.
            //

            if (state >= 0)
            {
                return(waitStatus);
            }

            toTimer = null;
            if (timeout == 0)
            {
                //
                // If a zero timeout is specified with a timer, we record the
                // current time as *fireTime* in order to support periodic timers.
                //

                if (tmr != null)
                {
                    tmr.fireTime = Environment.TickCount;
                }

                if (TryCancel())
                {
                    return(StParkStatus.Timeout);
                }
            }
            else if (timeout != Timeout.Infinite)
            {
                toTimer = tmr;
                if (timeout < 0)
                {
                    TimerList.SetPeriodicRawTimer(tmr, timeout & ~(1 << 31));
                }
                else
                {
                    TimerList.SetRawTimer(tmr, timeout);
                }
            }

            //
            // Clear the wait-in-progress bit. If this bit is already cleared,
            // the current thread was already unparked.
            //

            if (!TestAndClearInProgress())
            {
                if (toTimer != null && waitStatus != StParkStatus.Timeout)
                {
                    TimerList.UnlinkRawTimer(tmr);
                }
                return(waitStatus);
            }
            return(StParkStatus.Pending);
        }
        //
        // Constructors.
        //

        public StTimer(bool notificationTimer) {
            if (notificationTimer) {
                tmrEvent = new StNotificationEvent();
            } else {
                tmrEvent = new StSynchronizationEvent();
            }
 
            state = INACTIVE;
            cbparker = new CbParker(TimerCallback);
            timer = new RawTimer(cbparker);        
        }
        //
        // Constructor: registers a take with a blocking queue.
        //

        internal StRegisteredTake(StBlockingQueue <T> queue, StTakeCallback <T> callback,
                                  object cbState, int timeout, bool executeOnce)
        {
            //
            // Validate the arguments.
            //

            if (timeout == 0)
            {
                throw new ArgumentOutOfRangeException("\"timeout\" can not be zero");
            }
            if (callback == null)
            {
                throw new ArgumentOutOfRangeException("\"callback\" must be specified");
            }

            //
            // Initialize the registered take fields.
            //

            this.queue = queue;
            cbparker   = new CbParker(UnparkCallback);
            if ((this.timeout = timeout) != Timeout.Infinite)
            {
                toTimer = new RawTimer(cbparker);
            }
            this.executeOnce = executeOnce;
            this.callback    = callback;
            this.cbState     = cbState;

            //
            // Execute the TryTakePrologue prologue on the queue.
            //

            waitNode = queue.TryTakePrologue(cbparker, StParkStatus.Success, out dataItem,
                                             ref hint);

            //
            // Set the state to active and enable the unpark callback.
            //

            state = ACTIVE;
            int ws;

            if ((ws = cbparker.EnableCallback(timeout, toTimer)) != StParkStatus.Pending)
            {
                //
                // The take operation was already accomplished. To prevent
                // uncontrolled reentrancy, the unpark callback is executed inline.
                //

                UnparkCallback(ws);
            }
        }
示例#11
0
        //
        // Adds a raw timer to the timer list.
        //

        private static void SetRawTimerWorker(RawTimer timer, int delay)
        {
            //
            // Set the next fire time.
            //

            timer.fireTime = baseTime + delay;

            //
            // Find the insertion position for the new timer.
            //

            RawTimer t = timerListHead.next;

            while (t != timerListHead)
            {
                if (delay < t.delay)
                {
                    break;
                }
                delay -= t.delay;
                t      = t.next;
            }

            //
            // Insert the new timer in the list, adjust the next timer and
            // redefine the delay sentinel.
            //

            timer.delay = delay;
            InsertTailTimerList(t, timer);
            if (t != timerListHead)
            {
                t.delay -= delay;
            }

            //
            // If the timer was inserted at front of the timer list we need
            // to wake the timer thread if it is blocked on its parker.
            //

            bool wake = (timerListHead.next == timer && parker.TryLock());

            //
            // Release the timer list lock and unpark the timer thread, if needed.
            //

            _lock.Exit();
            if (wake)
            {
                parker.Unpark(StParkStatus.Success);
            }
        }
示例#12
0
        //
        // Constructors.
        //

        public StTimer(bool notificationTimer)
        {
            if (notificationTimer)
            {
                tmrEvent = new StNotificationEvent();
            }
            else
            {
                tmrEvent = new StSynchronizationEvent();
            }

            state    = INACTIVE;
            cbparker = new CbParker(TimerCallback);
            timer    = new RawTimer(cbparker);
        }
示例#13
0
        //
        // Unlinks a cancelled raw timer from the timer list.
        //

        internal static void UnlinkRawTimer(RawTimer timer)
        {
            if (timer.next != timer)
            {
                _lock.Enter();
                if (timer.next != timer)
                {
                    if (timer.next != timerListHead)
                    {
                        timer.next.delay += timer.delay;
                    }
                    RemoveTimerFromList(timer);
                }
                _lock.Exit();
            }
        }
示例#14
0
        //
        // Adjusts the base time of the timer list.
        //

        private static void AdjustBaseTime()
        {
            int now;
            int sliding = (now = Environment.TickCount) - baseTime;

            RawTimer t;

            while ((t = timerListHead.next) != timerListHead)
            {
                if (t.delay <= sliding)
                {
                    sliding -= t.delay;
                    RemoveTimerFromList(t);

                    //
                    // Try to cancel the timer's parker. If we succeed, insert the
                    // raw timer on the fired timer list.
                    //

                    if (t.parker != null && t.parker.TryCancel())
                    {
                        //
                        // Add timer to the fired timer list, using the *prev* field.
                        //

                        t.prev      = firedTimers;
                        firedTimers = t;
                    }
                    else
                    {
                        //
                        // Mark the raw timer as unlinked.
                        //

                        t.next = t;
                    }
                }
                else
                {
                    t.delay -= sliding;
                    break;
                }
            }
            baseTime = now;
        }
示例#15
0
        //
        // Adds a raw timer to the timer list.
        //

        internal static void SetRawTimer(RawTimer tmr, int delay)
        {
            if (delay <= 0)
            {
                throw new ArgumentOutOfRangeException("\"delay\" must be greater than 0");
            }

            //
            // Acquire the timer list lock and adjust the base time.
            //

            _lock.Enter();
            AdjustBaseTime();

            //
            // Set the timer and return.
            //

            SetRawTimerWorker(tmr, delay);
        }
示例#16
0
        //
        // Adds a periodic raw timer to the timer list.
        //

        internal static void SetPeriodicRawTimer(RawTimer tmr, int period)
        {
            if (period <= 0)
            {
                throw new ArgumentOutOfRangeException("\"period\" must be greater than 0");
            }

            //
            // Acquire the timer list lock and adjust the base time.
            //

            _lock.Enter();
            AdjustBaseTime();

            //
            // Set the relative raw timer and return.
            //

            SetRawTimerWorker(tmr, (tmr.fireTime + period) - baseTime);
        }
示例#17
0
        static TimerList()
        {
            //
            // Create the objects.
            //

            _lock         = new SpinLock(TIMER_LIST_LOCK_SPINS);
            timerListHead = new RawTimer(null);
            limitTimer    = new RawTimer(null);
            parker        = new StParker(1);

            //
            // Initialize the limit timer as unlinked.
            //

            limitTimer.next = limitTimer;

            //
            // Initialize the timer list as empty.
            //

            timerListHead.next = timerListHead.prev = timerListHead;

            //
            // Set the start base time e set the *delay* sentinel.
            //

            baseTime            = Environment.TickCount;
            timerListHead.delay = Int32.MaxValue;

            //
            // Create and start the timer thread.
            //

            new Thread(TimerThread).Start();
        }
示例#18
0
        //
        // Enables the unpark callback.
        //

        internal int EnableCallback(int timeout, RawTimer tmr) {
 
	        //
	        // If the unpark method was already called, return immediately.
	        //

	        if (state >= 0) {
		        return waitStatus;
	        }

            toTimer = null;
	        if (timeout == 0) {

		        //
		        // If a zero timeout is specified with a timer, we record the
                // current time as *fireTime* in order to support periodic timers.
		        //

                if (tmr != null) {
                    tmr.fireTime = Environment.TickCount;
                }

                if (TryCancel()) {
                    return StParkStatus.Timeout;
                }
            } else if (timeout != Timeout.Infinite) {
                toTimer = tmr;
                if (timeout < 0) {
                    TimerList.SetPeriodicRawTimer(tmr, timeout & ~(1 << 31));
                } else {
                    TimerList.SetRawTimer(tmr, timeout);
                }
            }

	        //
	        // Clear the wait-in-progress bit. If this bit is already cleared,
	        // the current thread was already unparked.
	        //
	
            if (!TestAndClearInProgress()) {
                if (toTimer != null && waitStatus != StParkStatus.Timeout) {
                    TimerList.UnlinkRawTimer(tmr);
                }
                return waitStatus;
            }
            return StParkStatus.Pending;
        }
        //
        // Constructor: registers a wait with a Waitable synchronizer.
        //

        internal StRegisteredWait(StWaitable waitObject, WaitOrTimerCallback callback,
                                  object cbState, int timeout, bool executeOnce)
        {
            //
            // Validate the arguments.
            //

            if (timeout == 0)
            {
                throw new ArgumentOutOfRangeException("\"timeout\" can't be zero");
            }
            if (callback == null)
            {
                throw new ArgumentOutOfRangeException("\"callback\" can't be null");
            }
            if ((waitObject is StReentrantFairLock) || (waitObject is StReentrantReadWriteLock))
            {
                throw new InvalidOperationException("can't register waits on reentrant locks");
            }
            if ((waitObject is StNotificationEvent) && !executeOnce)
            {
                throw new InvalidOperationException("Notification event can't register waits"
                                                    + " to execute more than once");
            }

            //
            // Initialize the register wait fields
            //

            waitable         = waitObject;
            cbparker         = new CbParker(UnparkCallback);
            toTimer          = new RawTimer(cbparker);
            this.timeout     = timeout;
            this.executeOnce = executeOnce;
            this.callback    = callback;
            this.cbState     = (cbState != null) ? cbState : this;

            //
            // Execute the WaitAny prologue on the waitable.
            //
            int ignored = 0;

            waitBlock = waitObject._WaitAnyPrologue(cbparker, StParkStatus.Success, ref hint,
                                                    ref ignored);

            //
            // Set the registered wait state to active and enable the
            // unpark callback.
            //

            state = ACTIVE;
            int ws = cbparker.EnableCallback(timeout, toTimer);

            if (ws != StParkStatus.Pending)
            {
                //
                // The acquire operation was already accomplished. To prevent
                // uncontrolled reentrancy, the unpark callback is executed inline.
                //

                UnparkCallback(ws);
            }
        }
        //
        // Adds a raw timer to the timer list.
        //

        private static void SetRawTimerWorker(RawTimer timer, int delay) {

            //
	        // Set the next fire time.
        	//

	        timer.fireTime = baseTime + delay;

	        //
	        // Find the insertion position for the new timer.
	        //

            RawTimer t = timerListHead.next;
	        while (t != timerListHead) {
		        if (delay < t.delay) {
			        break;
		        }
		        delay -= t.delay;
		        t = t.next;
	        }

	        //
	        // Insert the new timer in the list, adjust the next timer and
	        // redefine the delay sentinel.
	        //

            timer.delay = delay;
            InsertTailTimerList(t, timer);
            if (t != timerListHead) {
                t.delay -= delay;
            }
        
            //
	        // If the timer was inserted at front of the timer list we need
	        // to wake the timer thread if it is blocked on its parker.
	        //

	        bool wake = (timerListHead.next == timer && parker.TryLock());

	        //
	        // Release the timer list lock and unpark the timer thread, if needed.
	        //

            _lock.Exit();
            if (wake) {
                parker.Unpark(StParkStatus.Success);
            }
        }
        //
        // Adds a raw timer to the timer list.
        //

        internal static void SetRawTimer(RawTimer tmr, int delay) {
            if (delay <= 0) {
                throw new ArgumentOutOfRangeException("\"delay\" must be greater than 0");
            }
	
            //
	        // Acquire the timer list lock and adjust the base time.
	        //

            _lock.Enter();
	        AdjustBaseTime();

	        //
	        // Set the timer and return.
	        //

	        SetRawTimerWorker(tmr, delay);
        }
        //
        // Adds a periodic raw timer to the timer list.
        //

        internal static void SetPeriodicRawTimer(RawTimer tmr, int period) {
            if (period <= 0) {
                throw new ArgumentOutOfRangeException("\"period\" must be greater than 0");
            }

	        //
	        // Acquire the timer list lock and adjust the base time.
	        //

            _lock.Enter();
	        AdjustBaseTime();

	        //
	        // Set the relative raw timer and return.
	        //

	        SetRawTimerWorker(tmr, (tmr.fireTime + period) - baseTime);
        }
        //
        // The timer thread.
        //

        private static void TimerThread() {

            //
            // The timer thread is a background thread.
            //

            Thread.CurrentThread.IsBackground = true;
            Thread.CurrentThread.Name = "StTimers";

            do {

		        //
		        // Acquire the timer list lock.
		        //

                _lock.Enter();

                //
                // If the limit timer was activated, remove it from the timer list.
                //

                if (limitTimer.next != limitTimer) {
                    if (limitTimer.next != timerListHead) {
                        limitTimer.next.delay += limitTimer.delay;
                    }
                    RemoveTimerFromList(limitTimer);
                    limitTimer.next = limitTimer;
                }

                //
                // Adjust the base time and the timer list and process
                // expired timers.
                //

		        AdjustBaseTime();

		        //
		        // Initializes the parker and compute the time at which the
		        // front timer must expire.
		        //

                parker.Reset(1);

                //
		        // If the first timer ...
		        //

                RawTimer first = timerListHead.next;
                int btime = baseTime;
                int delay;

        		if ((delay = first.delay) > MAXIMUM_SLEEP_TIME) {
                    limitTimer.delay = MAXIMUM_SLEEP_TIME;
			        InsertHeadTimerList(timerListHead, limitTimer);
                    if (first != timerListHead) {
                        first.delay -= MAXIMUM_SLEEP_TIME;
                    }
                    delay = MAXIMUM_SLEEP_TIME;
		        }

                //
                // Get the fired timers list and empty it.
                //

                RawTimer fired = TimerList.firedTimers;
                TimerList.firedTimers = null;

		        //
		        // Release the timer list's lock.
		        //

                _lock.Exit();

		        //
		        // Call unpark method on the expired timer's parkers.
		        //

                while (fired != null) {
                    RawTimer next = fired.prev;
                    fired.parker.Unpark(StParkStatus.Timeout);
                    fired = next;
                }

                //
		        // Since that the timer thread can take significant time to execute
		        // the timer's callbacks, we must ajust the *delay*, if needed.
		        //

                int sliding;
                if ((sliding = Environment.TickCount - btime) != 0) {
			        delay = (sliding >= delay) ? 0 : (delay - sliding);	
		        }

		        //
		        // Park the timer thread until the next timer expires or a new
		        // timer is inserted at front of the timer list.
		        //

		        parker.Park(new StCancelArgs(delay));
	        } while (true);

	        //
	        // We never get here!
	        //
        }
示例#24
0
        //
        // The timer thread.
        //

        private static void TimerThread()
        {
            //
            // The timer thread is a background thread.
            //

            Thread.CurrentThread.IsBackground = true;
            Thread.CurrentThread.Name         = "StTimers";

            do
            {
                //
                // Acquire the timer list lock.
                //

                _lock.Enter();

                //
                // If the limit timer was activated, remove it from the timer list.
                //

                if (limitTimer.next != limitTimer)
                {
                    if (limitTimer.next != timerListHead)
                    {
                        limitTimer.next.delay += limitTimer.delay;
                    }
                    RemoveTimerFromList(limitTimer);
                    limitTimer.next = limitTimer;
                }

                //
                // Adjust the base time and the timer list and process
                // expired timers.
                //

                AdjustBaseTime();

                //
                // Initializes the parker and compute the time at which the
                // front timer must expire.
                //

                parker.Reset(1);

                //
                // If the first timer ...
                //

                RawTimer first = timerListHead.next;
                int      btime = baseTime;
                int      delay;

                if ((delay = first.delay) > MAXIMUM_SLEEP_TIME)
                {
                    limitTimer.delay = MAXIMUM_SLEEP_TIME;
                    InsertHeadTimerList(timerListHead, limitTimer);
                    if (first != timerListHead)
                    {
                        first.delay -= MAXIMUM_SLEEP_TIME;
                    }
                    delay = MAXIMUM_SLEEP_TIME;
                }

                //
                // Get the fired timers list and empty it.
                //

                RawTimer fired = TimerList.firedTimers;
                TimerList.firedTimers = null;

                //
                // Release the timer list's lock.
                //

                _lock.Exit();

                //
                // Call unpark method on the expired timer's parkers.
                //

                while (fired != null)
                {
                    RawTimer next = fired.prev;
                    fired.parker.Unpark(StParkStatus.Timeout);
                    fired = next;
                }

                //
                // Since that the timer thread can take significant time to execute
                // the timer's callbacks, we must ajust the *delay*, if needed.
                //

                int sliding;
                if ((sliding = Environment.TickCount - btime) != 0)
                {
                    delay = (sliding >= delay) ? 0 : (delay - sliding);
                }

                //
                // Park the timer thread until the next timer expires or a new
                // timer is inserted at front of the timer list.
                //

                parker.Park(new StCancelArgs(delay));
            } while (true);

            //
            // We never get here!
            //
        }
        //
        // Unlinks a cancelled raw timer from the timer list.
        //

        internal static void UnlinkRawTimer(RawTimer timer) {
	        if (timer.next != timer) {
                _lock.Enter();
		        if (timer.next != timer) {
                    if (timer.next != timerListHead) {
                        timer.next.delay += timer.delay;
                    }
			        RemoveTimerFromList(timer);
		        }
                _lock.Exit();
	        }
        }
        //
        // Constructor: registers a wait with a Waitable synchronizer.
        //

        internal StRegisteredWait(StWaitable waitObject,  WaitOrTimerCallback callback,
                                  object cbState, int timeout, bool executeOnce) {

        	//
	        // Validate the arguments.
	        //

            if (timeout == 0) {
                throw new ArgumentOutOfRangeException("\"timeout\" can't be zero");
            }
            if (callback == null) {
                throw new ArgumentOutOfRangeException("\"callback\" can't be null");
            }
            if ((waitObject is StReentrantFairLock) || (waitObject is StReentrantReadWriteLock)) {
                throw new InvalidOperationException("can't register waits on reentrant locks");
            }
            if ((waitObject is StNotificationEvent) && !executeOnce) {
                throw new InvalidOperationException("Notification event can't register waits"
                            + " to execute more than once");
            }

	        //
	        // Initialize the register wait fields
	        //

            waitable = waitObject;
            cbparker = new CbParker(UnparkCallback);
            toTimer = new RawTimer(cbparker);
	        this.timeout = timeout;
            this.executeOnce = executeOnce;
	        this.callback = callback;
	        this.cbState = (cbState != null) ? cbState : this;
        
            //
	        // Execute the WaitAny prologue on the waitable.
	        //
            int ignored = 0;
            waitBlock  = waitObject._WaitAnyPrologue(cbparker, StParkStatus.Success, ref hint,
                                                     ref ignored);

            //
	        // Set the registered wait state to active and enable the
            // unpark callback.
	        //

	        state = ACTIVE;
            int ws = cbparker.EnableCallback(timeout, toTimer);
            if (ws != StParkStatus.Pending) {
		
                //
		        // The acquire operation was already accomplished. To prevent
                // uncontrolled reentrancy, the unpark callback is executed inline.
		        //

		        UnparkCallback(ws);
	        }
        }
        //
        // Tries to cancel a raw timer, if it's still active.
        //

        private static bool TryCancelRawTimer(RawTimer tmr) {
            if (tmr.parker.TryCancel()) {
		        UnlinkRawTimer(tmr);
                return true;
            }
            return false;
        }
        static TimerList() {

            //
            // Create the objects.
            //

            _lock = new SpinLock(TIMER_LIST_LOCK_SPINS);
            timerListHead = new RawTimer(null);
            limitTimer = new RawTimer(null);
            parker = new StParker(1);

            //
            // Initialize the limit timer as unlinked.
            //
            
            limitTimer.next = limitTimer;

            //
            // Initialize the timer list as empty.
            //

            timerListHead.next = timerListHead.prev = timerListHead;

            //
            // Set the start base time e set the *delay* sentinel.
            //

        	baseTime = Environment.TickCount;
            timerListHead.delay = Int32.MaxValue;

	        //
	        // Create and start the timer thread.
	        //

            new Thread(TimerThread).Start();
	    }
        //
        // Adjusts the base time of the timer list.
        //

        private static void AdjustBaseTime() {
            int now;
            int sliding = (now = Environment.TickCount) - baseTime;

            RawTimer t;
            while ((t = timerListHead.next) != timerListHead) {
                if (t.delay <= sliding) {
                    sliding -= t.delay;
                    RemoveTimerFromList(t);

                    //
                    // Try to cancel the timer's parker. If we succeed, insert the
                    // raw timer on the fired timer list.
                    //

                    if (t.parker != null && t.parker.TryCancel()) {

                        //
                        // Add timer to the fired timer list, using the *prev* field.
                        //

                        t.prev = firedTimers;
                        firedTimers = t;
                    } else {

                        //
                        // Mark the raw timer as unlinked.
                        //

                        t.next = t;
                    }
                } else {
                    t.delay -= sliding;
                    break;
                }
            }
            baseTime = now;
        }