internal SparselyPopulatedArrayAddInfo(SparselyPopulatedArrayFragment <T> source, int index) { Contract.Assert(source != null); Contract.Assert(index >= 0 && index < source.Length); m_source = source; m_index = index; }
// Token: 0x06003E4F RID: 15951 RVA: 0x000E7788 File Offset: 0x000E5988 internal SparselyPopulatedArrayAddInfo <T> Add(T element) { SparselyPopulatedArrayFragment <T> sparselyPopulatedArrayFragment2; int num2; for (;;) { SparselyPopulatedArrayFragment <T> sparselyPopulatedArrayFragment = this.m_tail; while (sparselyPopulatedArrayFragment.m_next != null) { sparselyPopulatedArrayFragment = (this.m_tail = sparselyPopulatedArrayFragment.m_next); } for (sparselyPopulatedArrayFragment2 = sparselyPopulatedArrayFragment; sparselyPopulatedArrayFragment2 != null; sparselyPopulatedArrayFragment2 = sparselyPopulatedArrayFragment2.m_prev) { if (sparselyPopulatedArrayFragment2.m_freeCount < 1) { sparselyPopulatedArrayFragment2.m_freeCount--; } if (sparselyPopulatedArrayFragment2.m_freeCount > 0 || sparselyPopulatedArrayFragment2.m_freeCount < -10) { int length = sparselyPopulatedArrayFragment2.Length; int num = (length - sparselyPopulatedArrayFragment2.m_freeCount) % length; if (num < 0) { num = 0; sparselyPopulatedArrayFragment2.m_freeCount--; } for (int i = 0; i < length; i++) { num2 = (num + i) % length; if (sparselyPopulatedArrayFragment2.m_elements[num2] == null && Interlocked.CompareExchange <T>(ref sparselyPopulatedArrayFragment2.m_elements[num2], element, default(T)) == null) { goto Block_5; } } } } SparselyPopulatedArrayFragment <T> sparselyPopulatedArrayFragment3 = new SparselyPopulatedArrayFragment <T>((sparselyPopulatedArrayFragment.m_elements.Length == 4096) ? 4096 : (sparselyPopulatedArrayFragment.m_elements.Length * 2), sparselyPopulatedArrayFragment); if (Interlocked.CompareExchange <SparselyPopulatedArrayFragment <T> >(ref sparselyPopulatedArrayFragment.m_next, sparselyPopulatedArrayFragment3, null) == null) { this.m_tail = sparselyPopulatedArrayFragment3; } } Block_5: int num3 = sparselyPopulatedArrayFragment2.m_freeCount - 1; sparselyPopulatedArrayFragment2.m_freeCount = ((num3 > 0) ? num3 : 0); return(new SparselyPopulatedArrayAddInfo <T>(sparselyPopulatedArrayFragment2, num2)); }
internal SparselyPopulatedArrayAddInfo <T> Add(T element) { while (true) { SparselyPopulatedArrayFragment <T> tail = this.m_tail; while (tail.m_next != null) { this.m_tail = tail = tail.m_next; } for (SparselyPopulatedArrayFragment <T> fragment2 = tail; fragment2 != null; fragment2 = fragment2.m_prev) { if (fragment2.m_freeCount < 1) { fragment2.m_freeCount--; } if ((fragment2.m_freeCount > 0) || (fragment2.m_freeCount < -10)) { int length = fragment2.Length; int num2 = (length - fragment2.m_freeCount) % length; if (num2 < 0) { num2 = 0; fragment2.m_freeCount--; } for (int i = 0; i < length; i++) { int index = (num2 + i) % length; if (fragment2.m_elements[index] == null) { T comparand = default(T); if (Interlocked.CompareExchange <T>(ref fragment2.m_elements[index], element, comparand) == null) { int num5 = fragment2.m_freeCount - 1; fragment2.m_freeCount = (num5 > 0) ? num5 : 0; return(new SparselyPopulatedArrayAddInfo <T>(fragment2, index)); } } } } } SparselyPopulatedArrayFragment <T> fragment3 = new SparselyPopulatedArrayFragment <T>((tail.m_elements.Length == 0x1000) ? 0x1000 : (tail.m_elements.Length * 2), tail); if (Interlocked.CompareExchange <SparselyPopulatedArrayFragment <T> >(ref tail.m_next, fragment3, null) == null) { this.m_tail = fragment3; } } }
public bool Equals(CancellationTokenRegistration other) { if (this.m_callbackInfo == other.m_callbackInfo) { SparselyPopulatedArrayFragment <CancellationCallbackInfo> source1 = this.m_registrationInfo.Source; SparselyPopulatedArrayAddInfo <CancellationCallbackInfo> populatedArrayAddInfo = other.m_registrationInfo; SparselyPopulatedArrayFragment <CancellationCallbackInfo> source2 = populatedArrayAddInfo.Source; if (source1 == source2) { populatedArrayAddInfo = this.m_registrationInfo; int index1 = populatedArrayAddInfo.Index; populatedArrayAddInfo = other.m_registrationInfo; int index2 = populatedArrayAddInfo.Index; return(index1 == index2); } } return(false); }
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); } } }
internal SparselyPopulatedArrayAddInfo(SparselyPopulatedArrayFragment <T> source, int index) { this.m_source = source; this.m_index = index; }
internal SparselyPopulatedArrayFragment(int size, SparselyPopulatedArrayFragment <T> prev) { m_elements = new T[size]; m_freeCount = size; m_prev = prev; }
/// <summary> /// Adds an element in the first available slot, beginning the search from the tail-to-head. /// If no slots are available, the array is grown. The method doesn't return until successful. /// </summary> /// <param name="element">The element to add.</param> /// <returns>Information about where the add happened, to enable O(1) deregistration.</returns> internal SparselyPopulatedArrayAddInfo <T> Add(T element) { while (true) { // Get the tail, and ensure it's up to date. SparselyPopulatedArrayFragment <T> tail = m_tail; while (tail.m_next != null) { m_tail = (tail = tail.m_next); } // Search for a free index, starting from the tail. SparselyPopulatedArrayFragment <T> curr = tail; while (curr != null) { const int RE_SEARCH_THRESHOLD = -10; // Every 10 skips, force a search. if (curr.m_freeCount < 1) { --curr.m_freeCount; } if (curr.m_freeCount > 0 || curr.m_freeCount < RE_SEARCH_THRESHOLD) { int c = curr.Length; // We'll compute a start offset based on how many free slots we think there // are. This optimizes for ordinary the LIFO deregistration pattern, and is // far from perfect due to the non-threadsafe ++ and -- of the free counter. int start = ((c - curr.m_freeCount) % c); if (start < 0) { start = 0; curr.m_freeCount--; // Too many free elements; fix up. } Contract.Assert(start >= 0 && start < c, "start is outside of bounds"); // Now walk the array until we find a free slot (or reach the end). for (int i = 0; i < c; i++) { // If the slot is null, try to CAS our element into it. int tryIndex = (start + i) % c; Contract.Assert(tryIndex >= 0 && tryIndex < curr.m_elements.Length, "tryIndex is outside of bounds"); if (curr.m_elements[tryIndex] == null && Interlocked.CompareExchange(ref curr.m_elements[tryIndex], element, null) == null) { // We adjust the free count by --. Note: if this drops to 0, we will skip // the fragment on the next search iteration. Searching threads will -- the // count and force a search every so often, just in case fragmentation occurs. int newFreeCount = curr.m_freeCount - 1; curr.m_freeCount = newFreeCount > 0 ? newFreeCount : 0; return(new SparselyPopulatedArrayAddInfo <T>(curr, tryIndex)); } } } curr = curr.m_prev; } // If we got here, we need to add a new chunk to the tail and try again. SparselyPopulatedArrayFragment <T> newTail = new SparselyPopulatedArrayFragment <T>( tail.m_elements.Length == 4096 ? 4096 : tail.m_elements.Length * 2, tail); if (Interlocked.CompareExchange(ref tail.m_next, newTail, null) == null) { m_tail = newTail; } } }
/// <summary> /// Allocates a new array with the given initial size. /// </summary> /// <param name="initialSize">How many array slots to pre-allocate.</param> internal SparselyPopulatedArray(int initialSize) { m_head = m_tail = new SparselyPopulatedArrayFragment <T>(initialSize); }
public CancellationCallbackCoreWorkArguments(SparselyPopulatedArrayFragment <CancellationCallbackInfo> currArrayFragment, int currArrayIndex) { m_currArrayFragment = currArrayFragment; m_currArrayIndex = currArrayIndex; }
/// <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); } } }