##// END OF EJS Templates
Promise is rewritten to use interlocked operations instead of locks
cin -
r19:e3935fdf59a2 promises
parent child
Show More
@@ -14,7 +14,7 namespace Implab.Test {
14 p.Then(x => res = x);
14 p.Then(x => res = x);
15 p.Resolve(100);
15 p.Resolve(100);
16
16
17 Assert.AreEqual(res, 100);
17 Assert.AreEqual(100, res);
18 }
18 }
19
19
20 [TestMethod]
20 [TestMethod]
@@ -244,7 +244,7 namespace Implab.Test {
244 [TestMethod]
244 [TestMethod]
245 public void ChainedMapTest() {
245 public void ChainedMapTest() {
246
246
247 using (var pool = new WorkerPool(8,100,0)) {
247 using (var pool = new WorkerPool(4,4,0)) {
248 int count = 10000;
248 int count = 10000;
249
249
250 double[] args = new double[count];
250 double[] args = new double[count];
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
@@ -15,19 +15,6 namespace Implab
15 get;
15 get;
16 }
16 }
17
17
18 /// <summary>
19 /// The current state of the promise.
20 /// </summary>
21 PromiseState State
22 {
23 get;
24 }
25
18
26 /// <summary>
27 /// Registers handler for the case when the promise is cencelled. If the promise already cancelled the
28 /// handler will be invoked immediatelly.
29 /// </summary>
30 /// <param name="handler">The handler</param>
31 void HandleCancelled(Action handler);
32 }
19 }
33 }
20 }
@@ -140,7 +140,7 namespace Implab.Parallels {
140
140
141 AsyncPool.InvokeNewThread(() => {
141 AsyncPool.InvokeNewThread(() => {
142 for (int i = 0; i < source.Length; i++) {
142 for (int i = 0; i < source.Length; i++) {
143 if(promise.State != PromiseState.Unresolved)
143 if(promise.IsResolved)
144 break; // stop processing in case of error or cancellation
144 break; // stop processing in case of error or cancellation
145 var idx = i;
145 var idx = i;
146 semaphore.WaitOne();
146 semaphore.WaitOne();
@@ -42,12 +42,13 namespace Implab.Parallels {
42 next = first.next;
42 next = first.next;
43 if (next == null) {
43 if (next == null) {
44 // this is the last element,
44 // this is the last element,
45 // then try to update tail
45 // then try to update the tail
46 if (first != Interlocked.CompareExchange(ref m_last, null, first)) {
46 if (first != Interlocked.CompareExchange(ref m_last, null, first)) {
47 // this is inconsistent situation which means that the queue is empty
47 // this is a ace condition
48 if (m_last == null)
48 if (m_last == null)
49 // the queue is empty
49 return false;
50 return false;
50 // tail has been changed, that means that we need to restart
51 // tail has been changed, than we need to restart
51 continue;
52 continue;
52 }
53 }
53
54
@@ -3,6 +3,7 using System.Collections.Generic;
3 using System.Reflection;
3 using System.Reflection;
4 using System.Diagnostics;
4 using System.Diagnostics;
5 using System.Threading;
5 using System.Threading;
6 using Implab.Parallels;
6
7
7 namespace Implab {
8 namespace Implab {
8
9
@@ -48,24 +49,53 namespace Implab {
48 /// </remarks>
49 /// </remarks>
49 public class Promise<T> : IPromise {
50 public class Promise<T> : IPromise {
50
51
51 struct ResultHandlerInfo {
52 struct HandlerDescriptor {
52 public ResultHandler<T> resultHandler;
53 public ResultHandler<T> resultHandler;
53 public ErrorHandler errorHandler;
54 public ErrorHandler errorHandler;
55 public Action cancellHandler;
56
57 public void Resolve(T result) {
58 if (resultHandler != null)
59 try {
60 resultHandler(result);
61 } catch (Exception e) {
62 Reject(e);
63 }
64 }
65
66 public void Reject(Exception err) {
67 if (errorHandler != null)
68 try {
69 errorHandler(err);
70 } catch {
71 }
72 }
73
74 public void Cancel() {
75 if (cancellHandler != null)
76 try {
77 cancellHandler();
78 } catch {
79 }
80 }
54 }
81 }
55
82
83 const int UnresolvedSate = 0;
84 const int TransitionalState = 1;
85 const int ResolvedState = 2;
86 const int RejectedState = 3;
87 const int CancelledState = 4;
88
56 readonly IPromise m_parent;
89 readonly IPromise m_parent;
57
90 readonly bool m_cancellable;
58 LinkedList<ResultHandlerInfo> m_resultHandlers = new LinkedList<ResultHandlerInfo>();
59 LinkedList<Action> m_cancelHandlers = new LinkedList<Action>();
60
91
61 readonly object m_lock = new Object();
62 readonly bool m_cancellable;
63 int m_childrenCount = 0;
92 int m_childrenCount = 0;
64
93 int m_state;
65 PromiseState m_state;
66 T m_result;
94 T m_result;
67 Exception m_error;
95 Exception m_error;
68
96
97 readonly MTQueue<HandlerDescriptor> m_handlers = new MTQueue<HandlerDescriptor>();
98
69 public Promise() {
99 public Promise() {
70 m_cancellable = true;
100 m_cancellable = true;
71 }
101 }
@@ -73,8 +103,6 namespace Implab {
73 public Promise(IPromise parent, bool cancellable) {
103 public Promise(IPromise parent, bool cancellable) {
74 m_cancellable = cancellable;
104 m_cancellable = cancellable;
75 m_parent = parent;
105 m_parent = parent;
76 if (parent != null)
77 parent.HandleCancelled(InternalCancel);
78 }
106 }
79
107
80 void InternalCancel() {
108 void InternalCancel() {
@@ -82,22 +110,39 namespace Implab {
82 Cancel(false);
110 Cancel(false);
83 }
111 }
84
112
113 bool BeginTransit() {
114 return UnresolvedSate == Interlocked.CompareExchange(ref m_state, TransitionalState, UnresolvedSate);
115 }
116
117 void CompleteTransit(int state) {
118 if (TransitionalState != Interlocked.CompareExchange(ref m_state, state, TransitionalState))
119 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
120 }
121
122 public bool IsResolved {
123 get {
124 return m_state > 1;
125 }
126 }
127
128 public bool IsCancelled {
129 get {
130 return m_state == CancelledState;
131 }
132 }
133
85 /// <summary>
134 /// <summary>
86 /// ВыполняСт ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, сообщая ΠΎΠ± ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ.
135 /// ВыполняСт ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, сообщая ΠΎΠ± ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ.
87 /// </summary>
136 /// </summary>
88 /// <param name="result">Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния.</param>
137 /// <param name="result">Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния.</param>
89 /// <exception cref="InvalidOperationException">Π”Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception>
138 /// <exception cref="InvalidOperationException">Π”Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception>
90 public void Resolve(T result) {
139 public void Resolve(T result) {
91 lock (m_lock) {
140 if (BeginTransit()) {
92 if (m_state == PromiseState.Cancelled)
93 return;
94 if (m_state != PromiseState.Unresolved)
95 throw new InvalidOperationException("The promise is already resolved");
96 m_result = result;
141 m_result = result;
97 m_state = PromiseState.Resolved;
142 CompleteTransit(ResolvedState);
98 }
143 OnStateChanged();
99
144 } else if (m_state != CancelledState)
100 OnStateChanged();
145 throw new InvalidOperationException("The promise is already resolved");
101 }
146 }
102
147
103 /// <summary>
148 /// <summary>
@@ -111,16 +156,12 namespace Implab {
111 /// <param name="error">Π˜ΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ возникшСС ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ</param>
156 /// <param name="error">Π˜ΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ возникшСС ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ</param>
112 /// <exception cref="InvalidOperationException">Π”Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception>
157 /// <exception cref="InvalidOperationException">Π”Π°Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ</exception>
113 public void Reject(Exception error) {
158 public void Reject(Exception error) {
114 lock (m_lock) {
159 if (BeginTransit()) {
115 if (m_state == PromiseState.Cancelled || m_state == PromiseState.Rejected)
116 return;
117 if (m_state != PromiseState.Unresolved)
118 throw new InvalidOperationException("The promise is already resolved");
119 m_error = error;
160 m_error = error;
120 m_state = PromiseState.Rejected;
161 CompleteTransit(RejectedState);
121 }
162 OnStateChanged();
122
163 } else if (m_state == ResolvedState)
123 OnStateChanged();
164 throw new InvalidOperationException("The promise is already resolved");
124 }
165 }
125
166
126 /// <summary>
167 /// <summary>
@@ -144,27 +185,27 namespace Implab {
144
185
145 var medium = new Promise<T>(this, true);
186 var medium = new Promise<T>(this, true);
146
187
147 var handlerInfo = new ResultHandlerInfo();
188 ResultHandler<T> resultHandler;
148
149 if (success != null)
189 if (success != null)
150 handlerInfo.resultHandler = x => {
190 resultHandler = x => {
151 success(x);
191 success(x);
152 medium.Resolve(x);
192 medium.Resolve(x);
153 };
193 };
154 else
194 else
155 handlerInfo.resultHandler = medium.Resolve;
195 resultHandler = medium.Resolve;
156
196
197 ErrorHandler errorHandler;
157 if (error != null)
198 if (error != null)
158 handlerInfo.errorHandler = x => {
199 errorHandler = x => {
159 try {
200 try {
160 error(x);
201 error(x);
161 } catch { }
202 } catch { }
162 medium.Reject(x);
203 medium.Reject(x);
163 };
204 };
164 else
205 else
165 handlerInfo.errorHandler = medium.Reject;
206 errorHandler = medium.Reject;
166
207
167 AddHandler(handlerInfo);
208 AddHandler(resultHandler, errorHandler, medium.InternalCancel);
168
209
169 return medium;
210 return medium;
170 }
211 }
@@ -182,27 +223,28 namespace Implab {
182
223
183 var medium = new Promise<T>(this, true);
224 var medium = new Promise<T>(this, true);
184
225
185 var handlerInfo = new ResultHandlerInfo();
226 ResultHandler<T> resultHandler;
227 ErrorHandler errorHandler;
186
228
187 if (success != null)
229 if (success != null)
188 handlerInfo.resultHandler = x => {
230 resultHandler = x => {
189 success(x);
231 success(x);
190 medium.Resolve(x);
232 medium.Resolve(x);
191 };
233 };
192 else
234 else
193 handlerInfo.resultHandler = medium.Resolve;
235 resultHandler = medium.Resolve;
194
236
195 if (error != null)
237 if (error != null)
196 handlerInfo.errorHandler = x => {
238 errorHandler = x => {
197 try {
239 try {
198 medium.Resolve(error(x));
240 medium.Resolve(error(x));
199 } catch { }
241 } catch { }
200 medium.Reject(x);
242 medium.Reject(x);
201 };
243 };
202 else
244 else
203 handlerInfo.errorHandler = medium.Reject;
245 errorHandler = medium.Reject;
204
246
205 AddHandler(handlerInfo);
247 AddHandler(resultHandler, errorHandler, medium.InternalCancel);
206
248
207 return medium;
249 return medium;
208 }
250 }
@@ -214,19 +256,17 namespace Implab {
214
256
215 var medium = new Promise<T>(this, true);
257 var medium = new Promise<T>(this, true);
216
258
217 var handlerInfo = new ResultHandlerInfo();
259 ResultHandler<T> resultHandler;
218
260
219 if (success != null)
261 if (success != null)
220 handlerInfo.resultHandler = x => {
262 resultHandler = x => {
221 success(x);
263 success(x);
222 medium.Resolve(x);
264 medium.Resolve(x);
223 };
265 };
224 else
266 else
225 handlerInfo.resultHandler = medium.Resolve;
267 resultHandler = medium.Resolve;
226
268
227 handlerInfo.errorHandler = medium.Reject;
269 AddHandler(resultHandler, medium.Reject, medium.InternalCancel);
228
229 AddHandler(handlerInfo);
230
270
231 return medium;
271 return medium;
232 }
272 }
@@ -249,15 +289,17 namespace Implab {
249
289
250 var medium = new Promise<T>(this, true);
290 var medium = new Promise<T>(this, true);
251
291
252 AddHandler(new ResultHandlerInfo {
292 AddHandler(
253 errorHandler = e => {
293 null,
294 e => {
254 try {
295 try {
255 medium.Resolve(handler(e));
296 medium.Resolve(handler(e));
256 } catch (Exception e2) {
297 } catch (Exception e2) {
257 medium.Reject(e2);
298 medium.Reject(e2);
258 }
299 }
259 }
300 },
260 });
301 medium.InternalCancel
302 );
261
303
262 return medium;
304 return medium;
263 }
305 }
@@ -268,8 +310,8 namespace Implab {
268
310
269 var medium = new Promise<T>();
311 var medium = new Promise<T>();
270
312
271 AddHandler(new ResultHandlerInfo {
313 AddHandler(
272 resultHandler = x => {
314 x => {
273 // to avoid handler being called multiple times we handle exception by ourselfs
315 // to avoid handler being called multiple times we handle exception by ourselfs
274 try {
316 try {
275 handler();
317 handler();
@@ -278,13 +320,16 namespace Implab {
278 medium.Reject(e);
320 medium.Reject(e);
279 }
321 }
280 },
322 },
281 errorHandler = x => {
323
324 e => {
282 try {
325 try {
283 handler();
326 handler();
284 } catch { }
327 } catch { }
285 medium.Reject(x);
328 medium.Reject(e);
286 }
329 },
287 });
330
331 medium.InternalCancel
332 );
288
333
289 return medium;
334 return medium;
290 }
335 }
@@ -304,17 +349,22 namespace Implab {
304 // создаСм ΠΏΡ€ΠΈΡ†Π΅ΠΏΠ»Π΅Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅
349 // создаСм ΠΏΡ€ΠΈΡ†Π΅ΠΏΠ»Π΅Π½Π½ΠΎΠ΅ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅
305 var chained = new Promise<TNew>();
350 var chained = new Promise<TNew>();
306
351
307 AddHandler(new ResultHandlerInfo() {
352 ResultHandler<T> resultHandler = result => chained.Resolve(mapper(result));
308 resultHandler = result => chained.Resolve(mapper(result)),
353 ErrorHandler errorHandler = delegate(Exception e) {
309 errorHandler = delegate(Exception e) {
354 if (error != null)
310 if (error != null)
355 try {
311 try {
356 error(e);
312 error(e);
357 } catch { }
313 } catch { }
358 // Π² случаС ошибки Π½ΡƒΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ дальшС ΠΏΠΎ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ΅
314 // Π² случаС ошибки Π½ΡƒΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ дальшС ΠΏΠΎ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ΅
359 chained.Reject(e);
315 chained.Reject(e);
360 };
316 }
361
317 });
362
363 AddHandler(
364 resultHandler,
365 errorHandler,
366 chained.InternalCancel
367 );
318
368
319 return chained;
369 return chained;
320 }
370 }
@@ -341,27 +391,32 namespace Implab {
341 // ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· Π½Π΅Π³ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Ρ€Π°Π±ΠΎΡ‚Ρ‹.
391 // ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· Π½Π΅Π³ΠΎ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Ρ€Π°Π±ΠΎΡ‚Ρ‹.
342 var medium = new Promise<TNew>(this, true);
392 var medium = new Promise<TNew>(this, true);
343
393
344 AddHandler(new ResultHandlerInfo {
394 ResultHandler<T> resultHandler = delegate(T result) {
345 resultHandler = delegate(T result) {
395 if (medium.IsCancelled)
346 if (medium.State == PromiseState.Cancelled)
396 return;
347 return;
348
397
349 var promise = chained(result);
398 var promise = chained(result);
350
399
351 // notify chained operation that it's not needed
400 // notify chained operation that it's not needed
352 medium.Cancelled(() => promise.Cancel());
401 medium.Cancelled(() => promise.Cancel());
353 promise.Then(
402 promise.Then(
354 x => medium.Resolve(x),
403 x => medium.Resolve(x),
355 e => medium.Reject(e)
404 e => medium.Reject(e)
356 );
405 );
357 },
406 };
358 errorHandler = delegate(Exception e) {
407
359 if (error != null)
408 ErrorHandler errorHandler = delegate(Exception e) {
360 error(e);
409 if (error != null)
361 // Π² случаС ошибки Π½ΡƒΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ дальшС ΠΏΠΎ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ΅
410 error(e);
362 medium.Reject(e);
411 // Π² случаС ошибки Π½ΡƒΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ дальшС ΠΏΠΎ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ΅
363 }
412 medium.Reject(e);
364 });
413 };
414
415 AddHandler(
416 resultHandler,
417 errorHandler,
418 medium.InternalCancel
419 );
365
420
366 return medium;
421 return medium;
367 }
422 }
@@ -371,19 +426,19 namespace Implab {
371 }
426 }
372
427
373 public Promise<T> Cancelled(Action handler) {
428 public Promise<T> Cancelled(Action handler) {
374 if (handler == null)
429 AddHandler(null, null, handler);
375 return this;
376 lock (m_lock) {
377 if (m_state == PromiseState.Unresolved)
378 m_cancelHandlers.AddLast(handler);
379 else if (m_state == PromiseState.Cancelled)
380 handler();
381 }
382 return this;
430 return this;
383 }
431 }
384
432
385 public void HandleCancelled(Action handler) {
433 public Promise<T> Finally(Action handler) {
386 Cancelled(handler);
434 if (handler == null)
435 throw new ArgumentNullException("handler");
436 AddHandler(
437 x => handler(),
438 e => handler(),
439 handler
440 );
441 return this;
387 }
442 }
388
443
389 /// <summary>
444 /// <summary>
@@ -415,15 +470,15 namespace Implab {
415 if (!evt.WaitOne(timeout, true))
470 if (!evt.WaitOne(timeout, true))
416 throw new TimeoutException();
471 throw new TimeoutException();
417
472
418 switch (State) {
473 switch (m_state) {
419 case PromiseState.Resolved:
474 case ResolvedState:
420 return m_result;
475 return m_result;
421 case PromiseState.Cancelled:
476 case CancelledState:
422 throw new OperationCanceledException();
477 throw new OperationCanceledException();
423 case PromiseState.Rejected:
478 case RejectedState:
424 throw new TargetInvocationException(m_error);
479 throw new TargetInvocationException(m_error);
425 default:
480 default:
426 throw new ApplicationException(String.Format("Invalid promise state {0}", State));
481 throw new ApplicationException(String.Format("Invalid promise state {0}", m_state));
427 }
482 }
428 }
483 }
429
484
@@ -431,40 +486,45 namespace Implab {
431 return Join(Timeout.Infinite);
486 return Join(Timeout.Infinite);
432 }
487 }
433
488
434 void AddHandler(ResultHandlerInfo handler) {
489 void AddHandler(ResultHandler<T> success, ErrorHandler error, Action cancel) {
435 bool invokeRequired = false;
490 Interlocked.Increment(ref m_childrenCount);
491
492 HandlerDescriptor handler = new HandlerDescriptor {
493 resultHandler = success,
494 errorHandler = error,
495 cancellHandler = cancel
496 };
436
497
437 lock (m_lock) {
498 bool queued;
438 m_childrenCount++;
499
439 if (m_state == PromiseState.Unresolved) {
500 if (!IsResolved) {
440 m_resultHandlers.AddLast(handler);
501 m_handlers.Enqueue(handler);
441 } else
502 queued = true;
442 invokeRequired = true;
503 } else {
504 // the promise is in resolved state, just invoke the handled with minimum overhead
505 queued = false;
506 InvokeHandler(handler);
443 }
507 }
444
508
445 // ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ сам ΠΎΠ±ΡŠΠ΅ΠΊΡ‚
509 if (queued && IsResolved && m_handlers.TryDequeue(out handler))
446 if (invokeRequired)
510 // if the promise have been resolved while we was adding handler to the queue
511 // we can't guarantee that someone is still processing it
512 // therefore we will fetch a handler from the queue and execute it
513 // note that fetched handler may be not the one we have added
447 InvokeHandler(handler);
514 InvokeHandler(handler);
515
448 }
516 }
449
517
450 void InvokeHandler(ResultHandlerInfo handler) {
518 void InvokeHandler(HandlerDescriptor handler) {
451 switch (m_state) {
519 switch (m_state) {
452 case PromiseState.Resolved:
520 case ResolvedState:
453 try {
521 handler.Resolve(m_result);
454 if (handler.resultHandler != null)
455 handler.resultHandler(m_result);
456 } catch (Exception e) {
457 try {
458 if (handler.errorHandler != null)
459 handler.errorHandler(e);
460 } catch { }
461 }
462 break;
522 break;
463 case PromiseState.Rejected:
523 case RejectedState:
464 try {
524 handler.Reject(m_error);
465 if (handler.errorHandler != null)
525 break;
466 handler.errorHandler(m_error);
526 case CancelledState:
467 } catch { }
527 handler.Cancel();
468 break;
528 break;
469 default:
529 default:
470 // do nothing
530 // do nothing
@@ -473,76 +533,31 namespace Implab {
473 }
533 }
474
534
475 protected virtual void OnStateChanged() {
535 protected virtual void OnStateChanged() {
476 switch (m_state) {
536 HandlerDescriptor handler;
477 case PromiseState.Resolved:
537 while (m_handlers.TryDequeue(out handler))
478 foreach (var resultHandlerInfo in m_resultHandlers)
538 InvokeHandler(handler);
479 try {
480 if (resultHandlerInfo.resultHandler != null)
481 resultHandlerInfo.resultHandler(m_result);
482 } catch (Exception e) {
483 try {
484 if (resultHandlerInfo.errorHandler != null)
485 resultHandlerInfo.errorHandler(e);
486 } catch { }
487 }
488 break;
489 case PromiseState.Cancelled:
490 foreach (var cancelHandler in m_cancelHandlers)
491 cancelHandler();
492 break;
493 case PromiseState.Rejected:
494 foreach (var resultHandlerInfo in m_resultHandlers)
495 try {
496 if (resultHandlerInfo.errorHandler != null)
497 resultHandlerInfo.errorHandler(m_error);
498 } catch { }
499 break;
500 default:
501 throw new InvalidOperationException(String.Format("Promise entered an invalid state {0}", m_state));
502 }
503
504 m_resultHandlers = null;
505 m_cancelHandlers = null;
506 }
539 }
507
540
508
541
509
542
510 public bool IsExclusive {
543 public bool IsExclusive {
511 get {
544 get {
512 lock (m_lock) {
545 return m_childrenCount <= 1;
513 return m_childrenCount <= 1;
514 }
515 }
516 }
517
518 public PromiseState State {
519 get {
520 lock (m_lock) {
521 return m_state;
522 }
523 }
546 }
524 }
547 }
525
548
526 protected bool Cancel(bool dependencies) {
549 protected bool Cancel(bool dependencies) {
527 bool result;
550 if (BeginTransit()) {
528
551 CompleteTransit(CancelledState);
529 lock (m_lock) {
530 if (m_state == PromiseState.Unresolved) {
531 m_state = PromiseState.Cancelled;
532 result = true;
533 } else {
534 result = false;
535 }
536 }
537
538 if (result)
539 OnStateChanged();
552 OnStateChanged();
540
553
541 if (dependencies && m_parent != null && m_parent.IsExclusive) {
554 if (dependencies && m_parent != null && m_parent.IsExclusive)
542 m_parent.Cancel();
555 m_parent.Cancel();
556
557 return true;
558 } else {
559 return false;
543 }
560 }
544
545 return result;
546 }
561 }
547
562
548 }
563 }
General Comments 0
You need to be logged in to leave comments. Login now