private void CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args) { CancellationCallbackInfo cancellationCallbackInfo = args.m_currArrayFragment.SafeAtomicRemove(args.m_currArrayIndex, this.m_executingCallback); if (cancellationCallbackInfo == this.m_executingCallback) { if (cancellationCallbackInfo.TargetExecutionContext != null) { cancellationCallbackInfo.CancellationTokenSource.ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId; } cancellationCallbackInfo.ExecuteCallback(); } }
private void CancellationCallbackCoreWork_OnSyncContext(object obj) { CancellationCallbackCoreWorkArguments arguments = (CancellationCallbackCoreWorkArguments)obj; CancellationCallbackInfo info = arguments.m_currArrayFragment.SafeAtomicRemove(arguments.m_currArrayIndex, this.m_executingCallback); if (info == this.m_executingCallback) { if (info.TargetExecutionContext != null) { info.CancellationTokenSource.ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId; } info.ExecuteCallback(); } }
// The main callback work that executes on the target synchronization context private void CancellationCallbackCoreWork_OnSyncContext(object obj) { CancellationCallbackCoreWorkArguments args = (CancellationCallbackCoreWorkArguments)obj; // now remove the intended callback..and ensure that it worked. // otherwise the callback has disappeared in the interim and we can immediately return. CancellationCallbackInfo callback = args.m_currArrayFragment.SafeAtomicRemove(args.m_currArrayIndex, m_executingCallback); if (callback == m_executingCallback) { if (callback.TargetExecutionContext != null) { // we are running via a custom sync context, so update the executing threadID callback.CancellationTokenSource.ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId; } callback.ExecuteCallback(); } }
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); } } }
private void CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args) { CancellationCallbackInfo cancellationCallbackInfo = args.m_currArrayFragment.SafeAtomicRemove(args.m_currArrayIndex, this.m_executingCallback); if (cancellationCallbackInfo == this.m_executingCallback) { if (cancellationCallbackInfo.TargetExecutionContext != null) { cancellationCallbackInfo.CancellationTokenSource.ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId; } cancellationCallbackInfo.ExecuteCallback(); } }
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); } } }