Schedules fibers for execution.
Schedulers are bound to the thread they are created on and they install a SynchronizationContext which is active during execution. Schedulers have an implementation specific update method or run loop. The interface is otherwise thin since schedulers are generally not intended to be used directly. Scheduling work is accomplished by invoking methods on Fiber or SynchronizationContext.
Inheritance: IFiberScheduler, IDisposable
Beispiel #1
0
        /// <summary>
        /// Start executing a new fiber using the default scheduler on the thread.
        /// </summary>
        /// <returns>
        /// Returns a <see cref="Fiber"/>
        /// that can be yielded against to wait for the fiber to complete.
        /// </returns>
        /// <param name='action'>
        /// A non-blocking action to execute on the fiber.
        /// </param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name='scheduler'>
        /// A scheduler to execute the fiber on.
        /// </param>
        public Fiber StartNew(Action action, CancellationToken cancellationToken, FiberScheduler scheduler)
        {
            var fiber = new Fiber(action, cancellationToken);

            fiber.Start(scheduler);
            return(fiber);
        }
        static internal void SetCurrentScheduler(FiberScheduler scheduler, bool internalInvoke)
        {
            // Only allow scheduler changes on a thread when a fiber is not executing.
            // Ignore this check if this is an internal invocation such as from
            // Fiber.Execute() which needs to switch schedulers on demand.
            if (!internalInvoke && Fiber.CurrentFiber != null)
            {
                throw new InvalidOperationException("The current scheduler for the thread cannot be changed from inside an executing fiber.");
            }

            // Skip work if nothing to change
            if (currentScheduler == scheduler)
            {
                return;
            }

            // Assign the scheduler
            currentScheduler = scheduler;

            // Update the synchronization context if it changed
            if (currentScheduler != null && SynchronizationContext.Current != currentScheduler.SynchronizationContext)
            {
                SynchronizationContext.SetSynchronizationContext(currentScheduler.SynchronizationContext);
            }
            else if (currentScheduler == null && SynchronizationContext.Current != null)
            {
                SynchronizationContext.SetSynchronizationContext(null);
            }
        }
        /// <summary>
        /// Creates a continuation that executes asynchronously when the target fiber completes.
        /// </summary>
        /// <returns>A fiber that executes when the target fiber completes.</returns>
        /// <param name="continuationCoroutine">Continuation coroutine.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name="continuationOptions">Continuation options.</param>
        /// <param name="scheduler">Scheduler.</param>
        public Fiber ContinueWith(IEnumerator continuationCoroutine, CancellationToken cancellationToken,
            FiberContinuationOptions continuationOptions, FiberScheduler scheduler)
        {
            if (continuationCoroutine == null)
                throw new ArgumentNullException("continuationCoroutine");

            if (scheduler == null)
                throw new ArgumentNullException("scheduler");

            var fiber = new Fiber(continuationCoroutine, cancellationToken);

            fiber.antecedent = this;
            fiber.status = (int)FiberStatus.WaitingForActivation;

            var continuation = new FiberContinuation(fiber, continuationOptions, scheduler);

            if (IsCompleted) {
                continuation.Execute();
            } else {
                // Lazy create queue
                if (continuations == null)
                    continuations = new Queue<FiberContinuation>();

                continuations.Enqueue(continuation);
            }

            return fiber;
        }
        /// <summary>
        /// Crates a Fiber that waits for a delay before completing.
        /// </summary>
        /// <param name="millisecondsDelay">Milliseconds to delay.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name="scheduler">Scheduler.</param>
        public static Fiber Delay(int millisecondsDelay, CancellationToken cancellationToken, FiberScheduler scheduler)
        {
            if (millisecondsDelay < -1)
                throw new ArgumentOutOfRangeException ("millisecondsDelay");

            return Fiber.Factory.StartNew(DelayCoroutine(millisecondsDelay, cancellationToken), scheduler);
        }
 /// <summary>
 /// Initializes the task factory during Awake().
 /// </summary>
 /// <remarks>
 /// The task factory cannot be initialized in the constructor
 /// because it must be initialized from the coroutine
 /// execution thread which the constructor does not guarantee.
 /// </remarks>
 protected virtual void Awake()
 {
     _taskFactory    = this.CreateTaskFactory();
     _taskScheduler  = _taskFactory.Scheduler;
     _fiberScheduler = ((FiberTaskScheduler)_taskScheduler).FiberScheduler;
     _fiberFactory   = new FiberFactory(_fiberScheduler);
 }
        /// <summary>
        /// Initializes a new instance of the <see cref="SpicyPixel.Threading.FiberFactory"/> class.
        /// </summary>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name="continuationOptions">Continuation options.</param>
        /// <param name="scheduler">Scheduler.</param>
        public FiberFactory(CancellationToken cancellationToken, FiberContinuationOptions continuationOptions,
            FiberScheduler scheduler)
        {
            this.cancellationToken = cancellationToken;
            this.continuationOptions = continuationOptions;
            this.scheduler = scheduler;

            CheckContinuationOptions (continuationOptions);
        }
Beispiel #7
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SpicyPixel.Threading.FiberFactory"/> class.
        /// </summary>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name="continuationOptions">Continuation options.</param>
        /// <param name="scheduler">Scheduler.</param>
        public FiberFactory(CancellationToken cancellationToken, FiberContinuationOptions continuationOptions,
                            FiberScheduler scheduler)
        {
            this.cancellationToken   = cancellationToken;
            this.continuationOptions = continuationOptions;
            this.scheduler           = scheduler;

            CheckContinuationOptions(continuationOptions);
        }
