Ejemplo n.º 1
0
        /// <summary>
        /// Schedules an action to be executed at dueTime.
        /// </summary>
        /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
        /// <param name="state">State passed to the action to be executed.</param>
        /// <param name="action">Action to be executed.</param>
        /// <param name="dueTime">Absolute time at which to execute the action.</param>
        /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns>
        /// <exception cref="ArgumentNullException"><paramref name="action"/> is <c>null</c>.</exception>
        public override IDisposable ScheduleAbsolute <TState>(TState state, TAbsolute dueTime, Func <IScheduler, TState, IDisposable> action)
        {
            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            ScheduledItem <TAbsolute, TState>?si = null;

            var run = new Func <IScheduler, TState, IDisposable>((scheduler, state1) =>
            {
                lock (_queue)
                {
                    _queue.Remove(si !); // NB: Assigned before function is invoked.
                }

                return(action(scheduler, state1));
            });

            si = new ScheduledItem <TAbsolute, TState>(this, state, run, dueTime, Comparer);

            lock (_queue)
            {
                _queue.Enqueue(si);
            }

            return(si);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Schedules an action to be executed after dueTime.
        /// </summary>
        /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
        /// <param name="state">State passed to the action to be executed.</param>
        /// <param name="action">Action to be executed.</param>
        /// <param name="dueTime">Relative time after which to execute the action.</param>
        /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns>
        /// <exception cref="ArgumentNullException"><paramref name="action"/> is null.</exception>
        public override IDisposable Schedule <TState>(TState state, TimeSpan dueTime, Func <IScheduler, TState, IDisposable> action)
        {
            if (action == null)
            {
                throw new ArgumentNullException("action");
            }

            var dt = Time + Scheduler.Normalize(dueTime);

            var si = new ScheduledItem <TimeSpan, TState>(this, state, action, dt);

            var queue = GetQueue();

            if (queue == null)
            {
                queue = new SchedulerQueue <TimeSpan>(4);
                queue.Enqueue(si);

                CurrentThreadScheduler.SetQueue(queue);
                try
                {
                    Trampoline.Run(queue);
                }
                finally
                {
                    CurrentThreadScheduler.SetQueue(null);
                }
            }
            else
            {
                queue.Enqueue(si);
            }

            return(Disposable.Create(si.Cancel));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Schedules an action to be executed at dueTime.
        /// </summary>
        /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
        /// <param name="state">State passed to the action to be executed.</param>
        /// <param name="action">Action to be executed.</param>
        /// <param name="dueTime">Absolute time at which to execute the action.</param>
        /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns>
        /// <exception cref="ArgumentNullException"><paramref name="action"/> is <c>null</c>.</exception>
        public override IDisposable ScheduleAbsolute <TState>(TState state, TAbsolute dueTime, Func <IScheduler, TState, IDisposable> action)
        {
            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            var si = default(ScheduledItem <TAbsolute, TState>);

            var run = new Func <IScheduler, TState, IDisposable>((scheduler, state1) =>
            {
                lock (queue)
                {
                    queue.Remove(si);
                }

                return(action(scheduler, state1));
            });

            si = new ScheduledItem <TAbsolute, TState>(this, state, run, dueTime, Comparer);

            lock (queue)
            {
                queue.Enqueue(si);
            }

            return(si);
        }
        /// <summary>
        /// Schedules an action to be executed after dueTime.
        /// </summary>
        /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
        /// <param name="state">State passed to the action to be executed.</param>
        /// <param name="action">Action to be executed.</param>
        /// <param name="dueTime">Relative time after which to execute the action.</param>
        /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns>
        /// <exception cref="ArgumentNullException"><paramref name="action"/> is <c>null</c>.</exception>
        /// <exception cref="ObjectDisposedException">The scheduler has been disposed and doesn't accept new work.</exception>
        public override IDisposable Schedule <TState>(TState state, TimeSpan dueTime, Func <IScheduler, TState, IDisposable> action)
        {
            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            var due = _stopwatch.Elapsed + dueTime;
            var si  = new ScheduledItem <TimeSpan, TState>(this, state, action, due);

            lock (_gate)
            {
                if (_disposed)
                {
                    throw new ObjectDisposedException("");
                }

                if (dueTime <= TimeSpan.Zero)
                {
                    _readyList.Enqueue(si);
                    _evt.Release();
                }
                else
                {
                    _queue.Enqueue(si);
                    _evt.Release();
                }

                EnsureThread();
            }

            return(Disposable.Create(si.Cancel));
        }
Ejemplo n.º 5
0
 public int CompareTo(ScheduledItem <TAbsolute> other)
 {
     if (other == null)
     {
         throw new ArgumentNullException("other");
     }
     return(comparer.Compare(DueTime, other.DueTime));
 }
Ejemplo n.º 6
0
        /// <summary>
        /// Compares the work item with another work item based on absolute time values.
        /// </summary>
        /// <param name="other">Work item to compare the current work item to.</param>
        /// <returns>Relative ordering between this and the specified work item.</returns>
        /// <remarks>The inequality operators are overloaded to provide results consistent with the <see cref="IComparable"/> implementation. Equality operators implement traditional reference equality semantics.</remarks>
        public int CompareTo(ScheduledItem <TAbsolute> other)
        {
            // MSDN: By definition, any object compares greater than null, and two null references compare equal to each other.
            if (ReferenceEquals(other, null))
            {
                return(1);
            }

            return(_comparer.Compare(DueTime, other.DueTime));
        }
Ejemplo n.º 7
0
        private void Tick(object state)
        {
            lock (_gate)
            {
                if (!_disposed)
                {
                    var item = (ScheduledItem <TimeSpan>)state;
                    if (item == _nextItem)
                    {
                        _nextItem = null;
                    }
                    if (_queue.Remove(item))
                    {
                        _readyList.Enqueue(item);
                    }

                    _evt.Release();
                }
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Schedules an action to be executed at dueTime.
        /// </summary>
        /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
        /// <param name="state">State passed to the action to be executed.</param>
        /// <param name="action">Action to be executed.</param>
        /// <param name="dueTime">Absolute time at which to execute the action.</param>
        /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns>
        /// <exception cref="ArgumentNullException"><paramref name="action"/> is null.</exception>
        public override IDisposable ScheduleAbsolute <TState>(TState state, DateTimeOffset dueTime, Func <IScheduler, TState, IDisposable> action)
        {
            if (action == null)
            {
                throw new ArgumentNullException("action");
            }

            var si = default(ScheduledItem <DateTimeOffset, TState>);

            var run = new Func <IScheduler, TState, IDisposable>((scheduler, state1) =>
            {
                queue.Remove(si);
                return(action(scheduler, state1));
            });

            si = new ScheduledItem <DateTimeOffset, TState>(this, state, run, dueTime, Comparer);
            queue.Enqueue(si);

            return(Disposable.Create(si.Cancel));
        }
Ejemplo n.º 9
0
        void AddTask(IList <ScheduledItem <TAbsolute> > tasks, ScheduledItem <TAbsolute> task)
        {
            // It is most likely appended in order, so don't use ineffective List.Sort(). Simple comparison makes it faster.
            // Also, it is important that events are processed *in order* when they are scheduled at the same moment.
            int       pos     = -1;
            TAbsolute dueTime = task.DueTime;

            for (int i = tasks.Count - 1; i >= 0; i--)
            {
                if (Comparer.Compare(dueTime, tasks [i].DueTime) >= 0)
                {
                    tasks.Insert(i + 1, task);
                    pos = i;
                    break;
                }
            }
            if (pos < 0)
            {
                tasks.Insert(0, task);
            }
        }
Ejemplo n.º 10
0
 /// <summary>
 /// Removes the specified work item from the scheduler queue.
 /// </summary>
 /// <param name="scheduledItem">Work item to be removed from the scheduler queue.</param>
 /// <returns>true if the item was found; false otherwise.</returns>
 public bool Remove(ScheduledItem <TAbsolute> scheduledItem)
 {
     return(_queue.Remove(scheduledItem));
 }
Ejemplo n.º 11
0
 /// <summary>
 /// Enqueues the specified work item to be scheduled.
 /// </summary>
 /// <param name="scheduledItem">Work item to be scheduled.</param>
 public void Enqueue(ScheduledItem <TAbsolute> scheduledItem)
 {
     _queue.Enqueue(scheduledItem);
 }
Ejemplo n.º 12
0
        /// <summary>
        /// Event loop scheduled on the designated event loop thread. The loop is suspended/resumed using the event
        /// which gets set by calls to Schedule, the next item timer, or calls to Dispose.
        /// </summary>
        private void Run()
        {
            while (true)
            {
                _evt.Wait();

                var ready = default(ScheduledItem <TimeSpan>[]);

                lock (_gate)
                {
                    //
                    // Bug fix that ensures the number of calls to Release never greatly exceeds the number of calls to Wait.
                    // See work item #37: https://rx.codeplex.com/workitem/37
                    //
                    while (_evt.CurrentCount > 0)
                    {
                        _evt.Wait();
                    }

                    //
                    // The event could have been set by a call to Dispose. This takes priority over anything else. We quit the
                    // loop immediately. Subsequent calls to Schedule won't ever create a new thread.
                    //
                    if (_disposed)
                    {
                        _evt.Dispose();
                        return;
                    }

                    while (_queue.Count > 0 && _queue.Peek().DueTime <= _stopwatch.Elapsed)
                    {
                        var item = _queue.Dequeue();
                        _readyList.Enqueue(item);
                    }

                    if (_queue.Count > 0)
                    {
                        var next = _queue.Peek();
                        if (next != _nextItem)
                        {
                            _nextItem = next;

                            var due = next.DueTime - _stopwatch.Elapsed;
                            Disposable.TrySetSerial(ref _nextTimer, ConcurrencyAbstractionLayer.Current.StartTimer(Tick, next, due));
                        }
                    }

                    if (_readyList.Count > 0)
                    {
                        ready = _readyList.ToArray();
                        _readyList.Clear();
                    }
                }

                if (ready != null)
                {
                    foreach (var item in ready)
                    {
                        if (!item.IsCanceled)
                        {
                            try
                            {
                                item.Invoke();
                            }
                            catch (ObjectDisposedException ex) when(nameof(EventLoopScheduler).Equals(ex.ObjectName))
                            {
                                // Since we are not inside the lock at this point
                                // the scheduler can be disposed before the item had a chance to run
                            }
                        }
                    }
                }

                if (ExitIfEmpty)
                {
                    lock (_gate)
                    {
                        if (_readyList.Count == 0 && _queue.Count == 0)
                        {
                            _thread = null;
                            return;
                        }
                    }
                }
            }
        }
Ejemplo n.º 13
0
 public bool Remove(ScheduledItem <TAbsolute> scheduledItem)
 {
     throw new NotImplementedException();
 }
Ejemplo n.º 14
0
        /// <summary>
        /// Schedules an action to be executed after dueTime.
        /// </summary>
        /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
        /// <param name="state">State passed to the action to be executed.</param>
        /// <param name="action">Action to be executed.</param>
        /// <param name="dueTime">Relative time after which to execute the action.</param>
        /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns>
        /// <exception cref="ArgumentNullException"><paramref name="action"/> is <c>null</c>.</exception>
        public override IDisposable Schedule <TState>(TState state, TimeSpan dueTime, Func <IScheduler, TState, IDisposable> action)
        {
            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            var queue = default(SchedulerQueue <TimeSpan>);

            // There is no timed task and no task is currently running
            if (!running)
            {
                running = true;

                if (dueTime > TimeSpan.Zero)
                {
                    ConcurrencyAbstractionLayer.Current.Sleep(dueTime);
                }

                // execute directly without queueing
                IDisposable d;
                try
                {
                    d = action(this, state);
                }
                catch
                {
                    SetQueue(null);
                    running = false;
                    throw;
                }

                // did recursive tasks arrive?
                queue = GetQueue();

                // yes, run those in the queue as well
                if (queue != null)
                {
                    try
                    {
                        Trampoline.Run(queue);
                    }
                    finally
                    {
                        SetQueue(null);
                        running = false;
                    }
                }
                else
                {
                    running = false;
                }

                return(d);
            }

            queue = GetQueue();

            // if there is a task running or there is a queue
            if (queue == null)
            {
                queue = new SchedulerQueue <TimeSpan>(4);
                SetQueue(queue);
            }

            var dt = Time + Scheduler.Normalize(dueTime);

            // queue up more work
            var si = new ScheduledItem <TimeSpan, TState>(this, state, action, dt);

            queue.Enqueue(si);
            return(si);
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Event loop scheduled on the designated event loop thread. The loop is suspended/resumed using the event
        /// which gets set by calls to Schedule, the next item timer, or calls to Dispose.
        /// </summary>
        private void Run()
        {
            while (true)
            {
#if !NO_CDS
                _evt.Wait();
#else
                _evt.WaitOne();
#endif

                var ready = default(ScheduledItem <SafeTimeSpan>[]);

                lock (_gate)
                {
                    //
                    // The event could have been set by a call to Dispose. This takes priority over anything else. We quit the
                    // loop immediately. Subsequent calls to Schedule won't ever create a new thread.
                    //
                    if (_disposed)
                    {
                        ((IDisposable)_evt).Dispose();
                        return;
                    }

                    while (_queue.Count > 0 && (TimeSpan)_queue.Peek().DueTime <= _stopwatch.Elapsed)
                    {
                        var item = _queue.Dequeue();
                        _readyList.Enqueue(item);
                    }

                    if (_queue.Count > 0)
                    {
                        var next = _queue.Peek();
                        if (next != _nextItem)
                        {
                            _nextItem = next;

                            var due = (TimeSpan)next.DueTime - _stopwatch.Elapsed;
                            _nextTimer.Disposable = ConcurrencyAbstractionLayer.Current.StartTimer(Tick, next, due);
                        }
                    }

                    if (_readyList.Count > 0)
                    {
                        ready = _readyList.ToArray();
                        _readyList.Clear();
                    }
                }

                if (ready != null)
                {
                    foreach (var item in ready)
                    {
                        if (!item.IsCanceled)
                        {
                            item.Invoke();
                        }
                    }
                }

                if (ExitIfEmpty)
                {
                    lock (_gate)
                    {
                        if (_readyList.Count == 0 && _queue.Count == 0)
                        {
                            _thread = null;
                            return;
                        }
                    }
                }
            }
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Event loop scheduled on the designated event loop thread. The loop is suspended/resumed using the event
        /// which gets set by calls to Schedule, the next item timer, or calls to Dispose.
        /// </summary>
        private void Run()
        {
            while (true)
            {
                _evt.Wait();

                var ready = default(ScheduledItem <TimeSpan>[]);

                lock (_gate)
                {
                    //
                    // Bug fix that ensures the number of calls to Release never greatly exceeds the number of calls to Wait.
                    // See work item #37: https://rx.codeplex.com/workitem/37
                    //
                    while (_evt.CurrentCount > 0)
                    {
                        _evt.Wait();
                    }

                    //
                    // The event could have been set by a call to Dispose. This takes priority over anything else. We quit the
                    // loop immediately. Subsequent calls to Schedule won't ever create a new thread.
                    //
                    if (_disposed)
                    {
                        ((IDisposable)_evt).Dispose();
                        return;
                    }

                    while (_queue.Count > 0 && _queue.Peek().DueTime <= _stopwatch.Elapsed)
                    {
                        var item = _queue.Dequeue();
                        _readyList.Enqueue(item);
                    }

                    if (_queue.Count > 0)
                    {
                        var next = _queue.Peek();
                        if (next != _nextItem)
                        {
                            _nextItem = next;

                            var due = next.DueTime - _stopwatch.Elapsed;
                            _nextTimer.Disposable = ConcurrencyAbstractionLayer.Current.StartTimer(Tick, next, due);
                        }
                    }

                    if (_readyList.Count > 0)
                    {
                        ready = _readyList.ToArray();
                        _readyList.Clear();
                    }
                }

                if (ready != null)
                {
                    foreach (var item in ready)
                    {
                        if (!item.IsCanceled)
                        {
                            item.Invoke();
                        }
                    }
                }

                if (ExitIfEmpty)
                {
                    lock (_gate)
                    {
                        if (_readyList.Count == 0 && _queue.Count == 0)
                        {
                            _thread = null;
                            return;
                        }
                    }
                }
            }
        }
Ejemplo n.º 17
0
 public void Enqueue(ScheduledItem <TAbsolute> scheduledItem)
 {
     throw new NotImplementedException();
 }