Skip to content

Commit b0e8361

Browse files
authored
Supports Task Cancellations (#1)
1 parent b679754 commit b0e8361

File tree

10 files changed

+722
-102
lines changed

10 files changed

+722
-102
lines changed

nanoFramework.System.Threading/System/Runtime/CompilerServices/AsyncTaskMethodBuilder.cs

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,109 @@
99

1010
namespace System.Runtime.CompilerServices
1111
{
12+
/// <summary>
13+
/// Represents a builder for asynchronous methods that return a task.
14+
/// </summary>
15+
public struct AsyncTaskMethodBuilder
16+
{
17+
/// <summary>
18+
/// Creates an instance of the <see cref="AsyncTaskMethodBuilder"/> class.
19+
/// </summary>
20+
/// <returns>A new instance of the builder.</returns>
21+
public static AsyncTaskMethodBuilder Create()
22+
{
23+
Debug.WriteLine($"AsyncTaskMethodBuilder:Create");
24+
return new AsyncTaskMethodBuilder();
25+
}
26+
27+
Task task;
28+
/// <summary>
29+
/// Gets the task for this builder
30+
/// </summary>
31+
/// <value>
32+
/// The task for this builder.
33+
/// </value>
34+
public Task Task => task;
35+
36+
/// <summary>
37+
/// Schedules the state machine to proceed to the next action when the specified awaiter completes.
38+
/// </summary>
39+
/// <typeparam name="TAwaiter"></typeparam>
40+
/// <typeparam name="TStateMachine"></typeparam>
41+
/// <param name="awaiter"></param>
42+
/// <param name="stateMachine"></param>
43+
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
44+
where TAwaiter : INotifyCompletion
45+
where TStateMachine : IAsyncStateMachine
46+
{
47+
Debug.WriteLine($"AsyncTaskMethodBuilder:AwaitOnCompleted");
48+
var _stateMachine = stateMachine;
49+
awaiter.OnCompleted(() =>
50+
{
51+
Debug.WriteLine($"AsyncTaskMethodBuilder:OnCompleted");
52+
_stateMachine.MoveNext();
53+
});
54+
}
55+
56+
/// <summary>
57+
/// Schedules the state machine to proceed to the next action when the specified awaiter completes. This method can be called from partially trusted code.
58+
/// </summary>
59+
/// <typeparam name="TAwaiter"></typeparam>
60+
/// <typeparam name="TStateMachine"></typeparam>
61+
/// <param name="awaiter"></param>
62+
/// <param name="stateMachine"></param>
63+
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
64+
where TAwaiter : ICriticalNotifyCompletion
65+
where TStateMachine : IAsyncStateMachine
66+
{
67+
Debug.WriteLine($"AsyncTaskMethodBuilder:AwaitUnsafeOnCompleted");
68+
var _stateMachine = stateMachine;
69+
awaiter.OnCompleted(() =>
70+
{
71+
Debug.WriteLine($"AsyncTaskMethodBuilder:OnCompleted");
72+
_stateMachine.MoveNext();
73+
});
74+
}
75+
76+
/// <summary>
77+
/// Marks the task as failed and binds the specified exception to the task.
78+
/// </summary>
79+
/// <param name="exception"></param>
80+
public void SetException(Exception exception)
81+
{
82+
Debug.WriteLine($"AsyncTaskMethodBuilder:SetException");
83+
task.CompleteWithException(exception);
84+
}
85+
/// <summary>
86+
/// Marks the task as successfully completed.
87+
/// </summary>
88+
public void SetResult()
89+
{
90+
task.Complete();
91+
Debug.WriteLine($"AsyncTaskMethodBuilder:SetResult");
92+
}
93+
/// <summary>
94+
/// Associates the builder with the specified state machine.
95+
/// </summary>
96+
/// <param name="stateMachine"></param>
97+
public void SetStateMachine(IAsyncStateMachine stateMachine)
98+
{
99+
Debug.WriteLine($"AsyncTaskMethodBuilder:SetStateMachine");
100+
}
101+
102+
/// <summary>
103+
/// Begins running the builder with the associated state machine.
104+
/// </summary>
105+
/// <typeparam name="TStateMachine"></typeparam>
106+
/// <param name="stateMachine"></param>
107+
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
108+
{
109+
Debug.WriteLine($"AsyncTaskMethodBuilder:Start");
110+
task = new Task();
111+
stateMachine.MoveNext();
112+
}
113+
}
114+
12115
/// <summary>
13116
/// Represents a builder for asynchronous methods that return a task.
14117
/// </summary>
@@ -18,7 +121,7 @@ public struct AsyncTaskMethodBuilder<TResult>
18121
Task<TResult> task;
19122

20123
/// <summary>
21-
/// Gets the task for this bu
124+
/// Gets the task for this builder
22125
/// </summary>
23126
/// <value>
24127
/// The task for this builder.
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
using System;
2+
3+
namespace System.Threading
4+
{
5+
/// <summary>
6+
/// Propagates notification that operation should be cancelled.
7+
/// </summary>
8+
public struct CancellationToken
9+
{
10+
CancellationTokenSource source;
11+
/// <summary>
12+
/// Initializes the System.Threading.CancellationToken.
13+
/// </summary>
14+
/// <param name="source">The canceled state for the token.</param>
15+
internal CancellationToken(CancellationTokenSource source)
16+
{
17+
this.source = source;
18+
}
19+
20+
/// <summary>
21+
/// Initializes the System.Threading.CancellationToken.
22+
/// </summary>
23+
/// <param name="canceled">The canceled state for the token.</param>
24+
public CancellationToken(bool canceled)
25+
{
26+
this.source = null;
27+
}
28+
29+
static readonly CancellationToken none = new CancellationToken();
30+
31+
/// <summary>
32+
/// Returns an empty System.Threading.CancellationToken value.
33+
/// </summary>
34+
/// <returns>An empty cancellation token.</returns>
35+
public static CancellationToken None => none;
36+
37+
/// <summary>
38+
/// Gets whether cancellation has been requested for this token.
39+
/// </summary>
40+
/// <returns>true if cancellation has been requested for this token; otherwise, false.</returns>
41+
public bool IsCancellationRequested => source.IsCancellationRequested;
42+
43+
/// <summary>
44+
/// Gets whether this token is capable of being in the canceled state.
45+
/// </summary>
46+
/// <returns> true if this token is capable of being in the canceled state; otherwise, false.</returns>
47+
public bool CanBeCanceled => !source.IsCancellationRequested;
48+
49+
/// <summary>
50+
/// Gets a System.Threading.WaitHandle that is signaled when the token is canceled.
51+
/// </summary>
52+
/// <returns>A System.Threading.WaitHandle that is signaled when the token is canceled.</returns>
53+
public WaitHandle WaitHandle => source.WaitHandle;
54+
55+
/// <summary>
56+
/// Determines whether the current System.Threading.CancellationToken instance is equal to the specified token.
57+
/// </summary>
58+
/// <param name="other"></param>
59+
/// <returns>
60+
/// true if the instances are equal; otherwise, false. Two tokens are equal if they
61+
/// are associated with the same System.Threading.CancellationTokenSource or if they
62+
/// were both constructed from public System.Threading.CancellationToken constructors
63+
/// and their System.Threading.CancellationToken.IsCancellationRequested values are
64+
/// equal.
65+
/// </returns>
66+
/// <exception cref="System.ObjectDisposedException">An associated System.Threading.CancellationTokenSource has been disposed.</exception>
67+
public bool Equals(CancellationToken other)
68+
{
69+
if (this.source == other.source)
70+
return true;
71+
return false;
72+
}
73+
/// <summary>
74+
/// Determines whether the current System.Threading.CancellationToken instance is equal to the specified System.Object.
75+
/// </summary>
76+
/// <param name="other">The other object to which to compare this instance.</param>
77+
/// <returns>
78+
/// true if other is a System.Threading.CancellationToken and if the two instances
79+
/// are equal; otherwise, false. Two tokens are equal if they are associated with
80+
/// the same System.Threading.CancellationTokenSource or if they were both constructed
81+
/// from public System.Threading.CancellationToken constructors and their System.Threading.CancellationToken.IsCancellationRequested
82+
/// values are equal.
83+
/// </returns>
84+
/// <exception cref="System.ObjectDisposedException">An associated System.Threading.CancellationTokenSource has been disposed.</exception>
85+
public override bool Equals(object other)
86+
{
87+
if (other is CancellationToken token)
88+
{
89+
return Equals(token);
90+
}
91+
return false;
92+
}
93+
94+
/// <summary>
95+
/// Serves as a hash function for a System.Threading.CancellationToken.
96+
/// </summary>
97+
/// <returns>A hash code for the current System.Threading.CancellationToken instance.</returns>
98+
public override int GetHashCode()
99+
{
100+
return source.GetHashCode();
101+
}
102+
103+
/// <summary>
104+
/// Registers a delegate that will be called when this System.Threading.CancellationToken is canceled.
105+
/// </summary>
106+
/// <param name="callback">The delegate to be executed when the System.Threading.CancellationToken is canceled.</param>
107+
/// <returns>The System.Threading.CancellationTokenRegistration instance that can be used to deregister the callback.</returns>
108+
/// <exception cref="System.ArgumentNullException">callback is null</exception>
109+
public CancellationTokenRegistration Register(Action callback)
110+
{
111+
return Register(callback, true);
112+
}
113+
114+
/// <summary>
115+
/// Registers a delegate that will be called when this System.Threading.CancellationToken is canceled.
116+
/// </summary>
117+
/// <param name="callback">The delegate to be executed when the System.Threading.CancellationToken is canceled.</param>
118+
/// <param name="useSynchronizationContext">A value that indicates whether to capture the current System.Threading.SynchronizationContext and use it when invoking the callback.</param>
119+
/// <returns>The System.Threading.CancellationTokenRegistration instance that can be used to deregister the callback.</returns>
120+
/// <exception cref="System.ArgumentNullException">callback is null</exception>
121+
public CancellationTokenRegistration Register(Action callback, bool useSynchronizationContext)
122+
{
123+
callback = callback ?? throw new ArgumentNullException("callback");
124+
if (source.IsCancellationRequested)
125+
{
126+
callback();
127+
}
128+
else if (source != null)
129+
{
130+
return source.NotifyOnCancelled(callback, useSynchronizationContext);
131+
}
132+
return new CancellationTokenRegistration();
133+
}
134+
/// <summary>
135+
/// Registers a delegate that will be called when this System.Threading.CancellationToken is canceled.
136+
/// </summary>
137+
/// <param name="callback">The delegate to be executed when the System.Threading.CancellationToken is canceled.</param>
138+
/// <param name="state">The state to pass to the callback when the delegate is invoked. This may be null.</param>
139+
/// <returns>The System.Threading.CancellationTokenRegistration instance that can be used to deregister the callback.</returns>
140+
/// <exception cref="System.ArgumentNullException">callback is null</exception>
141+
public CancellationTokenRegistration Register(Action<object> callback, object state)
142+
{
143+
return Register(() => callback(state), true);
144+
}
145+
/// <summary>
146+
/// Registers a delegate that will be called when this System.Threading.CancellationToken is canceled.
147+
/// </summary>
148+
/// <param name="callback">The delegate to be executed when the System.Threading.CancellationToken is canceled.</param>
149+
/// <param name="state">The state to pass to the callback when the delegate is invoked. This may be null.</param>
150+
/// <param name="useSynchronizationContext">A Boolean value that indicates whether to capture the current System.Threading.SynchronizationContext and use it when invoking the callback.</param>
151+
/// <returns>The System.Threading.CancellationTokenRegistration instance that can be used to deregister the callback.</returns>
152+
/// <exception cref="System.ArgumentNullException">callback is null</exception>
153+
public CancellationTokenRegistration Register(Action<object> callback, object state, bool useSynchronizationContext)
154+
{
155+
return Register(() => callback(state), useSynchronizationContext);
156+
}
157+
158+
/// <summary>
159+
/// Throws a System.OperationCanceledException if this token has had cancellation requested
160+
/// </summary>
161+
public void ThrowIfCancellationRequested()
162+
{
163+
if (source.IsCancellationRequested)
164+
throw new SystemException();//TODO: throw OperationCanceledException, not defined yet
165+
}
166+
167+
/// <summary>
168+
/// Determines whether two System.Threading.CancellationToken instances are equal.
169+
/// </summary>
170+
/// <param name="left">The first instance.</param>
171+
/// <param name="right">The second instance.</param>
172+
/// <returns> true if the instances are equal; otherwise, false.</returns>
173+
public static bool operator ==(CancellationToken left, CancellationToken right)
174+
{
175+
return left.Equals(right);
176+
}
177+
178+
/// <summary>
179+
/// Determines whether two System.Threading.CancellationToken instances are not equal.
180+
/// </summary>
181+
/// <param name="left">The first instance.</param>
182+
/// <param name="right">The second instance.</param>
183+
/// <returns>true if the instances are not equal; otherwise, false.</returns>
184+
public static bool operator !=(CancellationToken left, CancellationToken right)
185+
{
186+
return !left.Equals(right);
187+
}
188+
}
189+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System;
2+
3+
namespace System.Threading
4+
{
5+
/// <summary>
6+
/// Represents a callback delegate that has been registered with a System.Threading.CancellationToken.
7+
/// </summary>
8+
public struct CancellationTokenRegistration : IDisposable
9+
{
10+
CancellationTokenSource source;
11+
Action onDisposed;
12+
internal CancellationTokenRegistration(CancellationTokenSource source, Action onDisposed)
13+
{
14+
this.source = source;
15+
this.onDisposed = onDisposed;
16+
}
17+
18+
/// <summary>
19+
/// Releases all resources used by the current instance of the System.Threading.CancellationTokenRegistration
20+
/// </summary>
21+
public void Dispose()
22+
{
23+
onDisposed?.Invoke();
24+
}
25+
26+
/// <summary>
27+
/// Determines whether the current System.Threading.CancellationTokenRegistration instance is equal to the specified System.Threading.CancellationTokenRegistration.
28+
/// </summary>
29+
/// <param name="obj">The other System.Threading.CancellationTokenRegistration to which to compare this instance.</param>
30+
/// <returns>
31+
/// True, if both this and other are equal. False, otherwise. Two System.Threading.CancellationTokenRegistration
32+
/// instances are equal if they both refer to the output of a single call to the
33+
/// same Register method of a System.Threading.CancellationToken.
34+
///</returns>
35+
public override bool Equals(object obj)
36+
{
37+
if (obj is CancellationTokenRegistration other)
38+
{
39+
return source == other.source;
40+
}
41+
return false;
42+
}
43+
44+
/// <summary>
45+
/// Determines whether the current System.Threading.CancellationTokenRegistration instance is equal to the specified System.Threading.CancellationTokenRegistration.
46+
/// </summary>
47+
/// <param name="other">The other System.Threading.CancellationTokenRegistration to which to compare this instance.</param>
48+
/// <returns>
49+
/// True, if both this and other are equal. False, otherwise. Two System.Threading.CancellationTokenRegistration
50+
/// instances are equal if they both refer to the output of a single call to the
51+
/// same Register method of a System.Threading.CancellationToken.
52+
///</returns>
53+
public bool Equals(CancellationTokenRegistration other)
54+
{
55+
return source == other.source;
56+
}
57+
58+
/// <summary>
59+
/// Serves as a hash function for a System.Threading.CancellationTokenRegistration.
60+
/// </summary>
61+
/// <returns>A hash code for the current System.Threading.CancellationTokenRegistration instance.</returns>
62+
public override int GetHashCode()
63+
{
64+
return source.GetHashCode();
65+
}
66+
67+
/// <summary>
68+
/// Determines whether two System.Threading.CancellationTokenRegistration instances are equal.
69+
/// </summary>
70+
/// <param name="left">The first instance.</param>
71+
/// <param name="right">The second instance.</param>
72+
/// <returns>True if the instances are not equal; otherwise, false.</returns>
73+
public static bool operator ==(CancellationTokenRegistration left, CancellationTokenRegistration right)
74+
{
75+
return left.Equals(right);
76+
}
77+
78+
/// <summary>
79+
/// Determines whether two System.Threading.CancellationTokenRegistration instances are not equal.
80+
/// </summary>
81+
/// <param name="left">The first instance.</param>
82+
/// <param name="right">The second instance.</param>
83+
/// <returns>True if the instances are not equal; otherwise, false.</returns>
84+
public static bool operator !=(CancellationTokenRegistration left, CancellationTokenRegistration right)
85+
{
86+
return !left.Equals(right);
87+
}
88+
}
89+
}

0 commit comments

Comments
 (0)