Mercurial > pub > ImplabNet
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