Beispiel #8
0
        /// <summary>
        /// Start executing the fiber using the specified scheduler.
        /// </summary>
        /// <remarks>
        /// This method is safe to call from any thread even if different
        /// than the scheduler execution thread.
        /// </remarks>
        /// <returns>
        /// Returns a <see cref="YieldUntilComplete"/> fiber instruction
        /// that can be yielded against to wait for the fiber to complete.
        /// </returns>
        /// <param name='scheduler'>
        /// The scheduler to start the fiber on.
        /// </param>
        public YieldUntilComplete Start(FiberScheduler scheduler)
        {
            // It would be unusual to attempt to start a Fiber more than once,
            // but to be safe and to support calling from any thread
            // use Interlocked with boxing on the enum.

            var originalState = (FiberState)Interlocked.CompareExchange(ref fiberState, (int)FiberState.Running, (int)FiberState.Unstarted);

            if (originalState != FiberState.Unstarted)
            {
                throw new InvalidOperationException("A fiber cannot be started again once it has begun running or has completed.");
            }

            this.scheduler = scheduler;
            ((IFiberScheduler)this.scheduler).QueueFiber(this);
            return(new YieldUntilComplete(this));
        }
        /// <summary>
        /// Start executing the fiber using the specified scheduler.
        /// </summary>
        /// <remarks>
        /// This method is safe to call from any thread even if different
        /// than the scheduler execution thread.
        /// </remarks>
        /// <param name='scheduler'>
        /// The scheduler to start the fiber on.
        /// </param>
        public void Start(FiberScheduler scheduler)
        {
            // It would be unusual to attempt to start a Fiber more than once,
            // but to be safe and to support calling from any thread
            // use Interlocked with boxing on the enum.

            var originalState = (FiberStatus)Interlocked.CompareExchange(ref status, (int)FiberStatus.WaitingToRun, (int)FiberStatus.Created);

            if (originalState != FiberStatus.Created)
            {
                originalState = (FiberStatus)Interlocked.CompareExchange(ref status, (int)FiberStatus.WaitingToRun, (int)FiberStatus.WaitingForActivation);
                if (originalState != FiberStatus.WaitingForActivation)
                {
                    throw new InvalidOperationException("A fiber cannot be started again once it has begun running or has completed.");
                }
            }

            this.scheduler = scheduler;
            ((IFiberScheduler)this.scheduler).QueueFiber(this);
        }
        /// <summary>
        /// Creates a continuation that executes asynchronously when the target fiber completes.
        /// </summary>
        /// <returns>A fiber that executes when the target fiber completes.</returns>
        /// <param name="continuationAction">Continuation action.</param>
        /// <param name="state">State.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name="continuationOptions">Continuation options.</param>
        /// <param name="scheduler">Scheduler.</param>
        public Fiber ContinueWith(Action <Fiber, object> continuationAction, object state, CancellationToken cancellationToken,
                                  FiberContinuationOptions continuationOptions, FiberScheduler scheduler)
        {
            if (continuationAction == null)
            {
                throw new ArgumentNullException("continuationAction");
            }

            if (scheduler == null)
            {
                throw new ArgumentNullException("scheduler");
            }

            var fiber = new Fiber((obj) => continuationAction(this, obj),
                                  state, cancellationToken);

            fiber.antecedent = this;
            fiber.status     = (int)FiberStatus.WaitingForActivation;

            var continuation = new FiberContinuation(fiber, continuationOptions, scheduler);

            if (IsCompleted)
            {
                continuation.Execute();
            }
            else
            {
                // Lazy create queue
                if (continuations == null)
                {
                    continuations = new Queue <FiberContinuation>();
                }

                continuations.Enqueue(continuation);
            }

            return(fiber);
        }
 /// <summary>
 /// Start executing a new fiber using the default scheduler on the thread.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="Fiber"/>
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='action'>
 /// A non-blocking action to execute on the fiber.
 /// </param>
 /// <param name='state'>
 /// State to pass to the action.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(Action<object> action, object state, FiberScheduler scheduler)
 {
     return StartNew(action, state, cancellationToken, scheduler);
 }
 /// <summary>
 /// Start executing a new fiber using the specified scheduler.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="Fiber"/>
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='coroutine'>
 /// A couroutine to execute on the fiber.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(IEnumerator coroutine, FiberScheduler scheduler)
 {
     return StartNew(coroutine, cancellationToken, scheduler);
 }
        /// <summary>
        /// Start executing the fiber using the specified scheduler.
        /// </summary>
        /// <remarks>
        /// This method is safe to call from any thread even if different
        /// than the scheduler execution thread.
        /// </remarks>
        /// <returns>
        /// Returns a <see cref="YieldUntilComplete"/> fiber instruction
        /// that can be yielded against to wait for the fiber to complete.
        /// </returns>
        /// <param name='scheduler'>
        /// The scheduler to start the fiber on.
        /// </param>
        public YieldUntilComplete Start(FiberScheduler scheduler)
        {
            // It would be unusual to attempt to start a Fiber more than once,
            // but to be safe and to support calling from any thread
            // use Interlocked with boxing on the enum.

            var originalState = (FiberState)Interlocked.CompareExchange(ref fiberState, (int)FiberState.Running, (int)FiberState.Unstarted);

            if(originalState != FiberState.Unstarted)
                throw new InvalidOperationException("A fiber cannot be started again once it has begun running or has completed.");

            this.scheduler = scheduler;
            ((IFiberScheduler)this.scheduler).QueueFiber(this);
            return new YieldUntilComplete(this);
        }
 /// <summary>
 /// Returns a fiber that completes when any fiber finishes.
 /// </summary>
 /// <remarks>
 /// `Fiber.ResultAsObject` will be the `Fiber` that completed.
 /// </remarks>
 /// <returns>A fiber that completes when any fiber finishes.</returns>
 /// <param name="fibers">Fibers to wait for completion.</param>
 /// <param name="millisecondsTimeout">Milliseconds timeout.</param>
 /// <param name="cancellationToken">Cancellation token.</param>
 /// <param name="scheduler">Scheduler.</param>
 public static Fiber WhenAny(IEnumerable<Fiber> fibers, int millisecondsTimeout, CancellationToken cancellationToken, FiberScheduler scheduler)
 {
     return WhenAny(fibers.ToArray(), millisecondsTimeout, cancellationToken, scheduler);
 }
        internal static void SetCurrentScheduler(FiberScheduler scheduler, bool internalInvoke)
        {
            // Only allow scheduler changes on a thread when a fiber is not executing.
            // Ignore this check if this is an internal invocation such as from
            // Fiber.Execute() which needs to switch schedulers on demand.
            if(!internalInvoke && Fiber.CurrentFiber != null)
                throw new InvalidOperationException("The current scheduler for the thread cannot be changed from inside an executing fiber.");

            // Skip work if nothing to change
            if(currentScheduler == scheduler)
                return;

            // Assign the scheduler
            currentScheduler = scheduler;

            // Update the synchronization context if it changed
            if(currentScheduler != null && SynchronizationContext.Current != currentScheduler.SynchronizationContext)
                SynchronizationContext.SetSynchronizationContext(currentScheduler.SynchronizationContext);
            else if(currentScheduler == null && SynchronizationContext.Current != null)
                SynchronizationContext.SetSynchronizationContext(null);
        }
 /// <summary>
 /// Start executing a new fiber using the default scheduler on the thread.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="Fiber"/>
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='action'>
 /// A non-blocking action to execute on the fiber.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(Action action, FiberScheduler scheduler)
 {
     return StartNew(action, cancellationToken, scheduler);
 }
