diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/CancellationToken.cs	Tue Jan 23 19:39:21 2018 +0300
@@ -0,0 +1,65 @@
+using System;
+using System.Threading;
+using Implab.Parallels;
+
+namespace Implab {
+    public class CancellationToken : ICancellationToken {
+        const int CANCEL_NOT_REQUESTED = 0;
+        const int CANCEL_REQUESTING = 1;
+        const int CANCEL_REQUESTED = 2;
+
+        volatile int m_state = CANCEL_NOT_REQUESTED;
+
+        Action<Exception> m_handler;
+
+        Parallels.SimpleAsyncQueue<Action<Exception>> m_handlers;
+
+        public bool IsCancellationRequested {
+            get { return m_state == CANCEL_REQUESTED; }
+        }
+
+        public Exception CancellationReason {
+            get; set;
+        }
+
+        public void CancellationRequested(Action<Exception> handler) {
+            Safe.ArgumentNotNull(handler, nameof(handler));
+            if (IsCancellationRequested) {
+                handler(CancellationReason);
+            } else {
+                EnqueueHandler(handler);
+                if (IsCancellationRequested && TryDequeueHandler(out handler))
+                    handler(CancellationReason);
+            }
+        }
+
+        bool TryDequeueHandler(out Action<Exception> handler) {
+            handler = Interlocked.Exchange(ref m_handler, null);
+            if (handler != null)
+                return true;
+            else if (m_handlers != null)
+                return m_handlers.TryDequeue(out handler);
+            else
+                return false;
+        }
+
+        void EnqueueHandler(Action<Exception> handler) {
+            if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) {
+                if (m_handlers == null)
+                    // compare-exchange will fprotect from loosing already created queue
+                    Interlocked.CompareExchange(ref m_handlers, new SimpleAsyncQueue<Action<Exception>>(), null);
+                m_handlers.Enqueue(handler);
+            }
+        }
+
+        void RequestCancellation(Exception reason) {
+            if (Interlocked.CompareExchange(ref m_state, CANCEL_REQUESTING, CANCEL_NOT_REQUESTED) == CANCEL_NOT_REQUESTED) {
+                if (reason == null)
+                    reason = new OperationCanceledException();
+                CancellationReason = reason;
+                m_state = CANCEL_REQUESTED;
+            }
+        }
+        
+    }
+}
\ No newline at end of file