TaskAwaitable.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Reactive.Concurrency;
  5. using System.Runtime.CompilerServices;
  6. namespace System.Threading.Tasks
  7. {
  8. public readonly struct TaskAwaitable
  9. {
  10. private readonly Task _task;
  11. private readonly bool _continueOnCapturedContext;
  12. private readonly IAsyncScheduler _scheduler;
  13. private readonly CancellationToken _token;
  14. public TaskAwaitable(Task task, bool continueOnCapturedContext, IAsyncScheduler scheduler, CancellationToken token)
  15. {
  16. _task = task;
  17. _continueOnCapturedContext = continueOnCapturedContext;
  18. _scheduler = scheduler;
  19. _token = token;
  20. }
  21. public TaskAwaiter GetAwaiter() => new(_task.ConfigureAwait(_continueOnCapturedContext).GetAwaiter(), _scheduler, _token);
  22. public readonly struct TaskAwaiter : INotifyCompletion
  23. {
  24. private readonly ConfiguredTaskAwaitable.ConfiguredTaskAwaiter _awaiter;
  25. private readonly IAsyncScheduler _scheduler;
  26. private readonly CancellationToken _token;
  27. public TaskAwaiter(ConfiguredTaskAwaitable.ConfiguredTaskAwaiter awaiter, IAsyncScheduler scheduler, CancellationToken token)
  28. {
  29. _awaiter = awaiter;
  30. _scheduler = scheduler;
  31. _token = token;
  32. }
  33. public bool IsCompleted => _awaiter.IsCompleted;
  34. public void GetResult()
  35. {
  36. _token.ThrowIfCancellationRequested();
  37. _awaiter.GetResult();
  38. }
  39. public void OnCompleted(Action continuation)
  40. {
  41. var cancel = default(IDisposable);
  42. if (_token.CanBeCanceled)
  43. {
  44. cancel = _token.Register(() =>
  45. {
  46. Interlocked.Exchange(ref continuation, null)?.Invoke();
  47. });
  48. }
  49. try
  50. {
  51. var scheduler = _scheduler;
  52. var token = _token;
  53. _awaiter.OnCompleted(() =>
  54. {
  55. void Invoke()
  56. {
  57. cancel?.Dispose();
  58. Interlocked.Exchange(ref continuation, null)?.Invoke();
  59. }
  60. if (scheduler != null)
  61. {
  62. var t = scheduler.ExecuteAsync(ct =>
  63. {
  64. Invoke();
  65. return default;
  66. }, token);
  67. }
  68. else
  69. {
  70. Invoke();
  71. }
  72. });
  73. }
  74. catch
  75. {
  76. cancel?.Dispose();
  77. throw;
  78. }
  79. }
  80. }
  81. }
  82. public readonly struct TaskAwaitable<T>
  83. {
  84. private readonly Task<T> _task;
  85. private readonly bool _continueOnCapturedContext;
  86. private readonly IAsyncScheduler _scheduler;
  87. private readonly CancellationToken _token;
  88. public TaskAwaitable(Task<T> task, bool continueOnCapturedContext, IAsyncScheduler scheduler, CancellationToken token)
  89. {
  90. _task = task;
  91. _continueOnCapturedContext = continueOnCapturedContext;
  92. _scheduler = scheduler;
  93. _token = token;
  94. }
  95. public TaskAwaiter GetAwaiter() => new(_task.ConfigureAwait(_continueOnCapturedContext).GetAwaiter(), _scheduler, _token);
  96. public readonly struct TaskAwaiter : INotifyCompletion
  97. {
  98. private readonly ConfiguredTaskAwaitable<T>.ConfiguredTaskAwaiter _awaiter;
  99. private readonly IAsyncScheduler _scheduler;
  100. private readonly CancellationToken _token;
  101. public TaskAwaiter(ConfiguredTaskAwaitable<T>.ConfiguredTaskAwaiter awaiter, IAsyncScheduler scheduler, CancellationToken token)
  102. {
  103. _awaiter = awaiter;
  104. _scheduler = scheduler;
  105. _token = token;
  106. }
  107. public bool IsCompleted => _awaiter.IsCompleted;
  108. public T GetResult()
  109. {
  110. _token.ThrowIfCancellationRequested();
  111. return _awaiter.GetResult();
  112. }
  113. public void OnCompleted(Action continuation)
  114. {
  115. var cancel = default(IDisposable);
  116. if (_token.CanBeCanceled)
  117. {
  118. cancel = _token.Register(() =>
  119. {
  120. Interlocked.Exchange(ref continuation, null)?.Invoke();
  121. });
  122. }
  123. try
  124. {
  125. var scheduler = _scheduler;
  126. var token = _token;
  127. _awaiter.OnCompleted(() =>
  128. {
  129. void Invoke()
  130. {
  131. cancel?.Dispose();
  132. Interlocked.Exchange(ref continuation, null)?.Invoke();
  133. }
  134. if (scheduler != null)
  135. {
  136. var t = scheduler.ExecuteAsync(ct =>
  137. {
  138. Invoke();
  139. return default;
  140. }, token);
  141. }
  142. else
  143. {
  144. Invoke();
  145. }
  146. });
  147. }
  148. catch
  149. {
  150. cancel?.Dispose();
  151. throw;
  152. }
  153. }
  154. }
  155. }
  156. }