3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
10 // <OWNER>Microsoft</OWNER>
12 // Types for awaiting Task and Task<T>. These types are emitted from Task{<T>}.GetAwaiter
13 // and Task{<T>}.ConfigureAwait. They are meant to be used only by the compiler, e.g.
15 // await nonGenericTask;
16 // =====================
17 // var $awaiter = nonGenericTask.GetAwaiter();
18 // if (!$awaiter.IsCompleted)
21 // $builder.AwaitUnsafeOnCompleted(ref $awaiter, ref this);
26 // $awaiter.GetResult();
28 // result += await genericTask.ConfigureAwait(false);
29 // ===================================================================================
30 // var $awaiter = genericTask.ConfigureAwait(false).GetAwaiter();
31 // if (!$awaiter.IsCompleted)
34 // $builder.AwaitUnsafeOnCompleted(ref $awaiter, ref this);
39 // result += $awaiter.GetResult();
41 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
44 using System.Diagnostics;
45 using System.Diagnostics.CodeAnalysis;
46 using System.Diagnostics.Contracts;
47 using System.Security;
48 using System.Threading;
49 using System.Threading.Tasks;
50 using System.Security.Permissions;
51 using System.Diagnostics.Tracing;
53 // NOTE: For performance reasons, initialization is not verified. If a developer
54 // incorrectly initializes a task awaiter, which should only be done by the compiler,
55 // NullReferenceExceptions may be generated (the alternative would be for us to detect
56 // this case and then throw a different exception instead). This is the same tradeoff
57 // that's made with other compiler-focused value types like List<T>.Enumerator.
59 namespace System.Runtime.CompilerServices
61 /// <summary>Provides an awaiter for awaiting a <see cref="System.Threading.Tasks.Task"/>.</summary>
62 /// <remarks>This type is intended for compiler use only.</remarks>
63 [HostProtection(Synchronization = true, ExternalThreading = true)]
64 public struct TaskAwaiter : ICriticalNotifyCompletion
66 /// <summary>The task being awaited.</summary>
67 private readonly Task m_task;
69 /// <summary>Initializes the <see cref="TaskAwaiter"/>.</summary>
70 /// <param name="task">The <see cref="System.Threading.Tasks.Task"/> to be awaited.</param>
71 internal TaskAwaiter(Task task)
73 Contract.Requires(task != null, "Constructing an awaiter requires a task to await.");
77 /// <summary>Gets whether the task being awaited is completed.</summary>
78 /// <remarks>This property is intended for compiler user rather than use directly in code.</remarks>
79 /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
80 public bool IsCompleted
82 get { return m_task.IsCompleted; }
85 /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary>
86 /// <param name="continuation">The action to invoke when the await operation completes.</param>
87 /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception>
88 /// <exception cref="System.InvalidOperationException">The awaiter was not properly initialized.</exception>
89 /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks>
90 [SecuritySafeCritical]
91 public void OnCompleted(Action continuation)
93 OnCompletedInternal(m_task, continuation, continueOnCapturedContext:true, flowExecutionContext:true);
96 /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary>
97 /// <param name="continuation">The action to invoke when the await operation completes.</param>
98 /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception>
99 /// <exception cref="System.InvalidOperationException">The awaiter was not properly initialized.</exception>
100 /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks>
102 public void UnsafeOnCompleted(Action continuation)
104 OnCompletedInternal(m_task, continuation, continueOnCapturedContext:true, flowExecutionContext:false);
107 /// <summary>Ends the await on the completed <see cref="System.Threading.Tasks.Task"/>.</summary>
108 /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
109 /// <exception cref="System.Threading.Tasks.TaskCanceledException">The task was canceled.</exception>
110 /// <exception cref="System.Exception">The task completed in a Faulted state.</exception>
111 public void GetResult()
117 /// Fast checks for the end of an await operation to determine whether more needs to be done
118 /// prior to completing the await.
120 /// <param name="task">The awaited task.</param>
121 internal static void ValidateEnd(Task task)
123 // Fast checks that can be inlined.
124 if (task.IsWaitNotificationEnabledOrNotRanToCompletion)
126 // If either the end await bit is set or we're not completed successfully,
127 // fall back to the slower path.
128 HandleNonSuccessAndDebuggerNotification(task);
133 /// Ensures the task is completed, triggers any necessary debugger breakpoints for completing
134 /// the await on the task, and throws an exception if the task did not complete successfully.
136 /// <param name="task">The awaited task.</param>
137 private static void HandleNonSuccessAndDebuggerNotification(Task task)
139 // NOTE: The JIT refuses to inline ValidateEnd when it contains the contents
140 // of HandleNonSuccessAndDebuggerNotification, hence the separation.
142 // Synchronously wait for the task to complete. When used by the compiler,
143 // the task will already be complete. This code exists only for direct GetResult use,
144 // for cases where the same exception propagation semantics used by "await" are desired,
145 // but where for one reason or another synchronous rather than asynchronous waiting is needed.
146 if (!task.IsCompleted)
148 bool taskCompleted = task.InternalWait(Timeout.Infinite, default(CancellationToken));
149 Contract.Assert(taskCompleted, "With an infinite timeout, the task should have always completed.");
152 // Now that we're done, alert the debugger if so requested
153 task.NotifyDebuggerOfWaitCompletionIfNecessary();
155 // And throw an exception if the task is faulted or canceled.
156 if (!task.IsRanToCompletion) ThrowForNonSuccess(task);
159 /// <summary>Throws an exception to handle a task that completed in a state other than RanToCompletion.</summary>
160 private static void ThrowForNonSuccess(Task task)
162 Contract.Requires(task.IsCompleted, "Task must have been completed by now.");
163 Contract.Requires(task.Status != TaskStatus.RanToCompletion, "Task should not be completed successfully.");
165 // Handle whether the task has been canceled or faulted
168 // If the task completed in a canceled state, throw an OperationCanceledException.
169 // This will either be the OCE that actually caused the task to cancel, or it will be a new
170 // TaskCanceledException. TCE derives from OCE, and by throwing it we automatically pick up the
171 // completed task's CancellationToken if it has one, including that CT in the OCE.
172 case TaskStatus.Canceled:
173 var oceEdi = task.GetCancellationExceptionDispatchInfo();
177 Contract.Assert(false, "Throw() should have thrown");
179 throw new TaskCanceledException(task);
181 // If the task faulted, throw its first exception,
182 // even if it contained more than one.
183 case TaskStatus.Faulted:
184 var edis = task.GetExceptionDispatchInfos();
188 Contract.Assert(false, "Throw() should have thrown");
189 break; // Necessary to compile: non-reachable, but compiler can't determine that
193 Contract.Assert(false, "There should be exceptions if we're Faulted.");
194 throw task.Exception;
199 /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary>
200 /// <param name="task">The task being awaited.</param>
201 /// <param name="continuation">The action to invoke when the await operation completes.</param>
202 /// <param name="continueOnCapturedContext">Whether to capture and marshal back to the current context.</param>
203 /// <param name="flowExecutionContext">Whether to flow ExecutionContext across the await.</param>
204 /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception>
205 /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
206 /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks>
207 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
209 internal static void OnCompletedInternal(Task task, Action continuation, bool continueOnCapturedContext, bool flowExecutionContext)
211 if (continuation == null) throw new ArgumentNullException("continuation");
212 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
214 // If TaskWait* ETW events are enabled, trace a beginning event for this await
215 // and set up an ending event to be traced when the asynchronous await completes.
216 if ( TplEtwProvider.Log.IsEnabled() || Task.s_asyncDebuggingEnabled)
218 continuation = OutputWaitEtwEvents(task, continuation);
222 // Set the continuation onto the awaited task.
223 task.SetContinuationForAwait(continuation, continueOnCapturedContext, flowExecutionContext, ref stackMark);
227 /// Outputs a WaitBegin ETW event, and augments the continuation action to output a WaitEnd ETW event.
229 /// <param name="task">The task being awaited.</param>
230 /// <param name="continuation">The action to invoke when the await operation completes.</param>
231 /// <returns>The action to use as the actual continuation.</returns>
232 private static Action OutputWaitEtwEvents(Task task, Action continuation)
234 Contract.Requires(task != null, "Need a task to wait on");
235 Contract.Requires(continuation != null, "Need a continuation to invoke when the wait completes");
237 if (Task.s_asyncDebuggingEnabled)
239 Task.AddToActiveTasks(task);
243 var etwLog = TplEtwProvider.Log;
245 if (etwLog.IsEnabled())
247 // ETW event for Task Wait Begin
248 var currentTaskAtBegin = Task.InternalCurrent;
250 // If this task's continuation is another task, get it.
251 var continuationTask = AsyncMethodBuilderCore.TryGetContinuationTask(continuation);
252 etwLog.TaskWaitBegin(
253 (currentTaskAtBegin != null ? currentTaskAtBegin.m_taskScheduler.Id : TaskScheduler.Default.Id),
254 (currentTaskAtBegin != null ? currentTaskAtBegin.Id : 0),
255 task.Id, TplEtwProvider.TaskWaitBehavior.Asynchronous,
256 (continuationTask != null ? continuationTask.Id : 0), System.Threading.Thread.GetDomainID());
260 // Create a continuation action that outputs the end event and then invokes the user
261 // provided delegate. This incurs the allocations for the closure/delegate, but only if the event
262 // is enabled, and in doing so it allows us to pass the awaited task's information into the end event
263 // in a purely pay-for-play manner (the alternatively would be to increase the size of TaskAwaiter
264 // just for this ETW purpose, not pay-for-play, since GetResult would need to know whether a real yield occurred).
265 return AsyncMethodBuilderCore.CreateContinuationWrapper(continuation, () =>
267 if (Task.s_asyncDebuggingEnabled)
269 Task.RemoveFromActiveTasks(task.Id);
272 // ETW event for Task Wait End.
273 Guid prevActivityId = new Guid();
274 bool bEtwLogEnabled = etwLog.IsEnabled();
277 var currentTaskAtEnd = Task.InternalCurrent;
279 (currentTaskAtEnd != null ? currentTaskAtEnd.m_taskScheduler.Id : TaskScheduler.Default.Id),
280 (currentTaskAtEnd != null ? currentTaskAtEnd.Id : 0),
283 // Ensure the continuation runs under the activity ID of the task that completed for the
284 // case the antecendent is a promise (in the other cases this is already the case).
285 if (etwLog.TasksSetActivityIds && (task.Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0)
286 EventSource.SetCurrentThreadActivityId(TplEtwProvider.CreateGuidForTaskID(task.Id), out prevActivityId);
289 // Invoke the original continuation provided to OnCompleted.
295 etwLog.TaskWaitContinuationComplete(task.Id);
296 if (etwLog.TasksSetActivityIds && (task.Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0)
297 EventSource.SetCurrentThreadActivityId(prevActivityId);
304 /// <summary>Provides an awaiter for awaiting a <see cref="System.Threading.Tasks.Task{TResult}"/>.</summary>
305 /// <remarks>This type is intended for compiler use only.</remarks>
306 [HostProtection(Synchronization = true, ExternalThreading = true)]
307 public struct TaskAwaiter<TResult> : ICriticalNotifyCompletion
309 /// <summary>The task being awaited.</summary>
310 private readonly Task<TResult> m_task;
312 /// <summary>Initializes the <see cref="TaskAwaiter{TResult}"/>.</summary>
313 /// <param name="task">The <see cref="System.Threading.Tasks.Task{TResult}"/> to be awaited.</param>
314 internal TaskAwaiter(Task<TResult> task)
316 Contract.Requires(task != null, "Constructing an awaiter requires a task to await.");
320 /// <summary>Gets whether the task being awaited is completed.</summary>
321 /// <remarks>This property is intended for compiler user rather than use directly in code.</remarks>
322 /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
323 public bool IsCompleted
325 get { return m_task.IsCompleted; }
328 /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary>
329 /// <param name="continuation">The action to invoke when the await operation completes.</param>
330 /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception>
331 /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
332 /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks>
333 [SecuritySafeCritical]
334 public void OnCompleted(Action continuation)
336 TaskAwaiter.OnCompletedInternal(m_task, continuation, continueOnCapturedContext:true, flowExecutionContext:true);
339 /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary>
340 /// <param name="continuation">The action to invoke when the await operation completes.</param>
341 /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception>
342 /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
343 /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks>
345 public void UnsafeOnCompleted(Action continuation)
347 TaskAwaiter.OnCompletedInternal(m_task, continuation, continueOnCapturedContext:true, flowExecutionContext:false);
350 /// <summary>Ends the await on the completed <see cref="System.Threading.Tasks.Task{TResult}"/>.</summary>
351 /// <returns>The result of the completed <see cref="System.Threading.Tasks.Task{TResult}"/>.</returns>
352 /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
353 /// <exception cref="System.Threading.Tasks.TaskCanceledException">The task was canceled.</exception>
354 /// <exception cref="System.Exception">The task completed in a Faulted state.</exception>
355 public TResult GetResult()
357 TaskAwaiter.ValidateEnd(m_task);
358 return m_task.ResultOnSuccess;
362 /// <summary>Provides an awaitable object that allows for configured awaits on <see cref="System.Threading.Tasks.Task"/>.</summary>
363 /// <remarks>This type is intended for compiler use only.</remarks>
364 public struct ConfiguredTaskAwaitable
366 /// <summary>The task being awaited.</summary>
367 private readonly ConfiguredTaskAwaitable.ConfiguredTaskAwaiter m_configuredTaskAwaiter;
369 /// <summary>Initializes the <see cref="ConfiguredTaskAwaitable"/>.</summary>
370 /// <param name="task">The awaitable <see cref="System.Threading.Tasks.Task"/>.</param>
371 /// <param name="continueOnCapturedContext">
372 /// true to attempt to marshal the continuation back to the original context captured; otherwise, false.
374 internal ConfiguredTaskAwaitable(Task task, bool continueOnCapturedContext)
376 Contract.Requires(task != null, "Constructing an awaitable requires a task to await.");
377 m_configuredTaskAwaiter = new ConfiguredTaskAwaitable.ConfiguredTaskAwaiter(task, continueOnCapturedContext);
380 /// <summary>Gets an awaiter for this awaitable.</summary>
381 /// <returns>The awaiter.</returns>
382 public ConfiguredTaskAwaitable.ConfiguredTaskAwaiter GetAwaiter()
384 return m_configuredTaskAwaiter;
387 /// <summary>Provides an awaiter for a <see cref="ConfiguredTaskAwaitable"/>.</summary>
388 /// <remarks>This type is intended for compiler use only.</remarks>
389 [HostProtection(Synchronization = true, ExternalThreading = true)]
390 public struct ConfiguredTaskAwaiter : ICriticalNotifyCompletion
392 /// <summary>The task being awaited.</summary>
393 private readonly Task m_task;
394 /// <summary>Whether to attempt marshaling back to the original context.</summary>
395 private readonly bool m_continueOnCapturedContext;
397 /// <summary>Initializes the <see cref="ConfiguredTaskAwaiter"/>.</summary>
398 /// <param name="task">The <see cref="System.Threading.Tasks.Task"/> to await.</param>
399 /// <param name="continueOnCapturedContext">
400 /// true to attempt to marshal the continuation back to the original context captured
401 /// when BeginAwait is called; otherwise, false.
403 internal ConfiguredTaskAwaiter(Task task, bool continueOnCapturedContext)
405 Contract.Requires(task != null, "Constructing an awaiter requires a task to await.");
407 m_continueOnCapturedContext = continueOnCapturedContext;
410 /// <summary>Gets whether the task being awaited is completed.</summary>
411 /// <remarks>This property is intended for compiler user rather than use directly in code.</remarks>
412 /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
413 public bool IsCompleted
415 get { return m_task.IsCompleted; }
418 /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary>
419 /// <param name="continuation">The action to invoke when the await operation completes.</param>
420 /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception>
421 /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
422 /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks>
423 [SecuritySafeCritical]
424 public void OnCompleted(Action continuation)
426 TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext:true);
429 /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary>
430 /// <param name="continuation">The action to invoke when the await operation completes.</param>
431 /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception>
432 /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
433 /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks>
435 public void UnsafeOnCompleted(Action continuation)
437 TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext:false);
440 /// <summary>Ends the await on the completed <see cref="System.Threading.Tasks.Task"/>.</summary>
441 /// <returns>The result of the completed <see cref="System.Threading.Tasks.Task{TResult}"/>.</returns>
442 /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
443 /// <exception cref="System.Threading.Tasks.TaskCanceledException">The task was canceled.</exception>
444 /// <exception cref="System.Exception">The task completed in a Faulted state.</exception>
445 public void GetResult()
447 TaskAwaiter.ValidateEnd(m_task);
452 /// <summary>Provides an awaitable object that allows for configured awaits on <see cref="System.Threading.Tasks.Task{TResult}"/>.</summary>
453 /// <remarks>This type is intended for compiler use only.</remarks>
454 public struct ConfiguredTaskAwaitable<TResult>
456 /// <summary>The underlying awaitable on whose logic this awaitable relies.</summary>
457 private readonly ConfiguredTaskAwaitable<TResult>.ConfiguredTaskAwaiter m_configuredTaskAwaiter;
459 /// <summary>Initializes the <see cref="ConfiguredTaskAwaitable{TResult}"/>.</summary>
460 /// <param name="task">The awaitable <see cref="System.Threading.Tasks.Task{TResult}"/>.</param>
461 /// <param name="continueOnCapturedContext">
462 /// true to attempt to marshal the continuation back to the original context captured; otherwise, false.
464 internal ConfiguredTaskAwaitable(Task<TResult> task, bool continueOnCapturedContext)
466 m_configuredTaskAwaiter = new ConfiguredTaskAwaitable<TResult>.ConfiguredTaskAwaiter(task, continueOnCapturedContext);
469 /// <summary>Gets an awaiter for this awaitable.</summary>
470 /// <returns>The awaiter.</returns>
471 public ConfiguredTaskAwaitable<TResult>.ConfiguredTaskAwaiter GetAwaiter()
473 return m_configuredTaskAwaiter;
476 /// <summary>Provides an awaiter for a <see cref="ConfiguredTaskAwaitable{TResult}"/>.</summary>
477 /// <remarks>This type is intended for compiler use only.</remarks>
478 [HostProtection(Synchronization = true, ExternalThreading = true)]
479 public struct ConfiguredTaskAwaiter : ICriticalNotifyCompletion
481 /// <summary>The task being awaited.</summary>
482 private readonly Task<TResult> m_task;
483 /// <summary>Whether to attempt marshaling back to the original context.</summary>
484 private readonly bool m_continueOnCapturedContext;
486 /// <summary>Initializes the <see cref="ConfiguredTaskAwaiter"/>.</summary>
487 /// <param name="task">The awaitable <see cref="System.Threading.Tasks.Task{TResult}"/>.</param>
488 /// <param name="continueOnCapturedContext">
489 /// true to attempt to marshal the continuation back to the original context captured; otherwise, false.
491 internal ConfiguredTaskAwaiter(Task<TResult> task, bool continueOnCapturedContext)
493 Contract.Requires(task != null, "Constructing an awaiter requires a task to await.");
495 m_continueOnCapturedContext = continueOnCapturedContext;
498 /// <summary>Gets whether the task being awaited is completed.</summary>
499 /// <remarks>This property is intended for compiler user rather than use directly in code.</remarks>
500 /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
501 public bool IsCompleted
503 get { return m_task.IsCompleted; }
506 /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary>
507 /// <param name="continuation">The action to invoke when the await operation completes.</param>
508 /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception>
509 /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
510 /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks>
511 [SecuritySafeCritical]
512 public void OnCompleted(Action continuation)
514 TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext:true);
517 /// <summary>Schedules the continuation onto the <see cref="System.Threading.Tasks.Task"/> associated with this <see cref="TaskAwaiter"/>.</summary>
518 /// <param name="continuation">The action to invoke when the await operation completes.</param>
519 /// <exception cref="System.ArgumentNullException">The <paramref name="continuation"/> argument is null (Nothing in Visual Basic).</exception>
520 /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
521 /// <remarks>This method is intended for compiler user rather than use directly in code.</remarks>
523 public void UnsafeOnCompleted(Action continuation)
525 TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext:false);
528 /// <summary>Ends the await on the completed <see cref="System.Threading.Tasks.Task{TResult}"/>.</summary>
529 /// <returns>The result of the completed <see cref="System.Threading.Tasks.Task{TResult}"/>.</returns>
530 /// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
531 /// <exception cref="System.Threading.Tasks.TaskCanceledException">The task was canceled.</exception>
532 /// <exception cref="System.Exception">The task completed in a Faulted state.</exception>
533 public TResult GetResult()
535 TaskAwaiter.ValidateEnd(m_task);
536 return m_task.ResultOnSuccess;