Пример #1
0
        /// <summary>
        /// Runs until no runnable tasklets left.
        /// This function is reentrant.
        /// </summary>
        public void Run()
        {
#if SILICONSTUDIO_PLATFORM_UWP
            int managedThreadId = 0;
#else
            int managedThreadId = Thread.CurrentThread.ManagedThreadId;
#endif

            MicroThreadCallbackList callbacks = default(MicroThreadCallbackList);

            while (true)
            {
                SchedulerEntry schedulerEntry;
                MicroThread    microThread;
                lock (scheduledEntries)
                {
                    // Reclaim callbacks of previous microthread
                    MicroThreadCallbackNode callback;
                    while (callbacks.TakeFirst(out callback))
                    {
                        callback.Clear();
                        callbackNodePool.Add(callback);
                    }

                    if (scheduledEntries.Count == 0)
                    {
                        break;
                    }
                    schedulerEntry = scheduledEntries.Dequeue();
                    microThread    = schedulerEntry.MicroThread;
                    if (microThread != null)
                    {
                        callbacks             = microThread.Callbacks;
                        microThread.Callbacks = default(MicroThreadCallbackList);
                    }
                }

                // Since it can be reentrant, it should be restored after running the callback.
                var previousRunningMicrothread = runningMicroThread.Value;
                if (previousRunningMicrothread != null)
                {
                    MicroThreadCallbackEnd?.Invoke(this, new SchedulerThreadEventArgs(previousRunningMicrothread, managedThreadId));
                }

                runningMicroThread.Value = microThread;

                if (microThread != null)
                {
                    var previousSyncContext = SynchronizationContext.Current;
                    SynchronizationContext.SetSynchronizationContext(microThread.SynchronizationContext);

                    // TODO: Do we still need to try/catch here? Everything should be caught in the continuation wrapper and put into MicroThread.Exception
                    try
                    {
                        if (microThread.State == MicroThreadState.Starting)
                        {
                            MicroThreadStarted?.Invoke(this, new SchedulerThreadEventArgs(microThread, managedThreadId));
                        }

                        MicroThreadCallbackStart?.Invoke(this, new SchedulerThreadEventArgs(microThread, managedThreadId));

                        using (Profiler.Begin(MicroThreadProfilingKeys.ProfilingKey, microThread.ScriptId))
                        {
                            var callback = callbacks.First;
                            while (callback != null)
                            {
                                callback.Invoke();
                                callback = callback.Next;
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        Log.Error("Unexpected exception while executing a micro-thread", e);
                        microThread.SetException(e);
                    }
                    finally
                    {
                        MicroThreadCallbackEnd?.Invoke(this, new SchedulerThreadEventArgs(microThread, managedThreadId));

                        SynchronizationContext.SetSynchronizationContext(previousSyncContext);
                        if (microThread.IsOver)
                        {
                            lock (microThread.AllLinkedListNode)
                            {
                                if (microThread.CompletionTask != null)
                                {
                                    if (microThread.State == MicroThreadState.Failed || microThread.State == MicroThreadState.Canceled)
                                    {
                                        microThread.CompletionTask.TrySetException(microThread.Exception);
                                    }
                                    else
                                    {
                                        microThread.CompletionTask.TrySetResult(1);
                                    }
                                }
                                else if (microThread.State == MicroThreadState.Failed && microThread.Exception != null)
                                {
                                    // Nothing was listening on the micro thread and it crashed
                                    // Let's treat it as unhandled exception and propagate it
                                    // Use ExceptionDispatchInfo.Capture to not overwrite callstack
                                    if (PropagateExceptions && (microThread.Flags & MicroThreadFlags.IgnoreExceptions) != MicroThreadFlags.IgnoreExceptions)
                                    {
                                        ExceptionDispatchInfo.Capture(microThread.Exception).Throw();
                                    }
                                }

                                MicroThreadEnded?.Invoke(this, new SchedulerThreadEventArgs(microThread, managedThreadId));
                            }
                        }

                        runningMicroThread.Value = previousRunningMicrothread;
                        if (previousRunningMicrothread != null)
                        {
                            MicroThreadCallbackStart?.Invoke(this, new SchedulerThreadEventArgs(previousRunningMicrothread, managedThreadId));
                        }
                    }
                }
                else
                {
                    try
                    {
                        schedulerEntry.Action();
                    }
                    catch (Exception e)
                    {
                        ActionException?.Invoke(this, schedulerEntry, e);
                    }
                }
            }

            while (FrameChannel.Balance < 0)
            {
                FrameChannel.Send(0);
            }
        }
Пример #2
0
        /// <summary>
        /// Runs until no runnable tasklets left.
        /// This function is reentrant.
        /// </summary>
        public void Run()
        {
#if SILICONSTUDIO_PLATFORM_WINDOWS_RUNTIME
            int managedThreadId = 0;
#else
            int managedThreadId = Thread.CurrentThread.ManagedThreadId;
#endif

            MicroThreadCallbackList callbacks = default(MicroThreadCallbackList);

            while (true)
            {
                MicroThread microThread;
                lock (scheduledMicroThreads)
                {
                    // Reclaim callbacks of previous microthread
                    MicroThreadCallbackNode callback;
                    while (callbacks.TakeFirst(out callback))
                    {
                        callback.Clear();
                        callbackNodePool.Add(callback);
                    }

                    if (scheduledMicroThreads.Count == 0)
                    {
                        break;
                    }
                    microThread = scheduledMicroThreads.Dequeue();

                    callbacks             = microThread.Callbacks;
                    microThread.Callbacks = default(MicroThreadCallbackList);
                }

                // Since it can be reentrant, it should be restored after running the callback.
                var previousRunningMicrothread = runningMicroThread.Value;
                if (previousRunningMicrothread != null)
                {
                    if (MicroThreadCallbackEnd != null)
                    {
                        MicroThreadCallbackEnd(this, new SchedulerThreadEventArgs(previousRunningMicrothread, managedThreadId));
                    }
                }

                runningMicroThread.Value = microThread;
                var previousSyncContext = SynchronizationContext.Current;
                SynchronizationContext.SetSynchronizationContext(microThread.SynchronizationContext);
                try
                {
                    if (microThread.State == MicroThreadState.Starting && MicroThreadStarted != null)
                    {
                        MicroThreadStarted(this, new SchedulerThreadEventArgs(microThread, managedThreadId));
                    }

                    if (MicroThreadCallbackStart != null)
                    {
                        MicroThreadCallbackStart(this, new SchedulerThreadEventArgs(microThread, managedThreadId));
                    }

                    using (Profiler.Begin(microThread.ProfilingKey))
                    {
                        var callback = callbacks.First;
                        while (callback != null)
                        {
                            microThread.ThrowIfExceptionRequest();
                            callback.Invoke();
                            callback = callback.Next;
                        }
                        microThread.ThrowIfExceptionRequest();
                    }
                }
                catch (Exception e)
                {
                    Log.Error("Unexpected exception while executing a micro-thread", e);
                    microThread.SetException(e);
                }
                finally
                {
                    if (MicroThreadCallbackEnd != null)
                    {
                        MicroThreadCallbackEnd(this, new SchedulerThreadEventArgs(microThread, managedThreadId));
                    }

                    SynchronizationContext.SetSynchronizationContext(previousSyncContext);
                    if (microThread.IsOver)
                    {
                        lock (microThread.AllLinkedListNode)
                        {
                            if (microThread.CompletionTask != null)
                            {
                                if (microThread.State == MicroThreadState.Failed || microThread.State == MicroThreadState.Cancelled)
                                {
                                    microThread.CompletionTask.TrySetException(microThread.Exception);
                                }
                                else
                                {
                                    microThread.CompletionTask.TrySetResult(1);
                                }
                            }
                            else if (microThread.State == MicroThreadState.Failed && microThread.Exception != null)
                            {
                                // Nothing was listening on the micro thread and it crashed
                                // Let's treat it as unhandled exception and propagate it
                                // Use ExceptionDispatchInfo.Capture to not overwrite callstack
                                if ((microThread.Flags & MicroThreadFlags.IgnoreExceptions) != MicroThreadFlags.IgnoreExceptions)
                                {
                                    ExceptionDispatchInfo.Capture(microThread.Exception).Throw();
                                }
                            }

                            if (MicroThreadEnded != null)
                            {
                                MicroThreadEnded(this, new SchedulerThreadEventArgs(microThread, managedThreadId));
                            }
                        }
                    }

                    runningMicroThread.Value = previousRunningMicrothread;
                    if (previousRunningMicrothread != null)
                    {
                        if (MicroThreadCallbackStart != null)
                        {
                            MicroThreadCallbackStart(this, new SchedulerThreadEventArgs(previousRunningMicrothread, managedThreadId));
                        }
                    }
                }
            }

            while (FrameChannel.Balance < 0)
            {
                FrameChannel.Send(0);
            }
        }