comparison Implab/CancellationToken.cs @ 240:fa6cbf4d8841 v3

refactoring, moving to dotnercore, simplifying promises
author cin
date Tue, 23 Jan 2018 19:39:21 +0300
parents
children 5cb4826c2c2a
comparison
equal deleted inserted replaced
239:eedf4d834e67 240:fa6cbf4d8841
1 using System;
2 using System.Threading;
3 using Implab.Parallels;
4
5 namespace Implab {
6 public class CancellationToken : ICancellationToken {
7 const int CANCEL_NOT_REQUESTED = 0;
8 const int CANCEL_REQUESTING = 1;
9 const int CANCEL_REQUESTED = 2;
10
11 volatile int m_state = CANCEL_NOT_REQUESTED;
12
13 Action<Exception> m_handler;
14
15 Parallels.SimpleAsyncQueue<Action<Exception>> m_handlers;
16
17 public bool IsCancellationRequested {
18 get { return m_state == CANCEL_REQUESTED; }
19 }
20
21 public Exception CancellationReason {
22 get; set;
23 }
24
25 public void CancellationRequested(Action<Exception> handler) {
26 Safe.ArgumentNotNull(handler, nameof(handler));
27 if (IsCancellationRequested) {
28 handler(CancellationReason);
29 } else {
30 EnqueueHandler(handler);
31 if (IsCancellationRequested && TryDequeueHandler(out handler))
32 handler(CancellationReason);
33 }
34 }
35
36 bool TryDequeueHandler(out Action<Exception> handler) {
37 handler = Interlocked.Exchange(ref m_handler, null);
38 if (handler != null)
39 return true;
40 else if (m_handlers != null)
41 return m_handlers.TryDequeue(out handler);
42 else
43 return false;
44 }
45
46 void EnqueueHandler(Action<Exception> handler) {
47 if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) {
48 if (m_handlers == null)
49 // compare-exchange will fprotect from loosing already created queue
50 Interlocked.CompareExchange(ref m_handlers, new SimpleAsyncQueue<Action<Exception>>(), null);
51 m_handlers.Enqueue(handler);
52 }
53 }
54
55 void RequestCancellation(Exception reason) {
56 if (Interlocked.CompareExchange(ref m_state, CANCEL_REQUESTING, CANCEL_NOT_REQUESTED) == CANCEL_NOT_REQUESTED) {
57 if (reason == null)
58 reason = new OperationCanceledException();
59 CancellationReason = reason;
60 m_state = CANCEL_REQUESTED;
61 }
62 }
63
64 }
65 }