##// END OF EJS Templates
fixed timeout handling in promises
cin -
r148:e6d4b41f0101 v2
parent child
Show More
@@ -1,353 +1,353
1 using System;
1 using System;
2 using Implab.Parallels;
2 using Implab.Parallels;
3 using System.Threading;
3 using System.Threading;
4 using System.Reflection;
4 using System.Reflection;
5
5
6 namespace Implab {
6 namespace Implab {
7 public abstract class AbstractEvent<THandler> : ICancellationToken, ICancellable {
7 public abstract class AbstractEvent<THandler> : ICancellationToken, ICancellable {
8
8
9 const int UNRESOLVED_SATE = 0;
9 const int UNRESOLVED_SATE = 0;
10 const int TRANSITIONAL_STATE = 1;
10 const int TRANSITIONAL_STATE = 1;
11 const int SUCCEEDED_STATE = 2;
11 const int SUCCEEDED_STATE = 2;
12 const int REJECTED_STATE = 3;
12 const int REJECTED_STATE = 3;
13 const int CANCELLED_STATE = 4;
13 const int CANCELLED_STATE = 4;
14
14
15 const int CANCEL_NOT_REQUESTED = 0;
15 const int CANCEL_NOT_REQUESTED = 0;
16 const int CANCEL_REQUESTING = 1;
16 const int CANCEL_REQUESTING = 1;
17 const int CANCEL_REQUESTED = 2;
17 const int CANCEL_REQUESTED = 2;
18
18
19 const int RESERVED_HANDLERS_COUNT = 4;
19 const int RESERVED_HANDLERS_COUNT = 4;
20
20
21 int m_state;
21 int m_state;
22 Exception m_error;
22 Exception m_error;
23 int m_handlersCount;
23 int m_handlersCount;
24
24
25 readonly THandler[] m_handlers = new THandler[RESERVED_HANDLERS_COUNT];
25 readonly THandler[] m_handlers = new THandler[RESERVED_HANDLERS_COUNT];
26 MTQueue<THandler> m_extraHandlers;
26 MTQueue<THandler> m_extraHandlers;
27 int m_handlerPointer = -1;
27 int m_handlerPointer = -1;
28 int m_handlersCommited;
28 int m_handlersCommited;
29
29
30 int m_cancelRequest;
30 int m_cancelRequest;
31 Exception m_cancelationReason;
31 Exception m_cancelationReason;
32 MTQueue<Action<Exception>> m_cancelationHandlers;
32 MTQueue<Action<Exception>> m_cancelationHandlers;
33
33
34
34
35 #region state managment
35 #region state managment
36 bool BeginTransit() {
36 bool BeginTransit() {
37 return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE);
37 return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE);
38 }
38 }
39
39
40 void CompleteTransit(int state) {
40 void CompleteTransit(int state) {
41 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
41 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
42 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
42 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
43 }
43 }
44
44
45 void WaitTransition() {
45 void WaitTransition() {
46 while (m_state == TRANSITIONAL_STATE) {
46 while (m_state == TRANSITIONAL_STATE) {
47 Thread.MemoryBarrier();
47 Thread.MemoryBarrier();
48 }
48 }
49 }
49 }
50
50
51 protected bool BeginSetResult() {
51 protected bool BeginSetResult() {
52 if (!BeginTransit()) {
52 if (!BeginTransit()) {
53 WaitTransition();
53 WaitTransition();
54 if (m_state != CANCELLED_STATE)
54 if (m_state != CANCELLED_STATE)
55 throw new InvalidOperationException("The promise is already resolved");
55 throw new InvalidOperationException("The promise is already resolved");
56 return false;
56 return false;
57 }
57 }
58 return true;
58 return true;
59 }
59 }
60
60
61 protected void EndSetResult() {
61 protected void EndSetResult() {
62 CompleteTransit(SUCCEEDED_STATE);
62 CompleteTransit(SUCCEEDED_STATE);
63 OnSuccess();
63 OnSuccess();
64 }
64 }
65
65
66
66
67
67
68 /// <summary>
68 /// <summary>
69 /// ВыполняСт ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, сообщая ΠΎΠ± ошибкС
69 /// ВыполняСт ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, сообщая ΠΎΠ± ошибкС
70 /// </summary>
70 /// </summary>
71 /// <remarks>
71 /// <remarks>
72 /// ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π² ΠΌΠ½ΠΎΠ³ΠΎΠΏΡ‚ΠΎΡ‡Π½ΠΎΠΉ срСдС, ΠΏΡ€ΠΈ Π΅Π³ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ сразу нСсколько ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ²
72 /// ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π² ΠΌΠ½ΠΎΠ³ΠΎΠΏΡ‚ΠΎΡ‡Π½ΠΎΠΉ срСдС, ΠΏΡ€ΠΈ Π΅Π³ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ сразу нСсколько ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ²
73 /// ΠΌΠΎΠ³Ρƒ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ ΠΎΡˆΠΈΠ±ΠΊΡƒ, ΠΏΡ€ΠΈ этом Ρ‚ΠΎΠ»ΡŒΠΊΠΎ пСрвая Π±ΡƒΠ΄Π΅Ρ‚ использована Π² качСствС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°, ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅
73 /// ΠΌΠΎΠ³Ρƒ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ ΠΎΡˆΠΈΠ±ΠΊΡƒ, ΠΏΡ€ΠΈ этом Ρ‚ΠΎΠ»ΡŒΠΊΠΎ пСрвая Π±ΡƒΠ΄Π΅Ρ‚ использована Π² качСствС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°, ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅
74 /// Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΡ€ΠΎΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΠΎΠ²Π°Π½Ρ‹.
74 /// Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΡ€ΠΎΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΠΎΠ²Π°Π½Ρ‹.
75 /// </remarks>
75 /// </remarks>
76 /// <param name="error">Π˜ΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ возникшСС ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ</param>
76 /// <param name="error">Π˜ΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ возникшСС ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ</param>
77 /// <exception cref="InvalidOperationException">Π”Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception>
77 /// <exception cref="InvalidOperationException">Π”Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception>
78 protected void SetError(Exception error) {
78 protected void SetError(Exception error) {
79 if (BeginTransit()) {
79 if (BeginTransit()) {
80 if (error is OperationCanceledException) {
80 if (error is OperationCanceledException) {
81 CompleteTransit(CANCELLED_STATE);
81 CompleteTransit(CANCELLED_STATE);
82 m_error = error.InnerException;
82 m_error = error.InnerException;
83 OnCancelled();
83 OnCancelled();
84 } else {
84 } else {
85 m_error = error is PromiseTransientException ? error.InnerException : error;
85 m_error = error is PromiseTransientException ? error.InnerException : error;
86 CompleteTransit(REJECTED_STATE);
86 CompleteTransit(REJECTED_STATE);
87 OnError();
87 OnError();
88 }
88 }
89 } else {
89 } else {
90 WaitTransition();
90 WaitTransition();
91 if (m_state == SUCCEEDED_STATE)
91 if (m_state == SUCCEEDED_STATE)
92 throw new InvalidOperationException("The promise is already resolved");
92 throw new InvalidOperationException("The promise is already resolved");
93 }
93 }
94 }
94 }
95
95
96 /// <summary>
96 /// <summary>
97 /// ΠžΡ‚ΠΌΠ΅Π½ΡΠ΅Ρ‚ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ, Ссли это Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ.
97 /// ΠžΡ‚ΠΌΠ΅Π½ΡΠ΅Ρ‚ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ, Ссли это Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ.
98 /// </summary>
98 /// </summary>
99 /// <remarks>Для опрСдСлСния Π±Ρ‹Π»Π° Π»ΠΈ опСрация ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½Π° слСдуСт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ свойство <see cref="IsCancelled"/>.</remarks>
99 /// <remarks>Для опрСдСлСния Π±Ρ‹Π»Π° Π»ΠΈ опСрация ΠΎΡ‚ΠΌΠ΅Π½Π΅Π½Π° слСдуСт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ свойство <see cref="IsCancelled"/>.</remarks>
100 protected void SetCancelled(Exception reason) {
100 protected void SetCancelled(Exception reason) {
101 if (BeginTransit()) {
101 if (BeginTransit()) {
102 m_error = reason;
102 m_error = reason;
103 CompleteTransit(CANCELLED_STATE);
103 CompleteTransit(CANCELLED_STATE);
104 OnCancelled();
104 OnCancelled();
105 }
105 }
106 }
106 }
107
107
108 protected abstract void SignalSuccess(THandler handler);
108 protected abstract void SignalSuccess(THandler handler);
109
109
110 protected abstract void SignalError(THandler handler, Exception error);
110 protected abstract void SignalError(THandler handler, Exception error);
111
111
112 protected abstract void SignalCancelled(THandler handler, Exception reason);
112 protected abstract void SignalCancelled(THandler handler, Exception reason);
113
113
114 void OnSuccess() {
114 void OnSuccess() {
115 var hp = m_handlerPointer;
115 var hp = m_handlerPointer;
116 var slot = hp +1 ;
116 var slot = hp +1 ;
117 while (slot < m_handlersCommited) {
117 while (slot < m_handlersCommited) {
118 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) {
118 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) {
119 SignalSuccess(m_handlers[slot]);
119 SignalSuccess(m_handlers[slot]);
120 }
120 }
121 hp = m_handlerPointer;
121 hp = m_handlerPointer;
122 slot = hp +1 ;
122 slot = hp +1 ;
123 }
123 }
124
124
125
125
126 if (m_extraHandlers != null) {
126 if (m_extraHandlers != null) {
127 THandler handler;
127 THandler handler;
128 while (m_extraHandlers.TryDequeue(out handler))
128 while (m_extraHandlers.TryDequeue(out handler))
129 SignalSuccess(handler);
129 SignalSuccess(handler);
130 }
130 }
131 }
131 }
132
132
133 void OnError() {
133 void OnError() {
134 var hp = m_handlerPointer;
134 var hp = m_handlerPointer;
135 var slot = hp +1 ;
135 var slot = hp +1 ;
136 while (slot < m_handlersCommited) {
136 while (slot < m_handlersCommited) {
137 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) {
137 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) {
138 SignalError(m_handlers[slot],m_error);
138 SignalError(m_handlers[slot],m_error);
139 }
139 }
140 hp = m_handlerPointer;
140 hp = m_handlerPointer;
141 slot = hp +1 ;
141 slot = hp +1 ;
142 }
142 }
143
143
144 if (m_extraHandlers != null) {
144 if (m_extraHandlers != null) {
145 THandler handler;
145 THandler handler;
146 while (m_extraHandlers.TryDequeue(out handler))
146 while (m_extraHandlers.TryDequeue(out handler))
147 SignalError(handler, m_error);
147 SignalError(handler, m_error);
148 }
148 }
149 }
149 }
150
150
151 void OnCancelled() {
151 void OnCancelled() {
152 var hp = m_handlerPointer;
152 var hp = m_handlerPointer;
153 var slot = hp +1 ;
153 var slot = hp +1 ;
154 while (slot < m_handlersCommited) {
154 while (slot < m_handlersCommited) {
155 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) {
155 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) {
156 SignalCancelled(m_handlers[slot], m_error);
156 SignalCancelled(m_handlers[slot], m_error);
157 }
157 }
158 hp = m_handlerPointer;
158 hp = m_handlerPointer;
159 slot = hp +1 ;
159 slot = hp +1 ;
160 }
160 }
161
161
162 if (m_extraHandlers != null) {
162 if (m_extraHandlers != null) {
163 THandler handler;
163 THandler handler;
164 while (m_extraHandlers.TryDequeue(out handler))
164 while (m_extraHandlers.TryDequeue(out handler))
165 SignalCancelled(handler, m_error);
165 SignalCancelled(handler, m_error);
166 }
166 }
167 }
167 }
168
168
169 #endregion
169 #endregion
170
170
171 protected abstract Signal GetResolveSignal();
171 protected abstract Signal GetResolveSignal();
172
172
173 #region synchronization traits
173 #region synchronization traits
174 protected void WaitResult(int timeout) {
174 protected void WaitResult(int timeout) {
175 if (!IsResolved)
175 if (!(IsResolved || GetResolveSignal().Wait(timeout)))
176 GetResolveSignal().Wait(timeout);
176 throw new TimeoutException();
177
177
178 switch (m_state) {
178 switch (m_state) {
179 case SUCCEEDED_STATE:
179 case SUCCEEDED_STATE:
180 return;
180 return;
181 case CANCELLED_STATE:
181 case CANCELLED_STATE:
182 throw new OperationCanceledException();
182 throw new OperationCanceledException();
183 case REJECTED_STATE:
183 case REJECTED_STATE:
184 throw new TargetInvocationException(m_error);
184 throw new TargetInvocationException(m_error);
185 default:
185 default:
186 throw new ApplicationException(String.Format("Invalid promise state {0}", m_state));
186 throw new ApplicationException(String.Format("Invalid promise state {0}", m_state));
187 }
187 }
188 }
188 }
189 #endregion
189 #endregion
190
190
191 #region handlers managment
191 #region handlers managment
192
192
193 protected void AddHandler(THandler handler) {
193 protected void AddHandler(THandler handler) {
194
194
195 if (m_state > 1) {
195 if (m_state > 1) {
196 // the promise is in the resolved state, just invoke the handler
196 // the promise is in the resolved state, just invoke the handler
197 InvokeHandler(handler);
197 InvokeHandler(handler);
198 } else {
198 } else {
199 var slot = Interlocked.Increment(ref m_handlersCount) - 1;
199 var slot = Interlocked.Increment(ref m_handlersCount) - 1;
200
200
201 if (slot < RESERVED_HANDLERS_COUNT) {
201 if (slot < RESERVED_HANDLERS_COUNT) {
202
202
203 m_handlers[slot] = handler;
203 m_handlers[slot] = handler;
204
204
205 while (slot != Interlocked.CompareExchange(ref m_handlersCommited, slot + 1, slot)) {
205 while (slot != Interlocked.CompareExchange(ref m_handlersCommited, slot + 1, slot)) {
206 }
206 }
207
207
208 if (m_state > 1) {
208 if (m_state > 1) {
209 do {
209 do {
210 var hp = m_handlerPointer;
210 var hp = m_handlerPointer;
211 slot = hp + 1;
211 slot = hp + 1;
212 if (slot < m_handlersCommited) {
212 if (slot < m_handlersCommited) {
213 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) != hp)
213 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) != hp)
214 continue;
214 continue;
215 InvokeHandler(m_handlers[slot]);
215 InvokeHandler(m_handlers[slot]);
216 }
216 }
217 break;
217 break;
218 } while(true);
218 } while(true);
219 }
219 }
220 } else {
220 } else {
221 if (slot == RESERVED_HANDLERS_COUNT) {
221 if (slot == RESERVED_HANDLERS_COUNT) {
222 m_extraHandlers = new MTQueue<THandler>();
222 m_extraHandlers = new MTQueue<THandler>();
223 } else {
223 } else {
224 while (m_extraHandlers == null)
224 while (m_extraHandlers == null)
225 Thread.MemoryBarrier();
225 Thread.MemoryBarrier();
226 }
226 }
227
227
228 m_extraHandlers.Enqueue(handler);
228 m_extraHandlers.Enqueue(handler);
229
229
230 if (m_state > 1 && m_extraHandlers.TryDequeue(out handler))
230 if (m_state > 1 && m_extraHandlers.TryDequeue(out handler))
231 // if the promise have been resolved while we was adding the handler to the queue
231 // if the promise have been resolved while we was adding the handler to the queue
232 // we can't guarantee that someone is still processing it
232 // we can't guarantee that someone is still processing it
233 // therefore we need to fetch a handler from the queue and execute it
233 // therefore we need to fetch a handler from the queue and execute it
234 // note that fetched handler may be not the one that we have added
234 // note that fetched handler may be not the one that we have added
235 // even we can fetch no handlers at all :)
235 // even we can fetch no handlers at all :)
236 InvokeHandler(handler);
236 InvokeHandler(handler);
237 }
237 }
238 }
238 }
239 }
239 }
240
240
241 protected void InvokeHandler(THandler handler) {
241 protected void InvokeHandler(THandler handler) {
242 switch (m_state) {
242 switch (m_state) {
243 case SUCCEEDED_STATE:
243 case SUCCEEDED_STATE:
244 SignalSuccess(handler);
244 SignalSuccess(handler);
245 break;
245 break;
246 case CANCELLED_STATE:
246 case CANCELLED_STATE:
247 SignalCancelled(handler, m_error);
247 SignalCancelled(handler, m_error);
248 break;
248 break;
249 case REJECTED_STATE:
249 case REJECTED_STATE:
250 SignalError(handler, m_error);
250 SignalError(handler, m_error);
251 break;
251 break;
252 default:
252 default:
253 throw new Exception(String.Format("Invalid promise state {0}", m_state));
253 throw new Exception(String.Format("Invalid promise state {0}", m_state));
254 }
254 }
255 }
255 }
256
256
257 #endregion
257 #endregion
258
258
259 #region IPromise implementation
259 #region IPromise implementation
260
260
261 public bool IsResolved {
261 public bool IsResolved {
262 get {
262 get {
263 Thread.MemoryBarrier();
263 Thread.MemoryBarrier();
264 return m_state > 1;
264 return m_state > 1;
265 }
265 }
266 }
266 }
267
267
268 public bool IsCancelled {
268 public bool IsCancelled {
269 get {
269 get {
270 Thread.MemoryBarrier();
270 Thread.MemoryBarrier();
271 return m_state == CANCELLED_STATE;
271 return m_state == CANCELLED_STATE;
272 }
272 }
273 }
273 }
274
274
275 #endregion
275 #endregion
276
276
277 public Exception Error {
277 public Exception Error {
278 get {
278 get {
279 return m_error;
279 return m_error;
280 }
280 }
281 }
281 }
282
282
283 public bool CancelOperationIfRequested() {
283 public bool CancelOperationIfRequested() {
284 if (IsCancellationRequested) {
284 if (IsCancellationRequested) {
285 CancelOperation(CancellationReason);
285 CancelOperation(CancellationReason);
286 return true;
286 return true;
287 }
287 }
288 return false;
288 return false;
289 }
289 }
290
290
291 public virtual void CancelOperation(Exception reason) {
291 public virtual void CancelOperation(Exception reason) {
292 SetCancelled(reason);
292 SetCancelled(reason);
293 }
293 }
294
294
295 public void CancellationRequested(Action<Exception> handler) {
295 public void CancellationRequested(Action<Exception> handler) {
296 Safe.ArgumentNotNull(handler, "handler");
296 Safe.ArgumentNotNull(handler, "handler");
297 if (IsCancellationRequested)
297 if (IsCancellationRequested)
298 handler(CancellationReason);
298 handler(CancellationReason);
299
299
300 if (m_cancelationHandlers == null)
300 if (m_cancelationHandlers == null)
301 Interlocked.CompareExchange(ref m_cancelationHandlers, new MTQueue<Action<Exception>>(), null);
301 Interlocked.CompareExchange(ref m_cancelationHandlers, new MTQueue<Action<Exception>>(), null);
302
302
303 m_cancelationHandlers.Enqueue(handler);
303 m_cancelationHandlers.Enqueue(handler);
304
304
305 if (IsCancellationRequested && m_cancelationHandlers.TryDequeue(out handler))
305 if (IsCancellationRequested && m_cancelationHandlers.TryDequeue(out handler))
306 // TryDeque implies MemoryBarrier()
306 // TryDeque implies MemoryBarrier()
307 handler(m_cancelationReason);
307 handler(m_cancelationReason);
308 }
308 }
309
309
310 public bool IsCancellationRequested {
310 public bool IsCancellationRequested {
311 get {
311 get {
312 do {
312 do {
313 if (m_cancelRequest == CANCEL_NOT_REQUESTED)
313 if (m_cancelRequest == CANCEL_NOT_REQUESTED)
314 return false;
314 return false;
315 if (m_cancelRequest == CANCEL_REQUESTED)
315 if (m_cancelRequest == CANCEL_REQUESTED)
316 return true;
316 return true;
317 Thread.MemoryBarrier();
317 Thread.MemoryBarrier();
318 } while(true);
318 } while(true);
319 }
319 }
320 }
320 }
321
321
322 public Exception CancellationReason {
322 public Exception CancellationReason {
323 get {
323 get {
324 do {
324 do {
325 Thread.MemoryBarrier();
325 Thread.MemoryBarrier();
326 } while(m_cancelRequest == CANCEL_REQUESTING);
326 } while(m_cancelRequest == CANCEL_REQUESTING);
327
327
328 return m_cancelationReason;
328 return m_cancelationReason;
329 }
329 }
330 }
330 }
331
331
332 #region ICancellable implementation
332 #region ICancellable implementation
333
333
334 public void Cancel() {
334 public void Cancel() {
335 Cancel(null);
335 Cancel(null);
336 }
336 }
337
337
338 public void Cancel(Exception reason) {
338 public void Cancel(Exception reason) {
339 if (CANCEL_NOT_REQUESTED == Interlocked.CompareExchange(ref m_cancelRequest, CANCEL_REQUESTING, CANCEL_NOT_REQUESTED)) {
339 if (CANCEL_NOT_REQUESTED == Interlocked.CompareExchange(ref m_cancelRequest, CANCEL_REQUESTING, CANCEL_NOT_REQUESTED)) {
340 m_cancelationReason = reason;
340 m_cancelationReason = reason;
341 m_cancelRequest = CANCEL_REQUESTED;
341 m_cancelRequest = CANCEL_REQUESTED;
342 if (m_cancelationHandlers != null) {
342 if (m_cancelationHandlers != null) {
343 Action<Exception> handler;
343 Action<Exception> handler;
344 while (m_cancelationHandlers.TryDequeue(out handler))
344 while (m_cancelationHandlers.TryDequeue(out handler))
345 handler(m_cancelationReason);
345 handler(m_cancelationReason);
346 }
346 }
347 }
347 }
348 }
348 }
349
349
350 #endregion
350 #endregion
351 }
351 }
352 }
352 }
353
353
General Comments 0
You need to be logged in to leave comments. Login now