// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System.Threading; using System.Reactive.Disposables; namespace System.Reactive.Concurrency { /// /// Represents an object that schedules units of work to run immediately on the current thread. /// /// Singleton instance of this type exposed through this static property. public sealed class ImmediateScheduler : LocalScheduler { private static readonly ImmediateScheduler s_instance = new ImmediateScheduler(); ImmediateScheduler() { } /// /// Gets the singleton instance of the immediate scheduler. /// public static ImmediateScheduler Instance { get { return s_instance; } } /// /// Schedules an action to be executed. /// /// The type of the state passed to the scheduled action. /// State passed to the action to be executed. /// Action to be executed. /// The disposable object used to cancel the scheduled action (best effort). /// is null. public override IDisposable Schedule(TState state, Func action) { if (action == null) throw new ArgumentNullException("action"); return action(new AsyncLockScheduler(), state); } /// /// Schedules an action to be executed after dueTime. /// /// The type of the state passed to the scheduled action. /// State passed to the action to be executed. /// Action to be executed. /// Relative time after which to execute the action. /// The disposable object used to cancel the scheduled action (best effort). /// is null. public override IDisposable Schedule(TState state, TimeSpan dueTime, Func action) { if (action == null) throw new ArgumentNullException("action"); var dt = Scheduler.Normalize(dueTime); if (dt.Ticks > 0) { ConcurrencyAbstractionLayer.Current.Sleep(dt); } return action(new AsyncLockScheduler(), state); } class AsyncLockScheduler : LocalScheduler { AsyncLock asyncLock; public override IDisposable Schedule(TState state, Func action) { if (action == null) throw new ArgumentNullException("action"); var m = new SingleAssignmentDisposable(); if (asyncLock == null) asyncLock = new AsyncLock(); asyncLock.Wait(() => { if (!m.IsDisposed) m.Disposable = action(this, state); }); return m; } public override IDisposable Schedule(TState state, TimeSpan dueTime, Func action) { if (action == null) throw new ArgumentNullException("action"); if (dueTime.Ticks <= 0) return Schedule(state, action); var timer = ConcurrencyAbstractionLayer.Current.StartStopwatch(); var m = new SingleAssignmentDisposable(); if (asyncLock == null) asyncLock = new AsyncLock(); asyncLock.Wait(() => { if (!m.IsDisposed) { var sleep = dueTime - timer.Elapsed; if (sleep.Ticks > 0) { ConcurrencyAbstractionLayer.Current.Sleep(sleep); } if (!m.IsDisposed) m.Disposable = action(this, state); } }); return m; } } } }