public void CancelAfter(int millisecondsDelay) { if (millisecondsDelay < -1) { throw new ArgumentOutOfRangeException("millisecondsDelay"); } CheckDisposed(); if (IsCancellationRequested || millisecondsDelay == Timeout.Infinite) { return; } if (timer == null) { // Have to be carefull not to create secondary background timer var t = new Timer(timer_callback, this, Timeout.Infinite, Timeout.Infinite); if (CustomInterlocked.CompareExchange(ref timer, t, null) != null) { t.Dispose(); } } Timer.Change(millisecondsDelay, Timeout.Infinite); }
internal CancellationTokenRegistration Register(Action callback, bool useSynchronizationContext) { CheckDisposed(); var tokenReg = new CancellationTokenRegistration(CustomInterlocked.Increment(ref currId), this); /* If the source is already canceled we execute the callback immediately * if not, we try to add it to the queue and if it is currently being processed * we try to execute it back ourselves to be sure the callback is ran */ if (IsCancellationRequested) { callback(); } else { callbacks.TryAdd(tokenReg, callback); if (IsCancellationRequested && callbacks.TryRemove(tokenReg, out callback)) { callback(); } } return(tokenReg); }
protected virtual void Dispose(bool disposing) { if (disposing && (state & StateDisposed) == 0) { if (CustomInterlocked.CompareExchange(ref state, StateDisposed, StateValid) == StateValid) { UnregisterLinkedTokens(); callbacks = null; } else { if (handle != null) { handle.WaitOne(); } state |= StateDisposed; Thread.MemoryBarrier(); } if (timer != null) { Timer.Dispose(); } ((IDisposable)handle).Dispose(); handle = null; } }
long UpdateStateWithOp(bool set) { int oldValue, newValue; do { oldValue = state; newValue = (int)(((oldValue >> 1) + 1) << 1) | (set ? 1 : 0); } while (CustomInterlocked.CompareExchange(ref state, newValue, oldValue) != oldValue); return(newValue); }
void UnregisterLinkedTokens() { var registrations = CustomInterlocked.Exchange(ref _linkedTokens, null); if (registrations == null) { return; } foreach (var linked in (CancellationTokenRegistration[])registrations) { linked.Dispose(); } }
void CommitChangeToHandle(long stamp) { CustomInterlocked.Increment(ref used); var tmpHandle = Handle; if (tmpHandle != null) { // First in all case we carry the operation we were called for if ((stamp & 1) == 1) { tmpHandle.Set(); } else { tmpHandle.Reset(); } /* Then what may happen is that the two suboperations (state change and handle change) * overlapped with others. In our case it doesn't matter if the two suboperations aren't * executed together at the same time, the only thing we have to make sure of is that both * state and handle are synchronized on the last visible state change. * * For instance if S is state change and H is handle change, for 3 concurrent operations * we may have the following serialized timeline: S1 S2 H2 S3 H3 H1 * Which is perfectly fine (all S were converted to H at some stage) but in that case * we have a mismatch between S and H at the end because the last operations done were * S3/H1. We thus need to repeat H3 to get to the desired final state. */ int currentState; do { currentState = state; if (currentState != stamp && (stamp & 1) != (currentState & 1)) { if ((currentState & 1) == 1) { tmpHandle.Set(); } else { tmpHandle.Reset(); } } } while (currentState != state); } CustomInterlocked.Decrement(ref used); }
protected virtual void Dispose(bool disposing) { if (!disposed.TryRelaxedSet()) { return; } if (handle != null) { var tmpHandle = CustomInterlocked.Exchange(ref handle, null); if (used > 0) { // A tiny wait (just a few cycles normally) before releasing SpinWait wait = new SpinWait(); while (used > 0) { wait.SpinOnce(); } } ((IDisposable)tmpHandle).Dispose(); } }
bool ApplyOperation(int num, out int newValue) { int oldCount; do { oldCount = initialCount; if (oldCount == 0) { newValue = 0; return(false); } newValue = oldCount + num; if (newValue < 0) { return(false); } } while (CustomInterlocked.CompareExchange(ref initialCount, newValue, oldCount) != oldCount); return(true); }
void Cancellation(bool throwOnFirstException) { if (CustomInterlocked.CompareExchange(ref state, StateCanceled, StateValid) != StateValid) { return; } handle.Set(); if (linkedTokens != null) { UnregisterLinkedTokens(); } var cbs = callbacks; if (cbs == null) { return; } List <Exception> exceptions = null; try { Action cb; for (int id = currId; id != int.MinValue; id--) { if (!cbs.TryRemove(new CancellationTokenRegistration(id, this), out cb)) { continue; } if (cb == null) { continue; } if (throwOnFirstException) { cb(); } else { try { cb(); } catch (Exception e) { if (exceptions == null) { exceptions = new List <Exception> (); } exceptions.Add(e); } } } } finally { cbs.Clear(); } if (exceptions != null) { throw new AggregateException(exceptions); } }