public void OperationAsync() { AsyncStateMachine stateMachine = new AsyncStateMachine(); stateMachine.builder = AsyncVoidMethodBuilder.Create(); stateMachine.builder.Start(ref stateMachine); }
// Start is called before the first frame update void Start() { inventory = GetComponent <ResourceInventory>().backingInventory; timeTracker = GetComponent <ITimeTracker>(); optimizer = new GatherBehaviorOptimizer(); gatheringWeights = optimizer.generateInitialWeights(); stateMachine = new AsyncStateMachine <GathererState, GathererBehavior>(GathererState.Gathering); stateMachine.registerStateTransitionHandler(GathererState.All, GathererState.All, (x) => { objectSeeker.ClearCurrentTarget(); lastTargetCheckTime = 0; }, StateChangeExecutionOrder.StateExit); var sellingStateHandler = new SellingStateHandler(); sellingStateHandler.InstantiateOnObject(this); stateMachine.registerGenericHandler(new GatheringStateHandler()); stateMachine.registerGenericHandler(new GoingHomeStateHandler()); stateMachine.registerGenericHandler(new WaitTillMarketStateHandler()); stateMachine.registerGenericHandler(sellingStateHandler); stateMachine.registerGenericHandler(new GoingToConsumeHandler()); stateMachine.registerGenericHandler(new ConsumingStateHandler()); stateMachine.registerGenericHandler(new DieStateHandler()); stateMachine.registerGenericHandler(new SleepStateHandler()); stateMachine.LockStateHandlers(); }
private static Task <long?> GetPageLengthAsync() { var stateMachine = new AsyncStateMachine { Builder = AsyncTaskMethodBuilder <long?> .Create(), State = -1 }; stateMachine.Builder.Start(ref stateMachine); return(stateMachine.Builder.Task); }
private void Connet_Click(object sender, RoutedEventArgs e) { AsyncStateMachine stateMachine = new AsyncStateMachine { baseWindow = this, sender = sender, e = e, builder = AsyncVoidMethodBuilder.Create(), state = -1 }; stateMachine.builder.Start <AsyncStateMachine>(ref stateMachine); }
internal static Task <T> CompiledAsync <T>(T value) { AsyncStateMachine <T> asyncStateMachine = new AsyncStateMachine <T>() { Value = value, Builder = AsyncTaskMethodBuilder <T> .Create(), State = -1 // -1 means start. }; asyncStateMachine.Builder.Start(ref asyncStateMachine); return(asyncStateMachine.Builder.Task); }
static async Task Main(string[] args) { //await Task.FromResul(true); var stateMachine = new AsyncStateMachine { _builder = AsyncTaskMethodBuilder <bool> .Create(), _state = -1 }; stateMachine._builder.Start(ref stateMachine); var result = stateMachine._builder.Task.Result; }
public void FactMethodName() { //await Task.FromResul(100) var t = new AsyncStateMachine { _this = this, _builder = AsyncTaskMethodBuilder <int> .Create(), _state = -1 }; t._builder.Start(ref t); t._builder.Task.Result.Should().Be(10); }
public static IStateMachine <TMachineState, TMachineEvent> CreateAsync <TMachineState, TMachineEvent>( TMachineState initialState, IAsyncStateMachineConfiguration <TMachineState, TMachineEvent> configuration) { if (configuration is AsyncStateMachineDispatcher <TMachineState, TMachineEvent> dispatcher) { var synchronizationQueueFactory = new DataFlowSynchronizationQueueFactory(); var machine = new AsyncStateMachine <TMachineState, TMachineEvent>(initialState, dispatcher, synchronizationQueueFactory); return(machine); } throw new ArgumentException("configuration must not be a custom implementation of the state machine configuration interface."); }
// When an async method is generated by the compiler, it is transformed into something similar than // the following method. Of course, it is only present in IL. This C# version is reconstructed from IL. private void CalculateOnBackgroundThreadDecompiled(object sender, RoutedEventArgs e) { var machine = new AsyncStateMachine { Builder = AsyncTaskMethodBuilder <long> .Create(), State = -1, ToTextBox = ToTextBox, Button = Button, ProgressRing = ProgressRing, ResultTextBlock = ResultTextBlock }; machine.Builder.Start(ref machine); }
// Start is called before the first frame update void Start() { inventory = GetComponent <ResourceInventory>().backingInventory; stateMachine = new AsyncStateMachine <TraderState, TraderBehavior>(TraderState.Initial); stateMachine.registerStateTransitionHandler(TraderState.All, TraderState.All, (x) => { objectSeeker.ClearCurrentTarget(); }, StateChangeExecutionOrder.StateExit); stateMachine.registerGenericHandler(new InitalStateHandler()); stateMachine.registerGenericHandler(new TradeTransitStateHandler()); stateMachine.registerGenericHandler(new TradeExecuteStateHandler()); stateMachine.LockStateHandlers(); }
void IInterceptor.Intercept(IInvocation invocation) { var returnType = invocation.Method.ReturnType; var builder = AsyncMethodBuilder.TryCreate(returnType); if (builder != null) { var asyncInvocation = new AsyncInvocation(invocation); var stateMachine = new AsyncStateMachine(asyncInvocation, builder, task: this.InterceptAsync(asyncInvocation)); builder.Start(stateMachine); invocation.ReturnValue = builder.Task(); } else { this.Intercept(invocation); } }
private static IAwaitableStateMachine <TState, TTrigger> Create <TState, TTrigger>(TState initialState, AwaitableStateMachineConfiguration <TState, TTrigger> config, bool asyncMachine, TaskScheduler scheduler) { IAwaitableStateMachine <TState, TTrigger> sm; if (asyncMachine) { sm = new AsyncStateMachine <TState, TTrigger>(initialState, config); } else { sm = scheduler == null ? (IAwaitableStateMachine <TState, TTrigger>) new AwaitableStateMachine <TState, TTrigger>(initialState, config) : new AwaitableStateMachineWithScheduler <TState, TTrigger>(initialState, config, scheduler); } sm.UnhandledTriggerExecuted += InvalidTriggerException <TTrigger, TState> .Throw; return(sm); }
void IAsyncStateMachine.MoveNext() { int num1 = State; long?contentLength; try { TaskAwaiter <HttpResponseMessage> awaiter; if (num1 != 0) { _client = new HttpClient(); awaiter = _client.GetAsync("http://apress.com").GetAwaiter(); if (!awaiter.IsCompleted) { State = 0; _awaiter = awaiter; AsyncStateMachine stateMachine = this; Builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); return; } } else { awaiter = _awaiter; _awaiter = new TaskAwaiter <HttpResponseMessage>(); State = -1; } _responce2 = awaiter.GetResult(); _responce1 = _responce2; _responce2 = null; contentLength = _responce1.Content.Headers.ContentLength; } catch (Exception ex) { State = -2; Builder.SetException(ex); return; } State = -2; Builder.SetResult(contentLength); }
public void MoveNext() { int num = _state; var taskAwaiter = new CustomAwaiter(); if (num != 0) { if (!taskAwaiter.IsCompleted) { _state = 0; _taskAwaiter = taskAwaiter; AsyncStateMachine state = this; _builder.AwaitOnCompleted(ref taskAwaiter, ref state); return; } } var res = taskAwaiter.GetResult(); taskAwaiter = null; _state = -2; _builder.SetResult(res); }
private static bool PrintAsyncStateMachineChain(DebuggerOutput output, AsyncStateMachine node, HashSet <AsyncStateMachine> printedMachines) { int nLevel = 0; bool multipleLineBlock = false; var loopDetection = new HashSet <AsyncStateMachine>(); for (AsyncStateMachine?p = node; p is object; p = p.Next) { printedMachines.Add(p); if (nLevel > 0) { output.WriteString(".."); multipleLineBlock = true; } else if (p.AlterPrevious is object) { output.WriteObjectAddress(p.AlterPrevious.StateMachine.Address); output.WriteString($" <{p.AlterPrevious.State}> * {p.AlterPrevious.StateMachine.Type?.Name} @ "); output.WriteMethodInfo($"{p.AlterPrevious.CodeAddress:x}", p.AlterPrevious.CodeAddress); output.WriteLine(string.Empty); output.WriteString(".."); multipleLineBlock = true; } else if (!p.SwitchToMainThreadTask.IsNull) { output.WriteObjectAddress(p.SwitchToMainThreadTask.Address); output.WriteLine(".SwitchToMainThreadAsync"); output.WriteString(".."); multipleLineBlock = true; } output.WriteObjectAddress(p.StateMachine.Address); string doubleDependentTaskMark = p.DependentCount > 1 ? " * " : " "; output.WriteString($" <{p.State}>{doubleDependentTaskMark}{p.StateMachine.Type?.Name} @ "); output.WriteMethodInfo($"{p.CodeAddress:x}", p.CodeAddress); output.WriteLine(string.Empty); if (!loopDetection.Add(p)) { output.WriteLine("!!Loop task dependencies"); break; } if (p.Next is null && p.BlockedThread.HasValue) { output.WriteString("-- "); output.WriteThreadLink(p.BlockedThread.Value); output.WriteString(" - JoinableTask: "); output.WriteObjectAddress(p.BlockedJoinableTask.Address); int state = p.BlockedJoinableTask.ReadField <int>("state"); if ((state & 0x20) == 0x20) { output.WriteLine(" SynchronouslyBlockingMainThread"); } else { output.WriteLine(string.Empty); } multipleLineBlock = true; } nLevel++; } return(multipleLineBlock); }
private static void GetAllStateMachines(DebuggerContext context, ClrHeap heap, List <AsyncStateMachine> allStateMachines, Dictionary <ulong, AsyncStateMachine> knownStateMachines) { foreach (var obj in heap.GetObjectsOfType("System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner")) { try { var stateMachine = obj.ReadObjectField("m_stateMachine"); if (!knownStateMachines.ContainsKey(stateMachine.Address)) { try { var state = stateMachine.ReadField <int>("<>1__state"); if (state >= -1) { ClrObject taskField = default(ClrObject); var asyncBuilder = stateMachine.TryGetValueClassField("<>t__builder"); if (asyncBuilder.HasValue) { while (asyncBuilder.HasValue) { taskField = asyncBuilder.TryGetObjectField("m_task"); if (!taskField.IsNull) { break; } asyncBuilder = asyncBuilder.TryGetValueClassField("m_builder"); } } else { // CLR debugger may not be able to access t__builder, when NGEN assemblies are being used, and the type of the field could be lost. // Our workaround is to pick up the first Task object referenced by the state machine, which seems to be correct. // That function works with the raw data structure (like how GC scans the object, so it doesn't depend on symbols. foreach (ClrObject referencedObject in stateMachine.EnumerateReferences(true)) { if (!referencedObject.IsNull && referencedObject.Type is object) { if (string.Equals(referencedObject.Type.Name, "System.Threading.Tasks.Task", StringComparison.Ordinal) || string.Equals(referencedObject.Type.BaseType?.Name, "System.Threading.Tasks.Task", StringComparison.Ordinal)) { taskField = referencedObject; break; } } } } var asyncState = new AsyncStateMachine(state, stateMachine, taskField); allStateMachines.Add(asyncState); knownStateMachines.Add(stateMachine.Address, asyncState); if (stateMachine.Type is object) { foreach (var method in stateMachine.Type.Methods) { if (method.Name == "MoveNext" && method.NativeCode != ulong.MaxValue) { asyncState.CodeAddress = method.NativeCode; } } } } } catch (Exception ex) { context.Output.WriteLine($"Fail to process state machine {stateMachine.Address:x} Type:'{stateMachine.Type?.Name}' Module:'{stateMachine.Type?.Module?.Name}' Error: {ex.Message}"); } } } catch (Exception ex) { context.Output.WriteLine($"Fail to process AsyncStateMachine Runner {obj.Address:x} Error: {ex.Message}"); } } }
private static void ChainStateMachineBasedOnTaskContinuations(Dictionary <ulong, AsyncStateMachine> knownStateMachines, AsyncStateMachine stateMachine, ClrObject continuationObject) { var continuationAction = continuationObject.TryGetObjectField("m_action"); // case 1 var continuationTarget = continuationAction.TryGetObjectField("_target"); if (continuationTarget.IsNull) { // case 2 continuationTarget = continuationObject.TryGetObjectField("_target"); if (continuationTarget.IsNull) { // case 3 continuationTarget = continuationObject.TryGetObjectField("m_task").TryGetObjectField("m_stateObject").TryGetObjectField("_target"); } } while (!continuationTarget.IsNull) { // now get the continuation from the target var continuationTargetStateMachine = continuationTarget.TryGetObjectField("m_stateMachine"); if (!continuationTargetStateMachine.IsNull) { AsyncStateMachine targetAsyncState; if (knownStateMachines.TryGetValue(continuationTargetStateMachine.Address, out targetAsyncState) && targetAsyncState != stateMachine) { stateMachine.Next = targetAsyncState; stateMachine.DependentCount++; targetAsyncState.Previous = stateMachine; } break; } else { var nextContinuation = continuationTarget.TryGetObjectField("m_continuation"); continuationTarget = nextContinuation.TryGetObjectField("_target"); } } var items = continuationObject.TryGetObjectField("_items"); if (!items.IsNull && items.IsArray && items.ContainsPointers) { foreach (var promise in items.EnumerateReferences(true)) { if (!promise.IsNull) { var innerContinuationObject = promise.TryGetObjectField("m_continuationObject"); if (!innerContinuationObject.IsNull) { ChainStateMachineBasedOnTaskContinuations(knownStateMachines, stateMachine, innerContinuationObject); } else { ChainStateMachineBasedOnTaskContinuations(knownStateMachines, stateMachine, promise); } } } } }
private static void GetAllStateMachines(DebuggerContext context, ClrHeap heap, List <AsyncStateMachine> allStateMachines, Dictionary <ulong, AsyncStateMachine> knownStateMachines) { foreach (ClrObject obj in heap.GetObjectsOfType("System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner")) { try { ClrObject stateMachine = obj.ReadObjectField("m_stateMachine"); if (!knownStateMachines.ContainsKey(stateMachine.Address)) { try { var state = stateMachine.ReadField <int>("<>1__state"); if (state >= -1) { ClrObject taskField = default(ClrObject); ClrValueType?asyncBuilder = stateMachine.TryGetValueClassField("<>t__builder"); if (asyncBuilder.HasValue) { while (asyncBuilder.HasValue) { taskField = asyncBuilder.TryGetObjectField("m_task"); if (!taskField.IsNull) { break; } ClrValueType?nextAsyncBuilder = asyncBuilder.TryGetValueClassField("m_builder"); if (nextAsyncBuilder is null) { asyncBuilder = asyncBuilder.TryGetValueClassField("_methodBuilder"); } else { asyncBuilder = nextAsyncBuilder; } } } else { // CLR debugger may not be able to access t__builder, when NGEN assemblies are being used, and the type of the field could be lost. // Our workaround is to pick up the first Task object referenced by the state machine, which seems to be correct. // That function works with the raw data structure (like how GC scans the object, so it doesn't depend on symbols. // // However, one problem of that is we can pick up tasks from other reference fields of the same structure. So, we go through fields which we have symbols // and remember references encounted, and we skip them when we go through GC references. // Note: we can do better by going through other value structures, and extract references from them here, which we can consider when we have a real scenario. var previousReferences = new Dictionary <ulong, int>(); if (stateMachine.Type?.GetFieldByName("<>t__builder") is not null) { foreach (ClrInstanceField field in stateMachine.Type.Fields) { if (string.Equals(field.Name, "<>t__builder", StringComparison.Ordinal)) { break; } if (field.IsObjectReference) { ClrObject referencedValue = field.ReadObject(stateMachine.Address, interior: false); if (!referencedValue.IsNull) { if (previousReferences.TryGetValue(referencedValue.Address, out int refCount)) { previousReferences[referencedValue.Address] = refCount + 1; } else { previousReferences[referencedValue.Address] = 1; } } } } } foreach (ClrObject referencedObject in stateMachine.EnumerateReferences(true)) { if (!referencedObject.IsNull) { if (previousReferences.TryGetValue(referencedObject.Address, out int refCount) && refCount > 0) { if (refCount == 1) { previousReferences.Remove(referencedObject.Address); } else { previousReferences[referencedObject.Address] = refCount - 1; } continue; } else if (previousReferences.Count > 0) { continue; } if (referencedObject.Type is object && (string.Equals(referencedObject.Type.Name, "System.Threading.Tasks.Task", StringComparison.Ordinal) || string.Equals(referencedObject.Type.BaseType?.Name, "System.Threading.Tasks.Task", StringComparison.Ordinal))) { taskField = referencedObject; break; } } } } var asyncState = new AsyncStateMachine(state, stateMachine, taskField); allStateMachines.Add(asyncState); knownStateMachines.Add(stateMachine.Address, asyncState); if (stateMachine.Type is object) { foreach (ClrMethod?method in stateMachine.Type.Methods) { if (method.Name == "MoveNext" && method.NativeCode != ulong.MaxValue) { asyncState.CodeAddress = method.NativeCode; } } } } } #pragma warning disable CA1031 // Do not catch general exception types catch (Exception ex) #pragma warning restore CA1031 // Do not catch general exception types { context.Output.WriteLine($"Fail to process state machine {stateMachine.Address:x} Type:'{stateMachine.Type?.Name}' Module:'{stateMachine.Type?.Module?.Name}' Error: {ex.Message}"); } } } #pragma warning disable CA1031 // Do not catch general exception types catch (Exception ex) #pragma warning restore CA1031 // Do not catch general exception types { context.Output.WriteLine($"Fail to process AsyncStateMachine Runner {obj.Address:x} Error: {ex.Message}"); } } }