##// END OF EJS Templates
working on promises
working on promises

File last commit:

r240:fa6cbf4d8841 v3
r247:fb70574741a1 v3
Show More
CancellationToken.cs
64 lines | 2.2 KiB | text/x-csharp | CSharpLexer
/ Implab / CancellationToken.cs
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;
}
}
}
}