Skip to content

Commit a914904

Browse files
author
Jonathan McGee
committed
* Initial outline for an IAsyncResult realization
1 parent 0fbf116 commit a914904

2 files changed

Lines changed: 250 additions & 0 deletions

File tree

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Diagnostics.Contracts;
4+
using System.Threading;
5+
6+
namespace PleaseIgnore.IntelMap {
7+
/// <summary>
8+
/// Implementation of <see cref="IAsyncResult"/>, providing common
9+
/// support for asynchronous function calls in PleaseIgnore.
10+
/// </summary>
11+
/// <typeparam name="TOwner">
12+
/// The object type that creates this <see cref="IntelAsyncResult`2"/>.
13+
/// </typeparam>
14+
/// <typeparam name="TResult">
15+
/// The return <see cref="Type"/> of the <c>End<var>Name</var></c>
16+
/// call.
17+
/// </typeparam>
18+
internal class IntelAsyncResult<TOwner, TResult> : IAsyncResult
19+
where TOwner : class {
20+
// The callback to call when execution has completed
21+
private readonly AsyncCallback callback;
22+
// The value of AsyncState
23+
private readonly object state;
24+
// The object that created this IntelAsyncResult
25+
private readonly TOwner owner;
26+
// Set to true to prevent multiple invocations of End*()
27+
private bool disposed;
28+
// Set to true once the asynchronous execution has completed
29+
private bool completed;
30+
// Set to true if the execution was completed synchronously
31+
private bool synchronous;
32+
// Set to true if we have entered End*() and are waiting for completion
33+
private bool waiting;
34+
// The return value of a successful asynchronous execution
35+
private TResult result;
36+
// The exception object for an unsuccessful asychronous execution
37+
private Exception exception;
38+
// The WaitHandle instance to use when waiting for completion. Populated
39+
// by AsyncWaitHandle only as needed.
40+
private ManualResetEvent waitHandle;
41+
42+
/// <summary>
43+
/// Initializes a new instance of the <see cref="IntelAsyncResult`2"/>
44+
/// class.
45+
/// </summary>
46+
/// <param name="owner">
47+
/// The instance of <see cref="TOwner"/> that created this object.
48+
/// </param>
49+
/// <param name="callback">
50+
/// The <see cref="AsyncCallback"/> to call when the asynchronous
51+
/// operation completes. This can be <see langword="null"/>.
52+
/// </param>
53+
/// <param name="state">
54+
/// The value of <see cref="AsyncState"/>. This can be
55+
/// <see langword="null"/>.
56+
/// </param>
57+
internal IntelAsyncResult(TOwner owner, AsyncCallback callback, object state) {
58+
Contract.Requires(owner != null);
59+
this.owner = owner;
60+
this.callback = callback;
61+
this.state = state;
62+
}
63+
64+
/// <summary>
65+
/// Gets a user-defined object that qualifies or contains information
66+
/// about an asynchronous operation.
67+
/// </summary>
68+
public object AsyncState { get { return this.state; } }
69+
70+
/// <summary>
71+
/// Gets a value that indicates whether the asynchronous operation
72+
/// completed synchronously.
73+
/// </summary>
74+
public bool CompletedSynchronously { get { return this.synchronous; } }
75+
76+
/// <summary>
77+
/// Gets a value that indicates whether the asynchronous operation
78+
/// has completed.
79+
/// </summary>
80+
public bool IsCompleted { get { return this.completed; } }
81+
82+
/// <summary>
83+
/// Gets a <see cref="WaitHandle"/> that is used to wait for an
84+
/// asynchronous operation to complete.
85+
/// </summary>
86+
public WaitHandle AsyncWaitHandle {
87+
get {
88+
lock (this) {
89+
if (this.disposed) {
90+
throw new InvalidOperationException();
91+
} else if (this.waitHandle == null) {
92+
this.waitHandle = new ManualResetEvent(this.completed);
93+
}
94+
return this.waitHandle;
95+
}
96+
}
97+
}
98+
99+
/// <summary>
100+
/// Signals that the asychronous operation has completed
101+
/// successfully.
102+
/// </summary>
103+
/// <param name="result">
104+
/// The return code for the <c>End*()</c> method.
105+
/// </param>
106+
/// <remarks>
107+
/// If a callback was provided at <see cref="IntelAsyncResult"/>
108+
/// initialization, it will be queued onto the
109+
/// <see cref="ThreadPool"/>.
110+
/// </remarks>
111+
internal void AsyncComplete(TResult result) {
112+
lock (this) {
113+
Debug.Assert(!this.completed);
114+
this.completed = true;
115+
this.result = result;
116+
if (this.waitHandle != null) {
117+
this.waitHandle.Set();
118+
}
119+
}
120+
121+
if (callback != null) {
122+
ThreadPool.QueueUserWorkItem(x => callback(this));
123+
}
124+
}
125+
126+
/// <summary>
127+
/// Signals that the asychronous operation was aborted due to
128+
/// an error.
129+
/// </summary>
130+
/// <param name="exception">
131+
/// The exception to throw from the <c>End*()</c> method.
132+
/// </param>
133+
/// <remarks>
134+
/// If a callback was provided at <see cref="IntelAsyncResult"/>
135+
/// initialization, it will be queued onto the
136+
/// <see cref="ThreadPool"/>.
137+
/// </remarks>
138+
internal void AsyncComplete(Exception exception) {
139+
Contract.Requires(exception != null);
140+
lock (this) {
141+
Debug.Assert(!this.completed);
142+
this.completed = true;
143+
this.exception = exception;
144+
if (this.waitHandle != null) {
145+
this.waitHandle.Set();
146+
}
147+
}
148+
149+
if (callback != null) {
150+
ThreadPool.QueueUserWorkItem(x => callback(this));
151+
}
152+
}
153+
154+
/// <summary>
155+
/// Signals that the asychronous operation has completed
156+
/// successfully, but the client should be notified synchronously.
157+
/// </summary>
158+
/// <param name="result">
159+
/// The return code for the <c>End*()</c> method.
160+
/// </param>
161+
/// <remarks>
162+
/// If a callback was provided at <see cref="IntelAsyncResult"/>
163+
/// initialization, it will be called immediately.
164+
/// </remarks>
165+
internal void SyncComplete(TResult result) {
166+
lock (this) {
167+
Debug.Assert(this.waitHandle == null);
168+
Debug.Assert(!this.completed);
169+
this.completed = true;
170+
this.result = result;
171+
this.synchronous = true;
172+
}
173+
174+
if (callback != null) {
175+
callback(this);
176+
}
177+
}
178+
179+
/// <summary>
180+
/// Signals that the asychronous operation was aborted due to an
181+
/// error, but the client should be notified synchronously.
182+
/// </summary>
183+
/// <param name="exception">
184+
/// The exception to throw from the <c>End*()</c> method.
185+
/// </param>
186+
/// <remarks>
187+
/// If a callback was provided at <see cref="IntelAsyncResult"/>
188+
/// initialization, it will be called immediately.
189+
/// </remarks>
190+
internal void SyncComplete(Exception exception) {
191+
Contract.Requires(exception != null);
192+
lock (this) {
193+
Debug.Assert(this.waitHandle == null);
194+
Debug.Assert(!this.completed);
195+
this.completed = true;
196+
this.exception = exception;
197+
this.synchronous = true;
198+
}
199+
200+
if (callback != null) {
201+
callback(this);
202+
}
203+
}
204+
205+
/// <summary>
206+
/// Waits for the asynchronous call to complete, returning the queued
207+
/// value or throwing an exception as appropriate.
208+
/// </summary>
209+
/// <returns>
210+
/// The value provided to <see cref="AsyncComplete(TResult)"/> or
211+
/// <see cref="SyncComplete(TResult)"/>.
212+
/// </returns>
213+
internal TResult Wait(TOwner owner) {
214+
if (this.owner != owner) {
215+
throw new ArgumentException();
216+
}
217+
218+
WaitHandle handle = null;
219+
lock (this) {
220+
if (this.disposed) {
221+
throw new InvalidOperationException();
222+
} else if (this.waiting) {
223+
throw new InvalidOperationException();
224+
} else if (!this.completed) {
225+
handle = this.AsyncWaitHandle;
226+
}
227+
this.waiting = true;
228+
}
229+
230+
if (handle != null) {
231+
handle.WaitOne();
232+
}
233+
234+
lock (this) {
235+
this.disposed = true;
236+
this.waitHandle = null;
237+
if (handle != null) {
238+
handle.Dispose();
239+
}
240+
}
241+
242+
if (this.exception != null) {
243+
throw this.exception;
244+
} else {
245+
return this.result;
246+
}
247+
}
248+
}
249+
}

PleaseIgnore.IntelMap/PleaseIgnore.IntelMap.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
<Compile Include="..\ProductInfo.cs">
159159
<Link>Properties\ProductInfo.cs</Link>
160160
</Compile>
161+
<Compile Include="IntelAsyncResult.cs" />
161162
<Compile Include="IntelChannel.cs" />
162163
<Compile Include="IntelEventArgs.cs" />
163164
<Compile Include="IntelException.cs" />

0 commit comments

Comments
 (0)