Exemplo n.º 1
0
        /// <summary>
        /// Yields execution until next frame.
        /// </summary>
        /// <returns>Task.</returns>
        public ChannelMicroThreadAwaiter <int> NextFrame()
        {
            if (MicroThread.Current == null)
            {
                throw new Exception("NextFrame cannot be called out of the micro-thread context.");
            }

            return(FrameChannel.Receive());
        }
Exemplo n.º 2
0
        internal Frame(IChannelOwner parent, string guid, FrameInitializer initializer) : base(parent, guid)
        {
            _channel     = new FrameChannel(guid, parent.Connection, this);
            _initializer = initializer;
            Url          = _initializer.Url;
            Name         = _initializer.Name;
            ParentFrame  = _initializer.ParentFrame;
            _loadStates  = initializer.LoadStates;

            _channel.LoadState += (sender, e) =>
            {
                lock (_loadStates)
                {
                    if (e.Add.HasValue)
                    {
                        _loadStates.Add(e.Add.Value);
                        LoadState?.Invoke(this, new LoadStateEventArgs {
                            LifecycleEvent = e.Add.Value
                        });
                    }

                    if (e.Remove.HasValue)
                    {
                        _loadStates.Remove(e.Remove.Value);
                    }
                }
            };

            _channel.Navigated += (sender, e) =>
            {
                Url  = e.Url;
                Name = e.Name;
                Navigated?.Invoke(this, e);

                if (string.IsNullOrEmpty(e.Error))
                {
                    ((Page)Page)?.OnFrameNavigated(this);
                }
            };
        }
Exemplo n.º 3
0
 internal Frame(ConnectionScope scope, string guid, FrameInitializer initializer)
 {
     _scope   = scope;
     _channel = new FrameChannel(guid, scope, this);
 }
Exemplo n.º 4
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

            while (true)
            {
                Action      callback;
                MicroThread microThread;
                lock (scheduledMicroThreads)
                {
                    if (scheduledMicroThreads.Count == 0)
                    {
                        break;
                    }
                    microThread = scheduledMicroThreads.Dequeue();

                    callback             = microThread.Callback;
                    microThread.Callback = null;
                }

                // 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))
                    {
                        callback();
                    }
                }
                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);
            }
        }
Exemplo n.º 5
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)
            {
                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)
                {
                    if (MicroThreadCallbackEnd != null)
                    {
                        MicroThreadCallbackEnd(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 != null)
                        {
                            MicroThreadStarted(this, new SchedulerThreadEventArgs(microThread, managedThreadId));
                        }

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

                        using (Profiler.Begin(MicroThread.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
                    {
                        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.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();
                                    }
                                }

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

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

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