public void OnRoutineStart(ITransitionMonitor monitor)
        {
            var syncContext = new InterceptingSynchronizationContext(
                SynchronizationContext.Current, this, monitor);

            SynchronizationContext.SetSynchronizationContext(syncContext);
        }
Esempio n. 2
0
 public InterceptingSynchronizationContext(
     SynchronizationContext innerSyncContext,
     IIntrinsicFlowController controller,
     ITransitionMonitor monitor)
 {
     InnerContext = innerSyncContext;
     _controller  = controller;
     _monitor     = monitor;
 }
        public void OnRoutineTransitionComplete(ITransitionMonitor monitor)
        {
#warning THIS DOES NOT WORK! Because it's called from a synchronization context, where execution context is different. Need to call it e.g. from the transition runner, but that's ugly.

#warning check if it's the same context?
            var syncContext = SynchronizationContext.Current;
            if (syncContext != null)
            {
                var routineSyncContext = (InterceptingSynchronizationContext)syncContext;
                SynchronizationContext.SetSynchronizationContext(routineSyncContext.InnerContext);
            }
        }
        public void TryHandlePostInvoke(
            Delegate @delegate,
            object continuationObject,
            ITransitionMonitor monitor)
        {
#warning This is heavy weight. Analyzing just the state machine for the delay promise is must be good enough.
            var continuationInfo = _taskContinuationClassifier.GetContinuationInfo(continuationObject);
            if (continuationInfo.Type == TaskContinuationType.AsyncStateMachine &&
                ReferenceEquals(monitor.Context.RoutineStateMachine, continuationInfo.Target))
            {
                TryHandlePostMoveNext(monitor);
            }
        }
Esempio n. 5
0
        public void TryHandlePostMoveNext(ITransitionMonitor monitor)
        {
            if (TryFindDelayPromise(monitor.Context.RoutineStateMachine, out var delayPromise) &&
                DelayPromiseAccessor.TryGetTimerStartAndDelay(
                    delayPromise, out var timerStart, out var timerDelay)
#warning Needs a configuration setting for the minimum delay. If a delay is too short, it might be too expensive to try to save the state of a routine. Also, add ability to opt in/out auto save?
                //&& timerDelay > TimeSpan.FromSeconds(5)
                && DelayPromiseAccessor.TryCancelTimer(delayPromise))
            {
                delayPromise.ResetContinuation();
                delayPromise.TrySetResult(null);
                monitor.OnCheckpointIntent(resumeTime: timerStart + timerDelay);
            }
        }
        public bool TryHandlePreInvoke(
            Delegate @delegate,
            object continuationObject,
            ITransitionMonitor monitor)
        {
            if (@delegate.GetMethodInfo().DeclaringType == typeof(YieldAwaitable.YieldAwaiter) &&
                monitor.Context.RoutineStateMachine != null)
            {
                var continuationInfo = _taskContinuationClassifier.GetContinuationInfo(continuationObject);
                if (continuationInfo.Type == TaskContinuationType.AsyncStateMachine &&
                    ReferenceEquals(monitor.Context.RoutineStateMachine, continuationInfo.Target))
                {
                    monitor.OnCheckpointIntent();
                    return(true);
                }
            }

            return(false);
        }
Esempio n. 7
0
        public void HandleWhenAllAsDetectedContinuation(
            Task whenAllTask, Task[] awaitedTasks,
            ExecuteRoutineIntent awaitedRoutineIntent,
            ITransitionMonitor monitor)
        {
            ExecuteRoutineIntent executeWhenAllIntent;

            lock (whenAllTask)
            {
                var state = whenAllTask.AsyncState as WhenAllProxyTaskState;
                if (state == null)
                {
                    var whenAllIntentId = _numericIdGenerator.NewId();

                    Type itemType   = null;
                    var  resultType = whenAllTask.GetResultType();
                    if (resultType.IsArray)
                    {
                        itemType = resultType.GetElementType();
                    }

                    executeWhenAllIntent = new ExecuteRoutineIntent
                    {
                        Id = whenAllIntentId,

                        ServiceId = new ServiceId
                        {
                            ServiceName = awaitedRoutineIntent.ServiceId.ServiceName,
                            ProxyName   = nameof(IntrinsicRoutines)
                        },

                        MethodId = _routineMethodIdProvider.GetId(
                            IntrinsicRoutines.WhenAllMethodInfo),

                        Parameters = new WhenAllInputParameters
                        {
                            tasks   = awaitedTasks,
                            intents = new ExecuteRoutineIntent[awaitedTasks.Length],
                            // The task result must be an Array, e.g. string[]
                            itemType = itemType
                        }
                    };

                    state = new WhenAllProxyTaskState
                    {
                        IntentId             = whenAllIntentId,
                        ExecuteWhenAllIntent = executeWhenAllIntent
                    };
                    whenAllTask.SetAsyncState(state);

                    monitor.RegisterIntent(executeWhenAllIntent, whenAllTask);
                }
                else
                {
                    executeWhenAllIntent = state.ExecuteWhenAllIntent;
                }
            }

            var index = -1;

            for (var i = 0; i < awaitedTasks.Length; i++)
            {
                if (awaitedTasks[i].AsyncState is ProxyTaskState state &&
                    state.IntentId == awaitedRoutineIntent.Id)
                {
                    index = i;
                    break;
                }
            }
            var parameters = (WhenAllInputParameters)executeWhenAllIntent.Parameters;

            parameters.intents[index] = awaitedRoutineIntent;

            monitor.Context.ScheduledActions.ExecuteRoutineIntents.Remove(awaitedRoutineIntent);

            if (parameters.intents.All(i => i != null))
            {
                whenAllTask.SetAsyncState(new ProxyTaskState
                {
                    IntentId = executeWhenAllIntent.Id
                });
            }
        }