Example #1
0
        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);
        }
Example #2
0
        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);
        }
Example #3
0
        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);
        }
Example #5
0
        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);
        }
Example #9
0
        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);
            }
        }