Exemplo n.º 1
0
        /// <summary>
        /// Enqueues absolute time scheduled work in the timer queue or the short term work list.
        /// </summary>
        /// <param name="state">State to pass to the action.</param>
        /// <param name="dueTime">Absolute time to run the work on. The timer queue is responsible to execute the work close to the specified time, also accounting for system clock changes.</param>
        /// <param name="action">Action to run, potentially recursing into the scheduler.</param>
        /// <returns>Disposable object to prevent the work from running.</returns>
        private IDisposable Enqueue <TState>(TState state, DateTimeOffset dueTime, Func <IScheduler, TState, IDisposable> action)
        {
            //
            // Work that's due in the past is sent to the underlying scheduler through the Schedule
            // overload for execution at TimeSpan.Zero. We don't go to the overload for immediate
            // scheduling in order to:
            //
            // - Preserve the time-based nature of the call as surfaced to the underlying scheduler,
            //   as it may use different queuing strategies.
            //
            // - Optimize for the default behavior of LocalScheduler where a virtual call to Schedule
            //   for immediate execution calls into the abstract Schedule method with TimeSpan.Zero.
            //
            var due = Scheduler.Normalize(dueTime - Now);

            if (due == TimeSpan.Zero)
            {
                return(Schedule <TState>(state, TimeSpan.Zero, action));
            }

            //
            // We're going down the path of queueing up work or scheduling it, so we need to make
            // sure we can get system clock change notifications. If not, the call below is expected
            // to throw NotSupportedException. WorkItem.Invoke decreases the ref count again to allow
            // the system clock monitor to stop if there's no work left. Notice work items always
            // reach an execution stage since we don't dequeue items but merely mark them as cancelled
            // through WorkItem.Dispose. Double execution is also prevented, so the ref count should
            // correctly balance out.
            //
            SystemClock.AddRef();

            var workItem = new WorkItem <TState>(this, state, dueTime, action);

            if (due <= SHORTTERM)
            {
                ScheduleShortTermWork(workItem);
            }
            else
            {
                ScheduleLongTermWork(workItem);
            }

            return(workItem);
        }