public void OnRoutineStart(ITransitionMonitor monitor) { var syncContext = new InterceptingSynchronizationContext( SynchronizationContext.Current, this, monitor); SynchronizationContext.SetSynchronizationContext(syncContext); }
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); } }
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); }
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 }); } }