Beispiel #17
0
 /// <summary>
 /// Returns a fiber that waits on all fibers to complete.
 /// </summary>
 /// <remarks>
 /// `Fiber.ResultAsObject` will be `true` if all fibers complete
 /// successfully or `false` if cancelled or timeout.
 /// </remarks>
 /// <returns>A fiber that waits on all fibers to complete.</returns>
 /// <param name="fibers">Fibers to wait for completion.</param>
 /// <param name="millisecondsTimeout">Milliseconds timeout.</param>
 /// <param name="cancellationToken">Cancellation token.</param>
 /// <param name="scheduler">Scheduler.</param>
 public static Fiber WhenAll(IEnumerable <Fiber> fibers, int millisecondsTimeout, CancellationToken cancellationToken, FiberScheduler scheduler)
 {
     return(WhenAll(fibers.ToArray(), millisecondsTimeout, cancellationToken, scheduler));
 }
Beispiel #18
0
 /// <summary>
 /// Start executing a new fiber using the specified scheduler.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="YieldUntilComplete"/> fiber instruction
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='coroutine'>
 /// A couroutine to execute on the fiber.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public static YieldUntilComplete StartNew(IEnumerator coroutine, FiberScheduler scheduler)
 {
     return(new Fiber(coroutine).Start(scheduler));
 }
 /// <summary>
 /// Creates a continuation that executes asynchronously when the target fiber completes.
 /// </summary>
 /// <returns>A fiber that executes when the target fiber completes.</returns>
 /// <param name="continuationCoroutine">Continuation coroutine.</param>
 /// <param name="scheduler">Scheduler.</param>
 public Fiber ContinueWith(IEnumerator continuationCoroutine, FiberScheduler scheduler)
 {
     return(ContinueWith(continuationCoroutine, CancellationToken.None, FiberContinuationOptions.None, scheduler));
 }
 /// <summary>
 /// Creates a continuation that executes asynchronously when the target fiber completes.
 /// </summary>
 /// <returns>A fiber that executes when the target fiber completes.</returns>
 /// <param name="continuationAction">Continuation action.</param>
 /// <param name="state">State.</param>
 /// <param name="scheduler">Scheduler.</param>
 public Fiber ContinueWith(Action <Fiber, object> continuationAction, object state, FiberScheduler scheduler)
 {
     return(ContinueWith(continuationAction, state, CancellationToken.None, FiberContinuationOptions.None, scheduler));
 }
 /// <summary>
 /// Returns a fiber that waits on all tasks to complete.
 /// </summary>
 /// <remarks>
 /// `Fiber.ResultAsObject` will be `true` if all tasks complete
 /// successfully or `false` if cancelled or timeout.
 /// </remarks>
 /// <returns>A fiber that waits on all tasks to complete.</returns>
 /// <param name="tasks">Tasks to wait for completion.</param>
 /// <param name="millisecondsTimeout">Milliseconds timeout.</param>
 /// <param name="cancellationToken">Cancellation token.</param>
 /// <param name="scheduler">Scheduler.</param>
 public static Fiber WhenAll(IEnumerable<Task> tasks, int millisecondsTimeout, CancellationToken cancellationToken, FiberScheduler scheduler)
 {
     return WhenAll (tasks.ToArray (), millisecondsTimeout, cancellationToken, scheduler);
 }
        /// <summary>
        /// Returns a fiber that waits on all tasks to complete.
        /// </summary>
        /// <remarks>
        /// `Fiber.ResultAsObject` will be `true` if all tasks complete
        /// successfully or `false` if cancelled or timeout.
        /// </remarks>
        /// <returns>A fiber that waits on all tasks to complete.</returns>
        /// <param name="tasks">Tasks to wait for completion.</param>
        /// <param name="millisecondsTimeout">Milliseconds timeout.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name="scheduler">Scheduler.</param>
        public static Fiber WhenAll(Task [] tasks, int millisecondsTimeout, CancellationToken cancellationToken, FiberScheduler scheduler)
        {
            if (tasks == null)
                throw new ArgumentNullException ("tasks");

            foreach (var fiber in tasks) {
                if (fiber == null)
                    throw new ArgumentException ("tasks", "the tasks argument contains a null element");
            }

            return Fiber.Factory.StartNew (WhenAllTasksCoroutine (tasks, millisecondsTimeout, cancellationToken), cancellationToken, scheduler);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="SpicyPixel.Threading.FiberSchedulerSynchronizationContext"/> class.
 /// </summary>
 /// <param name='scheduler'>
 /// The scheduler to send or post callbacks to.
 /// </param>
 public FiberSchedulerSynchronizationContext(FiberScheduler scheduler)
 {
     this.scheduler = scheduler;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="SpicyPixel.Threading.Fiber"/> class.
 /// </summary>
 /// <param name='func'>
 /// A non-blocking function that returns a <see cref="Fiber"/> when complete.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(Func<FiberInstruction> func, FiberScheduler scheduler)
 {
     return StartNew(func, cancellationToken, scheduler);
 }
Beispiel #25
0
 /// <summary>
 /// Start executing a new fiber using the default scheduler on the thread.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="YieldUntilComplete"/> fiber instruction
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='action'>
 /// A non-blocking action to execute on the fiber.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 /// <param name='state'>
 /// State to pass to the action.
 /// </param>
 public static YieldUntilComplete StartNew(Action <object> action, object state, FiberScheduler scheduler)
 {
     return(new Fiber(action, state).Start(scheduler));
 }
 /// <summary>
 /// Start executing a new fiber using the default scheduler on the thread.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="Fiber"/>
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='action'>
 /// A non-blocking action to execute on the fiber.
 /// </param>
 /// <param name='state'>
 /// State to pass to the action.
 /// </param>
 /// <param name="cancellationToken">Cancellation token.</param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(Action<object> action, object state, CancellationToken cancellationToken, FiberScheduler scheduler)
 {
     var fiber = new Fiber(action, state, cancellationToken);
     fiber.Start(scheduler);
     return fiber;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="SpicyPixel.Threading.Fiber"/> class.
 /// </summary>
 /// <param name='func'>
 /// A non-blocking function that returns a <see cref="Fiber"/> when complete.
 /// </param>
 /// <param name='state'>
 /// State to pass to the function.
 /// </param>
 /// <param name="cancellationToken">Cancellation token.</param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(Func<object, FiberInstruction> func, object state, CancellationToken cancellationToken, FiberScheduler scheduler)
 {
     var fiber = new Fiber(func, state, cancellationToken);
     fiber.Start(scheduler);
     return fiber;
 }
        /// <summary>
        /// Returns a fiber that completes when any fiber finishes.
        /// </summary>
        /// <remarks>
        /// `Fiber.ResultAsObject` will be the `Fiber` that completed.
        /// </remarks>
        /// <returns>A fiber that completes when any fiber finishes.</returns>
        /// <param name="fibers">Fibers to wait for completion.</param>
        /// <param name="millisecondsTimeout">Milliseconds timeout.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name="scheduler">Scheduler.</param>
        public static Fiber WhenAny(Fiber[] fibers, int millisecondsTimeout, CancellationToken cancellationToken, FiberScheduler scheduler)
        {
            if (fibers == null)
            {
                throw new ArgumentNullException("fibers");
            }

            foreach (var fiber in fibers)
            {
                if (fiber == null)
                {
                    throw new ArgumentException("fibers", "the fibers argument contains a null element");
                }
            }

            return(Fiber.Factory.StartNew(WhenAnyFibersCoroutine(fibers, millisecondsTimeout, cancellationToken), cancellationToken, scheduler));
        }
 /// <summary>
 /// Start executing a new fiber using the specified scheduler.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="YieldUntilComplete"/> fiber instruction
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='coroutine'>
 /// A couroutine to execute on the fiber.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public static YieldUntilComplete StartNew(IEnumerator coroutine, FiberScheduler scheduler)
 {
     return new Fiber(coroutine).Start(scheduler);
 }
Beispiel #30
0
        /// <summary>
        /// Start executing a new fiber using the specified scheduler.
        /// </summary>
        /// <returns>
        /// Returns a <see cref="Fiber"/>
        /// that can be yielded against to wait for the fiber to complete.
        /// </returns>
        /// <param name='coroutine'>
        /// A couroutine to execute on the fiber.
        /// </param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name='scheduler'>
        /// A scheduler to execute the fiber on.
        /// </param>
        public Fiber StartNew(IEnumerator coroutine, CancellationToken cancellationToken, FiberScheduler scheduler)
        {
            var fiber = new Fiber(coroutine, cancellationToken);

            fiber.Start(scheduler);
            return(fiber);
        }
 /// <summary>
 /// Start executing a new fiber using the default scheduler on the thread.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="YieldUntilComplete"/> fiber instruction
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='action'>
 /// A non-blocking action to execute on the fiber.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 /// <param name='state'>
 /// State to pass to the action.
 /// </param>
 public static YieldUntilComplete StartNew(Action<object> action, object state, FiberScheduler scheduler)
 {
     return new Fiber(action, state).Start(scheduler);
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="SpicyPixel.Threading.Fiber"/> class.
 /// </summary>
 /// <param name='func'>
 /// A non-blocking function that returns a <see cref="Fiber"/> when complete.
 /// </param>
 /// <param name='state'>
 /// State to pass to the function.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(Func<object, FiberInstruction> func, object state, FiberScheduler scheduler)
 {
     return StartNew(func, state, cancellationToken, scheduler);
 }
 /// <summary>
 /// Start executing a new fiber using the specified scheduler.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="Fiber"/>
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='coroutine'>
 /// A couroutine to execute on the fiber.
 /// </param>
 /// <param name="cancellationToken">Cancellation token.</param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(IEnumerator coroutine, CancellationToken cancellationToken, FiberScheduler scheduler)
 {
     var fiber = new Fiber(coroutine, cancellationToken);
     fiber.Start(scheduler);
     return fiber;
 }
Beispiel #34
0
 /// <summary>
 /// Start executing a new fiber using the default scheduler on the thread.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="YieldUntilComplete"/> fiber instruction
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='action'>
 /// A non-blocking action to execute on the fiber.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public static YieldUntilComplete StartNew(Action action, FiberScheduler scheduler)
 {
     return(new Fiber(action).Start(scheduler));
 }
Beispiel #35
0
        /// <summary>
        /// Executes the fiber until it ends or yields.
        /// </summary>
        /// <returns>
        /// A fiber instruction to be processed by the scheduler.
        /// </returns>
        internal FiberInstruction Execute()
        {
            //Console.WriteLine ("Fiber {0}:{1} start executing", Id, Status);

            // Sanity check the scheduler. Since this is a scheduler
            // only issue, this test happens first before execution
            // and before allowing an exception handler to take over.
            if (IsCompleted)
            {
                throw new InvalidOperationException("An attempt was made to execute a completed Fiber. This indicates a logic error in the scheduler.");
            }

            // Setup thread globals with this scheduler as the owner.
            // The sync context is also setup when the scheduler changes.
            // Setting the sync context isn't a simple assign in .NET
            // so don't do this until needed.
            //
            // Doing this setup in Execute() frees derived schedulers from the
            // burden of setting up the sync context or scheduler. It also allows the
            // current scheduler to change on demand when there is more than one
            // scheduler running per thread.
            //
            // For example, each MonoBehaviour in Unity is assigned its own
            // scheduler since the behavior determines the lifetime of tasks.
            // The active scheduler then can vary depending on which behavior is
            // currently executing tasks. Unity will decide outside of this framework
            // which behaviour to execute in which order and therefore which
            // scheduler is active. The active scheduler in this case can
            // only be determined at the time of fiber execution.
            //
            // Unlike CurrentFiber below, this does not need to be stacked
            // once set because the scheduler will never change during fiber
            // execution. Only something outside of the scheduler would
            // change the scheduler.
            if (FiberScheduler.Current != scheduler)
            {
                FiberScheduler.SetCurrentScheduler(scheduler, true);
            }

            // Push the current fiber onto the stack and pop it in finally.
            // This must be stacked because the fiber may spawn another
            // fiber which the scheduler may choose to inline which would result
            // in a new fiber temporarily taking its place as current.
            var lastFiber = Fiber.CurrentFiber;

            Fiber.CurrentFiber = this;

            // Start the fiber if not started
            Interlocked.CompareExchange(ref status, (int)FiberStatus.WaitingToRun, (int)FiberStatus.Created);
            Interlocked.CompareExchange(ref status, (int)FiberStatus.Running, (int)FiberStatus.WaitingToRun);

            try {
                object result = null;

                // Execute the coroutine or action
                if (coroutine != null)
                {
                    //Console.WriteLine ("Fiber {0}:{1} start executing coroutine", Id, Status);
                    // Execute coroutine
                    if (coroutine.MoveNext())
                    {
                        // Get result of execution
                        result = coroutine.Current;

                        // If the coroutine returned a stop directly
                        // the fiber still needs to process it
                        if (result is StopInstruction)
                        {
                            Stop(FiberStatus.RanToCompletion);
                        }
                    }
                    else
                    {
                        // Coroutine finished executing
                        result = Stop(FiberStatus.RanToCompletion);
                    }
                    //Console.WriteLine ("Fiber {0}:{1} end executing coroutine", Id, Status);
                }
                else if (action != null)
                {
                    // Execute action
                    action();

                    // Action finished executing
                    result = Stop(FiberStatus.RanToCompletion);
                }
                else if (actionObject != null)
                {
                    // Execute action
                    actionObject(objectState);

                    // Action finished executing
                    result = Stop(FiberStatus.RanToCompletion);
                }
                else if (func != null)
                {
                    result = func();
                    func   = null;

                    if (result is StopInstruction)
                    {
                        Stop(FiberStatus.RanToCompletion);
                    }
                }
                else if (funcObject != null)
                {
                    result     = funcObject(objectState);
                    funcObject = null;

                    if (result is StopInstruction)
                    {
                        Stop(FiberStatus.RanToCompletion);
                    }
                }
                else
                {
                    // Func execution nulls out the function
                    // so the scheduler will return to here
                    // when complete and then stop.
                    result = Stop(FiberStatus.RanToCompletion);
                }

                // Treat null as a special case
                if (result == null)
                {
                    return(FiberInstruction.YieldToAnyFiber);
                }

                // Return instructions or throw if invalid
                var instruction = result as FiberInstruction;
                if (instruction == null)
                {
                    // If the result was an enumerator there is a nested coroutine to execute
                    if (result is IEnumerator)
                    {
                        instruction = new YieldUntilComplete(Fiber.Factory.StartNew(result as IEnumerator, cancelToken, scheduler));
                    }
                    else if (result is Fiber)
                    {
                        // Convert fibers into yield instructions
                        instruction = new YieldUntilComplete(result as Fiber);
                    }
                    else
                    {
                        // Pass through other values
                        return(new ObjectInstruction(result));
                    }
                }

                if (instruction is FiberResult)
                {
                    ResultAsObject = ((FiberResult)instruction).Result;
                    result         = Stop(FiberStatus.RanToCompletion);
                }

                // Verify same scheduler
                if (instruction is YieldUntilComplete && ((YieldUntilComplete)instruction).Fiber.Scheduler != FiberScheduler.Current)
                {
                    throw new InvalidOperationException("Currently only fibers belonging to the same scheduler may be yielded to. FiberScheduler.Current = "
                                                        + (FiberScheduler.Current == null ? "null" : FiberScheduler.Current.ToString())
                                                        + ", Fiber.Scheduler = " + (((YieldUntilComplete)instruction).Fiber.Scheduler == null ? "null" : ((YieldUntilComplete)instruction).Fiber.Scheduler.ToString()));
                }

                var yieldToFiberInstruction = instruction as YieldToFiber;
                if (yieldToFiberInstruction != null)
                {
                    // Start fibers yielded to that aren't running yet
                    Interlocked.CompareExchange(ref yieldToFiberInstruction.Fiber.status, (int)FiberStatus.WaitingToRun, (int)FiberStatus.Created);
                    var originalState = (FiberStatus)Interlocked.CompareExchange(ref yieldToFiberInstruction.Fiber.status, (int)FiberStatus.Running, (int)FiberStatus.WaitingToRun);
                    if (originalState == FiberStatus.WaitingToRun)
                    {
                        yieldToFiberInstruction.Fiber.scheduler = scheduler;
                    }

                    // Can't switch to completed fibers
                    if (yieldToFiberInstruction.Fiber.IsCompleted)
                    {
                        throw new InvalidOperationException("An attempt was made to yield to a completed fiber.");
                    }

                    // Verify scheduler
                    if (yieldToFiberInstruction.Fiber.Scheduler != FiberScheduler.Current)
                    {
                        throw new InvalidOperationException("Currently only fibers belonging to the same scheduler may be yielded to. FiberScheduler.Current = "
                                                            + (FiberScheduler.Current == null ? "null" : FiberScheduler.Current.ToString())
                                                            + ", Fiber.Scheduler = " + (yieldToFiberInstruction.Fiber.Scheduler == null ? "null" : yieldToFiberInstruction.Fiber.Scheduler.ToString()));
                    }
                }

                //Console.WriteLine ("Fiber {0}:{1} returning {2}", Id, Status, instruction);
                return(instruction);
            } catch (System.Threading.OperationCanceledException cancelException) {
                // Handle as proper cancellation only if the token matches.
                // Otherwise treat it as a fault.
                if (cancelException.CancellationToken == cancelToken)
                {
                    this.Exception = null;
                    return(Stop(FiberStatus.Canceled));
                }
                else
                {
                    this.Exception = cancelException;
                    return(Stop(FiberStatus.Faulted));
                }
            } catch (Exception fiberException) {
                this.Exception = fiberException;
                return(Stop(FiberStatus.Faulted));
            } finally {
                // Pop the current fiber
                Fiber.CurrentFiber = lastFiber;

                //Console.WriteLine ("Fiber {0}:{1} end executing", Id, Status);
            }
        }
Beispiel #36
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SpicyPixel.Threading.Fiber"/> class.
 /// </summary>
 /// <param name='func'>
 /// A non-blocking function that returns a <see cref="FiberInstruction"/> when complete.
 /// </param>
 /// <param name='state'>
 /// State to pass to the function.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public static YieldUntilComplete StartNew(Func <object, FiberInstruction> func, object state, FiberScheduler scheduler)
 {
     return(new Fiber(func, state).Start(scheduler));
 }
 public FiberContinuation(Fiber fiber, FiberContinuationOptions options, FiberScheduler scheduler)
 {
     this.fiber = fiber;
     this.options = options;
     this.scheduler = scheduler;
 }
Beispiel #38
0
        /// <summary>
        /// Executes the fiber until it ends or yields.
        /// </summary>
        /// <returns>
        /// A fiber instruction to be processed by the scheduler.
        /// </returns>
        internal FiberInstruction Execute()
        {
            // Sanity check the scheduler. Since this is a scheduler
            // only issue, this test happens first before execution
            // and before allowing an exception handler to take over.
            if (FiberState == FiberState.Stopped)
            {
                throw new InvalidOperationException("An attempt was made to execute a stopped Fiber. This indicates a logic error in the scheduler.");
            }

            // Setup thread globals with this scheduler as the owner.
            // The sync context is also setup when the scheduler changes.
            // Setting the sync context isn't a simple assign in .NET
            // so don't do this until needed.
            //
            // Doing this setup in Execute() frees derived schedulers from the
            // burden of setting up the sync context or scheduler. It also allows the
            // current scheduler to change on demand when there is more than one
            // scheduler running per thread.
            //
            // For example, each MonoBehaviour in Unity is assigned its own
            // scheduler since the behavior determines the lifetime of tasks.
            // The active scheduler then can vary depending on which behavior is
            // currently executing tasks. Unity will decide outside of this framework
            // which behaviour to execute in which order and therefore which
            // scheduler is active. The active scheduler in this case can
            // only be determined at the time of fiber execution.
            //
            // Unlike CurrentFiber below, this does not need to be stacked
            // once set because the scheduler will never change during fiber
            // execution. Only something outside of the scheduler would
            // change the scheduler.
            if (FiberScheduler.Current != scheduler)
            {
                FiberScheduler.SetCurrentScheduler(scheduler, true);
            }

            // Push the current fiber onto the stack and pop it in finally.
            // This must be stacked because the fiber may spawn another
            // fiber which the scheduler may choose to inline which would result
            // in a new fiber temporarily taking its place as current.
            var lastFiber = Fiber.CurrentFiber;

            Fiber.CurrentFiber = this;

            try
            {
                // Process an abort if pending
                if (FiberState == FiberState.AbortRequested)
                {
                    throw new FiberAbortException();
                }

                object result;

                // Execute the coroutine or action
                if (coroutine != null)
                {
                    // Execute coroutine
                    if (coroutine.MoveNext())
                    {
                        // Get result of execution
                        result = coroutine.Current;
                    }
                    else
                    {
                        // Coroutine finished executing
                        result = Stop();
                    }
                }
                else if (action != null)
                {
                    // Execute action
                    action();

                    // Action finished executing
                    result = Stop();
                }
                else if (actionObject != null)
                {
                    // Execute action
                    actionObject(objectState);

                    // Action finished executing
                    result = Stop();
                }
                else if (func != null)
                {
                    result = func();
                    func   = null;
                }
                else if (funcObject != null)
                {
                    result     = funcObject(objectState);
                    funcObject = null;
                }
                else
                {
                    // Func execution nulls out the function
                    // so the scheduler will return to here
                    // when complete and then stop.
                    result = Stop();
                }

                // Treat null as a special case
                if (result == null)
                {
                    return(FiberInstruction.YieldToAnyFiber);
                }

                // Return instructions or throw if invalid
                var instruction = result as FiberInstruction;
                if (instruction == null)
                {
                    return(new ObjectInstruction(result));
                }
                else
                {
                    // Verify same scheduler
                    if (instruction is YieldUntilComplete && ((YieldUntilComplete)instruction).Fiber.Scheduler != FiberScheduler.Current)
                    {
                        throw new InvalidOperationException("Currently only fibers belonging to the same scheduler may be yielded to. FiberScheduler.Current = "
                                                            + (FiberScheduler.Current == null ? "null" : FiberScheduler.Current.ToString())
                                                            + ", Fiber.Scheduler = " + (((YieldUntilComplete)instruction).Fiber.Scheduler == null ? "null" : ((YieldUntilComplete)instruction).Fiber.Scheduler.ToString()));
                    }

                    var yieldToFiberInstruction = instruction as YieldToFiber;
                    if (yieldToFiberInstruction != null)
                    {
                        // Start fibers yielded to that aren't running yet
                        var originalState = (FiberState)Interlocked.CompareExchange(ref yieldToFiberInstruction.Fiber.fiberState, (int)FiberState.Running, (int)FiberState.Unstarted);
                        if (originalState == FiberState.Unstarted)
                        {
                            yieldToFiberInstruction.Fiber.scheduler = scheduler;
                        }

                        // Can't switch to stopped fibers
                        if (yieldToFiberInstruction.Fiber.FiberState == FiberState.Stopped)
                        {
                            throw new InvalidOperationException("An attempt was made to yield to a stopped fiber.");
                        }

                        // Verify scheduler
                        if (yieldToFiberInstruction.Fiber.Scheduler != FiberScheduler.Current)
                        {
                            throw new InvalidOperationException("Currently only fibers belonging to the same scheduler may be yielded to. FiberScheduler.Current = "
                                                                + (FiberScheduler.Current == null ? "null" : FiberScheduler.Current.ToString())
                                                                + ", Fiber.Scheduler = " + (yieldToFiberInstruction.Fiber.Scheduler == null ? "null" : yieldToFiberInstruction.Fiber.Scheduler.ToString()));
                        }
                    }

                    return(instruction);
                }
            }
            catch (Exception fiberException)
            {
                // If an exception occurs allow the handler to run.
                // Fiber execution will terminate even with a handler
                // because it's not possible to resume an action or a
                // coroutine that throws an exception.
                //
                // The only exception that could result in a contiunation
                // is FiberAbortException. Handlers may choose to deny
                // the abort by calling Fiber.ResetAbort().
                try
                {
                    // Invoke the exception handler (which could throw)
                    var unhandledException = this.unhandledException;
                    var eventArgs          = new FiberUnhandledExceptionEventArgs(this, fiberException);
                    if (unhandledException != null)
                    {
                        foreach (var subscriber in unhandledException.GetInvocationList())
                        {
                            subscriber.DynamicInvoke(this, eventArgs);
                            if (eventArgs.Handled)
                            {
                                break;
                            }
                        }
                    }

                    // See if an abort was requested. The flag is thread safe because
                    // it is only ever touched by the scheduler thread.
                    if (resetAbortRequested)
                    {
                        resetAbortRequested = false;
                        fiberState          = (int)FiberState.Running;
                        return(FiberInstruction.YieldToAnyFiber);                        // signal the scheduler to continue
                    }
                    else
                    {
                        if (!eventArgs.Handled)
                        {
                            throw fiberException;
                        }
                        else
                        {
                            return(Stop());
                        }
                    }
                }
                catch (Exception fiberOrHandlerException)
                {
                    // The exception wasn't from an abort or it wasn't reset
                    // and so the exception needs to happen.

                    // Clear reset requests (if any). This is needed here in case
                    // the exceptionHandler above threw after ResetAbort() was
                    // called.
                    //
                    // The flag is thread safe because
                    // it is only ever touched by the scheduler thread.
                    resetAbortRequested = false;

                    // Stop the fiber. This will invoke completion handlers
                    // but they won't know this fiber failed due to an exception
                    // unless they handled the exception above or wait for
                    // the scheduler to do something after the throw below.
                    Stop();

                    // Throw the exception back to the scheduler.
                    throw fiberOrHandlerException;
                }
            }
            finally
            {
                // Pop the current fiber
                Fiber.CurrentFiber = lastFiber;
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="SpicyPixel.Threading.FiberFactory"/> class.
 /// </summary>
 /// <param name="scheduler">Scheduler.</param>
 public FiberFactory(FiberScheduler scheduler)
     : this(CancellationToken.None, FiberContinuationOptions.None, scheduler)
 {
 }
 /// <summary>
 /// Start executing a new fiber using the default scheduler on the thread.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="YieldUntilComplete"/> fiber instruction
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='action'>
 /// A non-blocking action to execute on the fiber.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public static YieldUntilComplete StartNew(Action action, FiberScheduler scheduler)
 {
     return new Fiber(action).Start(scheduler);
 }
Beispiel #41
0
 /// <summary>
 /// Start executing a new fiber using the default scheduler on the thread.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="Fiber"/>
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='action'>
 /// A non-blocking action to execute on the fiber.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(Action action, FiberScheduler scheduler)
 {
     return(StartNew(action, cancellationToken, scheduler));
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="SpicyPixel.Threading.Fiber"/> class.
 /// </summary>
 /// <param name='func'>
 /// A non-blocking function that returns a <see cref="FiberInstruction"/> when complete.
 /// </param>
 /// <param name='state'>
 /// State to pass to the function.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public static YieldUntilComplete StartNew(Func<object, FiberInstruction> func, object state, FiberScheduler scheduler)
 {
     return new Fiber(func, state).Start(scheduler);
 }
        /// <summary>
        /// Crates a Fiber that waits for a delay before completing.
        /// </summary>
        /// <param name="millisecondsDelay">Milliseconds to delay.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name="scheduler">Scheduler.</param>
        public static Fiber Delay(int millisecondsDelay, CancellationToken cancellationToken, FiberScheduler scheduler)
        {
            if (millisecondsDelay < -1)
            {
                throw new ArgumentOutOfRangeException("millisecondsDelay");
            }

            return(Fiber.Factory.StartNew(DelayCoroutine(millisecondsDelay, cancellationToken), scheduler));
        }
Beispiel #44
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SpicyPixel.Threading.FiberFactory"/> class.
 /// </summary>
 /// <param name="scheduler">Scheduler.</param>
 public FiberFactory(FiberScheduler scheduler)
     : this(CancellationToken.None, FiberContinuationOptions.None, scheduler)
 {
 }
 /// <summary>
 /// Creates a continuation that executes asynchronously when the target fiber completes.
 /// </summary>
 /// <returns>A fiber that executes when the target fiber completes.</returns>
 /// <param name="continuationAction">Continuation action.</param>
 /// <param name="state">State.</param>
 /// <param name="scheduler">Scheduler.</param>
 public Fiber ContinueWith(Action<Fiber, object> continuationAction, object state, FiberScheduler scheduler)
 {
     return ContinueWith(continuationAction, state, CancellationToken.None, FiberContinuationOptions.None, scheduler);
 }
Beispiel #46
0
 public FiberContinuation(Fiber fiber, FiberContinuationOptions options, FiberScheduler scheduler)
 {
     this.fiber     = fiber;
     this.options   = options;
     this.scheduler = scheduler;
 }
 /// <summary>
 /// Start executing a new fiber using the default scheduler on the thread.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="Fiber"/>
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='action'>
 /// A non-blocking action to execute on the fiber.
 /// </param>
 /// <param name="cancellationToken">Cancellation token.</param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(Action action, CancellationToken cancellationToken, FiberScheduler scheduler)
 {
     var fiber = new Fiber(action, cancellationToken);
     fiber.Start(scheduler);
     return fiber;
 }
 /// <summary>
 /// Creates a continuation that executes asynchronously when the target fiber completes.
 /// </summary>
 /// <returns>A fiber that executes when the target fiber completes.</returns>
 /// <param name="continuationAction">Continuation action.</param>
 /// <param name="cancellationToken">Cancellation token.</param>
 /// <param name="continuationOptions">Continuation options.</param>
 /// <param name="scheduler">Scheduler.</param>
 public Fiber ContinueWith(Action<Fiber> continuationAction, CancellationToken cancellationToken,
                            FiberContinuationOptions continuationOptions, FiberScheduler scheduler)
 {
     return ContinueWith((fiber, state) => continuationAction(fiber), null, cancellationToken, continuationOptions, scheduler);
 }
Beispiel #49
0
 /// <summary>
 /// Start executing a new fiber using the default scheduler on the thread.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="Fiber"/>
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='action'>
 /// A non-blocking action to execute on the fiber.
 /// </param>
 /// <param name='state'>
 /// State to pass to the action.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(Action <object> action, object state, FiberScheduler scheduler)
 {
     return(StartNew(action, state, cancellationToken, scheduler));
 }
 /// <summary>
 /// Creates a continuation that executes asynchronously when the target fiber completes.
 /// </summary>
 /// <returns>A fiber that executes when the target fiber completes.</returns>
 /// <param name="continuationCoroutine">Continuation coroutine.</param>
 /// <param name="scheduler">Scheduler.</param>
 public Fiber ContinueWith(IEnumerator continuationCoroutine, FiberScheduler scheduler)
 {
     return ContinueWith(continuationCoroutine, CancellationToken.None, FiberContinuationOptions.None, scheduler);
 }
Beispiel #51
0
        /// <summary>
        /// Start executing a new fiber using the default scheduler on the thread.
        /// </summary>
        /// <returns>
        /// Returns a <see cref="Fiber"/>
        /// that can be yielded against to wait for the fiber to complete.
        /// </returns>
        /// <param name='action'>
        /// A non-blocking action to execute on the fiber.
        /// </param>
        /// <param name='state'>
        /// State to pass to the action.
        /// </param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name='scheduler'>
        /// A scheduler to execute the fiber on.
        /// </param>
        public Fiber StartNew(Action <object> action, object state, CancellationToken cancellationToken, FiberScheduler scheduler)
        {
            var fiber = new Fiber(action, state, cancellationToken);

            fiber.Start(scheduler);
            return(fiber);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="SpicyPixel.Threading.FiberSchedulerSynchronizationContext"/> class.
 /// </summary>
 /// <param name='scheduler'>
 /// The scheduler to send or post callbacks to.
 /// </param>
 public FiberSchedulerSynchronizationContext(FiberScheduler scheduler)
 {
     this.scheduler = scheduler;
 }
Beispiel #53
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SpicyPixel.Threading.Fiber"/> class.
 /// </summary>
 /// <param name='func'>
 /// A non-blocking function that returns a <see cref="Fiber"/> when complete.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(Func <FiberInstruction> func, FiberScheduler scheduler)
 {
     return(StartNew(func, cancellationToken, scheduler));
 }
Beispiel #54
0
        /// <summary>
        /// Start executing the fiber using the specified scheduler.
        /// </summary>
        /// <remarks>
        /// This method is safe to call from any thread even if different
        /// than the scheduler execution thread.
        /// </remarks>
        /// <param name='scheduler'>
        /// The scheduler to start the fiber on.
        /// </param>
        public void Start(FiberScheduler scheduler)
        {
            // It would be unusual to attempt to start a Fiber more than once,
            // but to be safe and to support calling from any thread
            // use Interlocked with boxing on the enum.

            var originalState = (FiberStatus)Interlocked.CompareExchange (ref status, (int)FiberStatus.WaitingToRun, (int)FiberStatus.Created);
            if (originalState != FiberStatus.Created) {
                originalState = (FiberStatus)Interlocked.CompareExchange (ref status, (int)FiberStatus.WaitingToRun, (int)FiberStatus.WaitingForActivation);
                if (originalState != FiberStatus.WaitingForActivation) {
                    throw new InvalidOperationException ("A fiber cannot be started again once it has begun running or has completed.");
                }
            }

            this.scheduler = scheduler;
            ((IFiberScheduler)this.scheduler).QueueFiber (this);
        }
Beispiel #55
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SpicyPixel.Threading.Fiber"/> class.
 /// </summary>
 /// <param name='func'>
 /// A non-blocking function that returns a <see cref="Fiber"/> when complete.
 /// </param>
 /// <param name='state'>
 /// State to pass to the function.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(Func <object, FiberInstruction> func, object state, FiberScheduler scheduler)
 {
     return(StartNew(func, state, cancellationToken, scheduler));
 }
 /// <summary>
 /// Returns a fiber that completes when any task finishes.
 /// </summary>
 /// <remarks>
 /// `Fiber.ResultAsObject` will be the `Task` that completed.
 /// </remarks>
 /// <returns>A fiber that completes when any task finishes.</returns>
 /// <param name="tasks">Tasks to wait for completion.</param>
 /// <param name="millisecondsTimeout">Milliseconds timeout.</param>
 /// <param name="cancellationToken">Cancellation token.</param>
 /// <param name="scheduler">Scheduler.</param>
 public static Fiber WhenAny(IEnumerable <Task> tasks, int millisecondsTimeout, CancellationToken cancellationToken, FiberScheduler scheduler)
 {
     return(WhenAny(tasks.ToArray(), millisecondsTimeout, cancellationToken, scheduler));
 }
Beispiel #57
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SpicyPixel.Threading.Fiber"/> class.
        /// </summary>
        /// <param name='func'>
        /// A non-blocking function that returns a <see cref="Fiber"/> when complete.
        /// </param>
        /// <param name='state'>
        /// State to pass to the function.
        /// </param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name='scheduler'>
        /// A scheduler to execute the fiber on.
        /// </param>
        public Fiber StartNew(Func <object, FiberInstruction> func, object state, CancellationToken cancellationToken, FiberScheduler scheduler)
        {
            var fiber = new Fiber(func, state, cancellationToken);

            fiber.Start(scheduler);
            return(fiber);
        }
 /// <summary>
 /// Initializes the task factory during Awake().
 /// </summary>
 /// <remarks>
 /// The task factory cannot be initialized in the constructor
 /// because it must be initialized from the coroutine
 /// execution thread which the constructor does not guarantee.
 /// </remarks>
 protected virtual void Awake()
 {
     _taskFactory = this.CreateTaskFactory();
     _taskScheduler = _taskFactory.Scheduler;
     _fiberScheduler = ((FiberTaskScheduler)_taskScheduler).FiberScheduler;
     _fiberFactory = new FiberFactory(_fiberScheduler);
 }
Beispiel #59
0
 /// <summary>
 /// Start executing a new fiber using the specified scheduler.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="Fiber"/>
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='coroutine'>
 /// A couroutine to execute on the fiber.
 /// </param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(IEnumerator coroutine, FiberScheduler scheduler)
 {
     return(StartNew(coroutine, cancellationToken, scheduler));
 }