/// <summary> /// Registers a callback object. If cancellation has already occurred, the /// callback will have been run by the time this method returns. /// </summary> internal CancellationTokenRegistration InternalRegister( Action <object> callback, object stateForCallback, SynchronizationContext targetSyncContext, ExecutionContext executionContext) { ThrowIfDisposed(); // the CancellationToken has already checked that the token is cancelable before calling this method. Contract.Assert(CanBeCanceled, "Cannot register for uncancelable token src"); // if not canceled, register the event handlers // if canceled already, run the callback synchronously // Apart from the semantics of late-enlistment, this also ensures that during ExecuteCallbackHandlers() there // will be no mutation of the _registeredCallbacks list if (!IsCancellationRequested) { int myIndex = Thread.CurrentThread.ManagedThreadId % s_nLists; CancellationCallbackInfo callbackInfo = new CancellationCallbackInfo(callback, stateForCallback, targetSyncContext, executionContext, this); //allocate the callback list array if (m_registeredCallbacksLists == null) { SparselyPopulatedArray <CancellationCallbackInfo>[] list = new SparselyPopulatedArray <CancellationCallbackInfo> [s_nLists]; Interlocked.CompareExchange(ref m_registeredCallbacksLists, list, null); } //allocate the actual lists on-demand to save mem in low-use situations, and to avoid false-sharing. if (m_registeredCallbacksLists[myIndex] == null) { SparselyPopulatedArray <CancellationCallbackInfo> callBackArray = new SparselyPopulatedArray <CancellationCallbackInfo>(4); Interlocked.CompareExchange(ref (m_registeredCallbacksLists[myIndex]), callBackArray, null); } // Now add the registration to the list. SparselyPopulatedArray <CancellationCallbackInfo> callbacks = m_registeredCallbacksLists[myIndex]; SparselyPopulatedArrayAddInfo <CancellationCallbackInfo> addInfo = callbacks.Add(callbackInfo); CancellationTokenRegistration registration = new CancellationTokenRegistration(this, callbackInfo, addInfo); if (!IsCancellationRequested) { return(registration); } //If a cancellation has since come in, we will try to undo the registration and run the callback directly here. bool deregisterOccurred = registration.TryDeregister(); if (!deregisterOccurred) { // the callback execution process must have snagged the callback for execution, so // 1. wait for the callback to complete, then // 2. return a dummy registration. WaitForCallbackToComplete(callbackInfo); return(new CancellationTokenRegistration()); } } // If cancellation already occurred, we run the callback on this thread and return an empty registration. callback(stateForCallback); return(new CancellationTokenRegistration()); }
internal CancellationTokenRegistration InternalRegister(Action <object> callback, object stateForCallback, SynchronizationContext targetSyncContext, ExecutionContext executionContext) { this.ThrowIfDisposed(); if (!this.IsCancellationRequested) { int index = Thread.CurrentThread.ManagedThreadId % s_nLists; CancellationCallbackInfo element = new CancellationCallbackInfo(callback, stateForCallback, targetSyncContext, executionContext, this); if (this.m_registeredCallbacksLists == null) { SparselyPopulatedArray <CancellationCallbackInfo>[] arrayArray = new SparselyPopulatedArray <CancellationCallbackInfo> [s_nLists]; Interlocked.CompareExchange <SparselyPopulatedArray <CancellationCallbackInfo>[]>(ref this.m_registeredCallbacksLists, arrayArray, null); } if (this.m_registeredCallbacksLists[index] == null) { SparselyPopulatedArray <CancellationCallbackInfo> array = new SparselyPopulatedArray <CancellationCallbackInfo>(4); Interlocked.CompareExchange <SparselyPopulatedArray <CancellationCallbackInfo> >(ref this.m_registeredCallbacksLists[index], array, null); } SparselyPopulatedArrayAddInfo <CancellationCallbackInfo> registrationInfo = this.m_registeredCallbacksLists[index].Add(element); CancellationTokenRegistration registration = new CancellationTokenRegistration(this, element, registrationInfo); if (!this.IsCancellationRequested) { return(registration); } if (!registration.TryDeregister()) { this.WaitForCallbackToComplete(element); return(new CancellationTokenRegistration()); } } callback(stateForCallback); return(new CancellationTokenRegistration()); }
// Token: 0x06003E40 RID: 15936 RVA: 0x000E71FC File Offset: 0x000E53FC internal CancellationTokenRegistration InternalRegister(Action <object> callback, object stateForCallback, SynchronizationContext targetSyncContext, ExecutionContext executionContext) { if (AppContextSwitches.ThrowExceptionIfDisposedCancellationTokenSource) { this.ThrowIfDisposed(); } if (!this.IsCancellationRequested) { if (this.m_disposed && !AppContextSwitches.ThrowExceptionIfDisposedCancellationTokenSource) { return(default(CancellationTokenRegistration)); } int num = Thread.CurrentThread.ManagedThreadId % CancellationTokenSource.s_nLists; CancellationCallbackInfo cancellationCallbackInfo = new CancellationCallbackInfo(callback, stateForCallback, targetSyncContext, executionContext, this); SparselyPopulatedArray <CancellationCallbackInfo>[] array = this.m_registeredCallbacksLists; if (array == null) { SparselyPopulatedArray <CancellationCallbackInfo>[] array2 = new SparselyPopulatedArray <CancellationCallbackInfo> [CancellationTokenSource.s_nLists]; array = Interlocked.CompareExchange <SparselyPopulatedArray <CancellationCallbackInfo>[]>(ref this.m_registeredCallbacksLists, array2, null); if (array == null) { array = array2; } } SparselyPopulatedArray <CancellationCallbackInfo> sparselyPopulatedArray = Volatile.Read <SparselyPopulatedArray <CancellationCallbackInfo> >(ref array[num]); if (sparselyPopulatedArray == null) { SparselyPopulatedArray <CancellationCallbackInfo> value = new SparselyPopulatedArray <CancellationCallbackInfo>(4); Interlocked.CompareExchange <SparselyPopulatedArray <CancellationCallbackInfo> >(ref array[num], value, null); sparselyPopulatedArray = array[num]; } SparselyPopulatedArrayAddInfo <CancellationCallbackInfo> registrationInfo = sparselyPopulatedArray.Add(cancellationCallbackInfo); CancellationTokenRegistration result = new CancellationTokenRegistration(cancellationCallbackInfo, registrationInfo); if (!this.IsCancellationRequested) { return(result); } if (!result.TryDeregister()) { return(result); } } callback(stateForCallback); return(default(CancellationTokenRegistration)); }
internal CancellationTokenRegistration InternalRegister(Action <object> callback, object stateForCallback, SynchronizationContext targetSyncContext, ExecutionContext executionContext) { if (AppContextSwitches.ThrowExceptionIfDisposedCancellationTokenSource) { this.ThrowIfDisposed(); } if (!this.IsCancellationRequested) { if (this.m_disposed && !AppContextSwitches.ThrowExceptionIfDisposedCancellationTokenSource) { return(new CancellationTokenRegistration()); } int index = Thread.CurrentThread.ManagedThreadId % CancellationTokenSource.s_nLists; CancellationCallbackInfo cancellationCallbackInfo = new CancellationCallbackInfo(callback, stateForCallback, targetSyncContext, executionContext, this); SparselyPopulatedArray <CancellationCallbackInfo>[] sparselyPopulatedArrayArray1 = this.m_registeredCallbacksLists; if (sparselyPopulatedArrayArray1 == null) { SparselyPopulatedArray <CancellationCallbackInfo>[] sparselyPopulatedArrayArray2 = new SparselyPopulatedArray <CancellationCallbackInfo> [CancellationTokenSource.s_nLists]; sparselyPopulatedArrayArray1 = Interlocked.CompareExchange <SparselyPopulatedArray <CancellationCallbackInfo>[]>(ref this.m_registeredCallbacksLists, sparselyPopulatedArrayArray2, (SparselyPopulatedArray <CancellationCallbackInfo>[])null) ?? sparselyPopulatedArrayArray2; } SparselyPopulatedArray <CancellationCallbackInfo> sparselyPopulatedArray1 = Volatile.Read <SparselyPopulatedArray <CancellationCallbackInfo> >(ref sparselyPopulatedArrayArray1[index]); if (sparselyPopulatedArray1 == null) { SparselyPopulatedArray <CancellationCallbackInfo> sparselyPopulatedArray2 = new SparselyPopulatedArray <CancellationCallbackInfo>(4); Interlocked.CompareExchange <SparselyPopulatedArray <CancellationCallbackInfo> >(ref sparselyPopulatedArrayArray1[index], sparselyPopulatedArray2, (SparselyPopulatedArray <CancellationCallbackInfo>)null); sparselyPopulatedArray1 = sparselyPopulatedArrayArray1[index]; } SparselyPopulatedArrayAddInfo <CancellationCallbackInfo> registrationInfo = sparselyPopulatedArray1.Add(cancellationCallbackInfo); CancellationTokenRegistration tokenRegistration = new CancellationTokenRegistration(cancellationCallbackInfo, registrationInfo); if (!this.IsCancellationRequested || !tokenRegistration.TryDeregister()) { return(tokenRegistration); } } callback(stateForCallback); return(new CancellationTokenRegistration()); }
private void ExecuteCallbackHandlers(bool throwOnFirstException) { List <Exception> exceptionList = (List <Exception>)null; SparselyPopulatedArray <CancellationCallbackInfo>[] sparselyPopulatedArrayArray = this.m_registeredCallbacksLists; if (sparselyPopulatedArrayArray == null) { Interlocked.Exchange(ref this.m_state, 3); } else { try { for (int index = 0; index < sparselyPopulatedArrayArray.Length; ++index) { SparselyPopulatedArray <CancellationCallbackInfo> sparselyPopulatedArray = Volatile.Read <SparselyPopulatedArray <CancellationCallbackInfo> >(ref sparselyPopulatedArrayArray[index]); if (sparselyPopulatedArray != null) { for (SparselyPopulatedArrayFragment <CancellationCallbackInfo> currArrayFragment = sparselyPopulatedArray.Tail; currArrayFragment != null; currArrayFragment = currArrayFragment.Prev) { for (int currArrayIndex = currArrayFragment.Length - 1; currArrayIndex >= 0; --currArrayIndex) { this.m_executingCallback = currArrayFragment[currArrayIndex]; if (this.m_executingCallback != null) { CancellationCallbackCoreWorkArguments args = new CancellationCallbackCoreWorkArguments(currArrayFragment, currArrayIndex); try { if (this.m_executingCallback.TargetSyncContext != null) { this.m_executingCallback.TargetSyncContext.Send(new SendOrPostCallback(this.CancellationCallbackCoreWork_OnSyncContext), (object)args); this.ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId; } else { this.CancellationCallbackCoreWork(args); } } catch (Exception ex) { if (throwOnFirstException) { throw; } else { if (exceptionList == null) { exceptionList = new List <Exception>(); } exceptionList.Add(ex); } } } } } } } } finally { this.m_state = 3; this.m_executingCallback = (CancellationCallbackInfo)null; Thread.MemoryBarrier(); } if (exceptionList != null) { throw new AggregateException((IEnumerable <Exception>)exceptionList); } } }
/// <summary> /// Invoke the Canceled event. /// </summary> /// <remarks> /// The handlers are invoked synchronously in LIFO order. /// </remarks> private void ExecuteCallbackHandlers(bool throwOnFirstException) { Contract.Assert(IsCancellationRequested, "ExecuteCallbackHandlers should only be called after setting IsCancellationRequested->true"); Contract.Assert(ThreadIDExecutingCallbacks != -1, "ThreadIDExecutingCallbacks should have been set."); // Design decision: call the delegates in LIFO order so that callbacks fire 'deepest first'. // This is intended to help with nesting scenarios so that child enlisters cancel before their parents. List <Exception> exceptionList = null; SparselyPopulatedArray <CancellationCallbackInfo>[] callbackLists = m_registeredCallbacksLists; // If there are no callbacks to run, we can safely exit. Any races to lazy initialize it // will see IsCancellationRequested and will then run the callback themselves. if (callbackLists == null) { Interlocked.Exchange(ref m_state, NOTIFYINGCOMPLETE); return; } try { for (int index = 0; index < callbackLists.Length; index++) { SparselyPopulatedArray <CancellationCallbackInfo> list = callbackLists[index]; if (list != null) { SparselyPopulatedArrayFragment <CancellationCallbackInfo> currArrayFragment = list.Tail; while (currArrayFragment != null) { for (int i = currArrayFragment.Length - 1; i >= 0; i--) { // 1a. publish the indended callback, to ensure ctr.Dipose can tell if a wait is necessary. // 1b. transition to the target syncContext and continue there.. // On the target SyncContext. // 2. actually remove the callback // 3. execute the callback // re:#2 we do the remove on the syncCtx so that we can be sure we have control of the syncCtx before // grabbing the callback. This prevents a deadlock if ctr.Dispose() might run on the syncCtx too. m_executingCallback = currArrayFragment[i]; if (m_executingCallback != null) { //Transition to the target sync context (if necessary), and continue our work there. CancellationCallbackCoreWorkArguments args = new CancellationCallbackCoreWorkArguments(currArrayFragment, i); // marshal exceptions: either aggregate or perform an immediate rethrow // We assume that syncCtx.Send() has forwarded on user exceptions when appropriate. try { if (m_executingCallback.TargetSyncContext != null) { m_executingCallback.TargetSyncContext.Send(CancellationCallbackCoreWork_OnSyncContext, args); // CancellationCallbackCoreWork_OnSyncContext may have altered ThreadIDExecutingCallbacks, so reset it. ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId; } else { CancellationCallbackCoreWork_OnSyncContext(args); } } catch (Exception ex) { if (throwOnFirstException) { throw; } // Otherwise, log it and proceed. if (exceptionList == null) { exceptionList = new List <Exception>(); } exceptionList.Add(ex); } } } currArrayFragment = currArrayFragment.Prev; } } } } finally { m_state = NOTIFYINGCOMPLETE; m_executingCallback = null; Thread.MemoryBarrier(); // for safety, prevent reorderings crossing this point and seeing inconsistent state. } if (exceptionList != null) { Contract.Assert(exceptionList.Count > 0, "Expected exception count > 0"); throw new AggregateException(exceptionList); } }
private void ExecuteCallbackHandlers(bool throwOnFirstException) { List <Exception> list = null; SparselyPopulatedArray <CancellationCallbackInfo>[] registeredCallbacksLists = this.m_registeredCallbacksLists; if (registeredCallbacksLists == null) { Interlocked.Exchange(ref this.m_state, 3); return; } try { for (int i = 0; i < registeredCallbacksLists.Length; i++) { SparselyPopulatedArray <CancellationCallbackInfo> sparselyPopulatedArray = Volatile.Read <SparselyPopulatedArray <CancellationCallbackInfo> >(ref registeredCallbacksLists[i]); if (sparselyPopulatedArray != null) { for (SparselyPopulatedArrayFragment <CancellationCallbackInfo> sparselyPopulatedArrayFragment = sparselyPopulatedArray.Tail; sparselyPopulatedArrayFragment != null; sparselyPopulatedArrayFragment = sparselyPopulatedArrayFragment.Prev) { for (int j = sparselyPopulatedArrayFragment.Length - 1; j >= 0; j--) { this.m_executingCallback = sparselyPopulatedArrayFragment[j]; if (this.m_executingCallback != null) { CancellationCallbackCoreWorkArguments cancellationCallbackCoreWorkArguments = new CancellationCallbackCoreWorkArguments(sparselyPopulatedArrayFragment, j); try { if (this.m_executingCallback.TargetSyncContext != null) { this.m_executingCallback.TargetSyncContext.Send(new SendOrPostCallback(this.CancellationCallbackCoreWork_OnSyncContext), cancellationCallbackCoreWorkArguments); this.ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId; } else { this.CancellationCallbackCoreWork(cancellationCallbackCoreWorkArguments); } } catch (Exception item) { if (throwOnFirstException) { throw; } if (list == null) { list = new List <Exception>(); } list.Add(item); } } } } } } } finally { this.m_state = 3; this.m_executingCallback = null; Thread.MemoryBarrier(); } if (list != null) { throw new AggregateException(list); } }
private void ExecuteCallbackHandlers(bool throwOnFirstException) { List <Exception> innerExceptions = null; SparselyPopulatedArray <CancellationCallbackInfo>[] registeredCallbacksLists = this.m_registeredCallbacksLists; if (registeredCallbacksLists == null) { Interlocked.Exchange(ref this.m_state, 3); } else { try { for (int i = 0; i < registeredCallbacksLists.Length; i++) { SparselyPopulatedArray <CancellationCallbackInfo> array = registeredCallbacksLists[i]; if (array != null) { for (SparselyPopulatedArrayFragment <CancellationCallbackInfo> fragment = array.Tail; fragment != null; fragment = fragment.Prev) { for (int j = fragment.Length - 1; j >= 0; j--) { this.m_executingCallback = fragment[j]; if (this.m_executingCallback != null) { CancellationCallbackCoreWorkArguments state = new CancellationCallbackCoreWorkArguments(fragment, j); try { if (this.m_executingCallback.TargetSyncContext != null) { this.m_executingCallback.TargetSyncContext.Send(new SendOrPostCallback(this.CancellationCallbackCoreWork_OnSyncContext), state); this.ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId; } else { this.CancellationCallbackCoreWork_OnSyncContext(state); } } catch (Exception exception) { if (throwOnFirstException) { throw; } if (innerExceptions == null) { innerExceptions = new List <Exception>(); } innerExceptions.Add(exception); } } } } } } } finally { this.m_state = 3; this.m_executingCallback = null; Thread.MemoryBarrier(); } if (innerExceptions != null) { throw new AggregateException(innerExceptions); } } }