Esempio n. 1
0
        public bool Unregister(WaitHandle waitObject)
        {
            // Hold the lock during the synchronous part of Unregister (as in CoreCLR)
            using (LockHolder.Hold(_lock))
            {
                if (!_unregistering)
                {
                    // Ensure callbacks will not call SetThreadpoolWait anymore
                    _unregistering = true;

                    // Cease queueing more callbacks
                    Interop.Kernel32.SetThreadpoolWait(_tpWait, IntPtr.Zero, IntPtr.Zero);

                    // Should we wait for callbacks synchronously? Note that we treat the zero handle as the asynchronous case.
                    SafeWaitHandle safeWaitHandle = waitObject?.SafeWaitHandle;
                    bool           blocking       = ((safeWaitHandle != null) && (safeWaitHandle.DangerousGetHandle() == new IntPtr(-1)));

                    if (blocking)
                    {
                        FinishUnregistering();
                    }
                    else
                    {
                        // Wait for callbacks and dispose resources asynchronously
                        ThreadPool.QueueUserWorkItem(FinishUnregisteringAsync, safeWaitHandle);
                    }

                    return(true);
                }
            }
            return(false);
        }
Esempio n. 2
0
        internal bool Change(uint dueTime, uint period)
        {
            bool success;

            using (LockHolder.Hold(TimerQueue.Instance.Lock))
            {
                if (_canceled)
                {
                    throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic);
                }

                m_period = period;

                if (dueTime == Timeout.UnsignedInfinite)
                {
                    TimerQueue.Instance.DeleteTimer(this);
                    success = true;
                }
                else
                {
                    success = TimerQueue.Instance.UpdateTimer(this, dueTime, period);
                }
            }

            return(success);
        }
Esempio n. 3
0
        public bool Close(WaitHandle toSignal)
        {
            bool success;
            bool shouldSignal = false;

            using (LockHolder.Hold(TimerQueue.Instance.Lock))
            {
                if (_canceled)
                {
                    success = false;
                }
                else
                {
                    _canceled = true;
                    _notifyWhenNoCallbacksRunning = toSignal;
                    TimerQueue.Instance.DeleteTimer(this);

                    if (_callbacksRunning == 0)
                    {
                        shouldSignal = true;
                    }

                    success = true;
                }
            }

            if (shouldSignal)
            {
                SignalNoCallbacksRunning();
            }

            return(success);
        }
Esempio n. 4
0
        /// <summary>
        /// Resizes a table to a certain length (or larger).
        /// </summary>
        private void GrowTable(ref LinkedSlotVolatile[] table, int minLength)
        {
            Debug.Assert(table.Length < minLength);

            // Determine the size of the new table and allocate it.
            int newLen = GetNewTableSize(minLength);

            LinkedSlotVolatile[] newTable = new LinkedSlotVolatile[newLen];

            //
            // The lock is necessary to avoid a race with ThreadLocal.Dispose. GrowTable has to point all
            // LinkedSlot instances referenced in the old table to reference the new table. Without locking,
            // Dispose could use a stale SlotArray reference and clear out a slot in the old array only, while
            // the value continues to be referenced from the new (larger) array.
            //
            using (LockHolder.Hold(s_idManager.m_lock))
            {
                for (int i = 0; i < table.Length; i++)
                {
                    LinkedSlot linkedSlot = table[i].Value;
                    if (linkedSlot != null && linkedSlot.SlotArray != null)
                    {
                        linkedSlot.SlotArray = newTable;
                        newTable[i]          = table[i];
                    }
                }
            }

            table = newTable;
        }
Esempio n. 5
0
            internal int GetId()
            {
                using (LockHolder.Hold(m_lock))
                {
                    int availableId = m_nextIdToTry;
                    while (availableId < m_freeIds.Count)
                    {
                        if (m_freeIds[availableId])
                        {
                            break;
                        }
                        availableId++;
                    }

                    if (availableId == m_freeIds.Count)
                    {
                        m_freeIds.Add(false);
                    }
                    else
                    {
                        m_freeIds[availableId] = false;
                    }

                    m_nextIdToTry = availableId + 1;

                    return(availableId);
                }
            }
Esempio n. 6
0
            internal int Add(T e)
            {
                while (true)
                {
                    T[] array = m_array;
                    using (LockHolder.Hold(m_lock))
                    {
                        for (int i = 0; i < array.Length; i++)
                        {
                            if (array[i] == null)
                            {
                                Volatile.Write(ref array[i], e);
                                return(i);
                            }
                            else if (i == array.Length - 1)
                            {
                                // Must resize. If we raced and lost, we start over again.
                                if (array != m_array)
                                {
                                    continue;
                                }

                                T[] newArray = new T[array.Length * 2];
                                Array.Copy(array, newArray, i + 1);
                                newArray[i + 1] = e;
                                m_array         = newArray;
                                return(i + 1);
                            }
                        }
                    }
                }
            }
        /// <summary>
        /// Scans the table and frees all dead entries without adding them to the free entry list.
        /// Runs on the finalizer thread.
        /// </summary>
        private static void FreeDeadEntries()
        {
            // Be cautious as this method may run in parallel with grabbing a free entry in the
            // AssignEntry method.  The potential race is checking IsAllocated && (Target == null)
            // while a new non-zero (allocated) GCHandle is being assigned to the Owner field
            // containing a zero (non-allocated) GCHandle.  That must be safe as a GCHandle is
            // just an IntPtr, which is assigned atomically, and Target has load dependency on it.
            using (LockHolder.Hold(s_usedEntriesLock))
            {
                // We do not care if the s_unusedEntryIndex value is stale here; it suffices that
                // the s_entries reference is locked and s_unusedEntryIndex points within that array.
                Debug.Assert(s_unusedEntryIndex <= s_entries.Length);

                for (int idx = s_unusedEntryIndex; --idx > 0;)
                {
                    bool allocated = s_entries[idx].Owner.IsAllocated;
                    if (allocated && (s_entries[idx].Owner.Target == null))
                    {
                        s_entries[idx].Lock = null;
                        s_entries[idx].Next = 0;
                        s_entries[idx].Owner.Free();
                    }
                }
            }
        }
        /// <summary>
        /// Scans the table and recycles all dead and freed entries adding them to the free entry
        /// list.  Returns the number of recycled entries.
        /// </summary>
        private static int RecycleDeadEntries()
        {
            Debug.Assert(s_freeEntriesLock.IsAcquired);

            using (LockHolder.Hold(s_usedEntriesLock))
            {
                int recycledEntries = 0;
                for (int idx = s_unusedEntryIndex; --idx > 0;)
                {
                    bool freed = !s_entries[idx].Owner.IsAllocated;
                    if (freed || (s_entries[idx].Owner.Target == null))
                    {
                        s_entries[idx].Lock = null;
                        s_entries[idx].Next = s_freeEntryList;
                        if (!freed)
                        {
                            s_entries[idx].Owner.Free();
                        }
                        s_freeEntryList = idx;
                        recycledEntries++;
                    }
                }
                return(recycledEntries);
            }
        }
        public bool TrySetApartmentStateUnchecked(ApartmentState state)
        {
            if (this != CurrentThread)
            {
                using (LockHolder.Hold(_lock))
                {
                    if (HasStarted())
                    {
                        throw new ThreadStateException();
                    }
                    _initialApartmentState = state;
                    return(true);
                }
            }

            if ((t_comState & ComState.Locked) == 0)
            {
                if (state != ApartmentState.Unknown)
                {
                    InitializeCom(state);
                }
                else
                {
                    UninitializeCom();
                }
            }

            // Clear the cache and check whether new state matches the desired state
            t_apartmentType = ApartmentType.Unknown;
            return(state == GetApartmentState());
        }
Esempio n. 10
0
File: Timer.cs Progetto: z1c0/corert
        public ValueTask CloseAsync()
        {
            using (LockHolder.Hold(TimerQueue.Instance.Lock))
            {
                object notifyWhenNoCallbacksRunning = _notifyWhenNoCallbacksRunning;

                // Mark the timer as canceled if it's not already.
                if (_canceled)
                {
                    if (notifyWhenNoCallbacksRunning is WaitHandle)
                    {
                        // A previous call to Close(WaitHandle) stored a WaitHandle.  We could try to deal with
                        // this case by using ThreadPool.RegisterWaitForSingleObject to create a Task that'll
                        // complete when the WaitHandle is set, but since arbitrary WaitHandle's can be supplied
                        // by the caller, it could be for an auto-reset event or similar where that caller's
                        // WaitOne on the WaitHandle could prevent this wrapper Task from completing.  We could also
                        // change the implementation to support storing multiple objects, but that's not pay-for-play,
                        // and the existing Close(WaitHandle) already discounts this as being invalid, instead just
                        // returning false if you use it multiple times. Since first calling Timer.Dispose(WaitHandle)
                        // and then calling Timer.DisposeAsync is not something anyone is likely to or should do, we
                        // simplify by just failing in that case.
                        return(new ValueTask(Task.FromException(new InvalidOperationException(SR.InvalidOperation_TimerAlreadyClosed))));
                    }
                }
                else
                {
                    _canceled = true;
                    TimerQueue.Instance.DeleteTimer(this);
                }

                // We've deleted the timer, so if there are no callbacks queued or running,
                // we're done and return an already-completed value task.
                if (_callbacksRunning == 0)
                {
                    return(default);
Esempio n. 11
0
        private static void CancellationTokenCanceledEventHandler(object obj)
        {
            SemaphoreSlim semaphore = obj as SemaphoreSlim;

            Debug.Assert(semaphore != null, "Expected a SemaphoreSlim");
            using (LockHolder.Hold(semaphore.m_lock))
            {
                semaphore.m_condition.SignalAll(); //wake up all waiters.
            }
        }
Esempio n. 12
0
        private bool SetApartmentStateUnchecked(ApartmentState state, bool throwOnError)
        {
            ApartmentState retState;

            if (this != CurrentThread)
            {
                using (LockHolder.Hold(_lock))
                {
                    if (HasStarted())
                    {
                        throw new ThreadStateException();
                    }

                    // Compat: Disallow resetting the initial apartment state
                    if (_initialApartmentState == ApartmentState.Unknown)
                    {
                        _initialApartmentState = state;
                    }

                    retState = _initialApartmentState;
                }
            }
            else
            {
                if ((t_comState & ComState.Locked) == 0)
                {
                    if (state != ApartmentState.Unknown)
                    {
                        InitializeCom(state);
                    }
                    else
                    {
                        UninitializeCom();
                    }
                }

                // Clear the cache and check whether new state matches the desired state
                t_apartmentType = ApartmentType.Unknown;

                retState = GetApartmentState();
            }

            if (retState != state)
            {
                if (throwOnError)
                {
                    string msg = SR.Format(SR.Thread_ApartmentState_ChangeFailed, retState);
                    throw new InvalidOperationException(msg);
                }

                return(false);
            }

            return(true);
        }
Esempio n. 13
0
 public void Close()
 {
     using (LockHolder.Hold(TimerQueue.Instance.Lock))
     {
         if (!m_canceled)
         {
             m_canceled = true;
             TimerQueue.Instance.DeleteTimer(this);
         }
     }
 }
Esempio n. 14
0
 // Return an ID to the pool
 internal void ReturnId(int id)
 {
     using (LockHolder.Hold(m_lock))
     {
         m_freeIds[id] = true;
         if (id < m_nextIdToTry)
         {
             m_nextIdToTry = id;
         }
     }
 }
Esempio n. 15
0
        private static void CancellationTokenCallback(object obj)
        {
            ManualResetEventSlim mre = obj as ManualResetEventSlim;

            Debug.Assert(mre != null, "Expected a ManualResetEventSlim");
            Debug.Assert(mre.m_lock != null); //the lock should have been created before this callback is registered for use.
            using (LockHolder.Hold(mre.m_lock))
            {
                mre.m_condition.SignalAll(); // awaken all waiters
            }
        }
Esempio n. 16
0
File: Timer.cs Progetto: rivy/corert
        volatile int m_pauseTicks = 0; // Time when Pause was called

        internal void Pause()
        {
            using (LockHolder.Hold(Lock))
            {
                // Delete the native timer so that no timers are fired in the Pause zone
                if (m_appDomainTimer != null && !m_appDomainTimer.IsInvalid)
                {
                    m_appDomainTimer.Dispose();
                    m_appDomainTimer            = null;
                    m_isAppDomainTimerScheduled = false;
                    m_pauseTicks = TickCount;
                }
            }
        }
Esempio n. 17
0
        /// <summary>
        /// Private helper to actually perform the Set.
        /// </summary>
        /// <param name="duringCancellation">Indicates whether we are calling Set() during cancellation.</param>
        /// <exception cref="T:System.OperationCanceledException">The object has been canceled.</exception>
        private void Set(bool duringCancellation)
        {
            // We need to ensure that IsSet=true does not get reordered past the read of m_eventObj
            // This would be a legal movement according to the .NET memory model.
            // The code is safe as IsSet involves an Interlocked.CompareExchange which provides a full memory barrier.
            IsSet = true;

            // If there are waiting threads, we need to pulse them.
            if (Waiters > 0)
            {
                Debug.Assert(m_lock != null && m_condition != null); //if waiters>0, then m_lock has already been created.
                using (LockHolder.Hold(m_lock))
                {
                    m_condition.SignalAll();
                }
            }

            ManualResetEvent eventObj = m_eventObj;

            //Design-decision: do not set the event if we are in cancellation -> better to deadlock than to wake up waiters incorrectly
            //It would be preferable to wake up the event and have it throw OCE. This requires MRE to implement cancellation logic

            if (eventObj != null && !duringCancellation)
            {
                // We must surround this call to Set in a lock.  The reason is fairly subtle.
                // Sometimes a thread will issue a Wait and wake up after we have set m_state,
                // but before we have gotten around to setting m_eventObj (just below). That's
                // because Wait first checks m_state and will only access the event if absolutely
                // necessary.  However, the coding pattern { event.Wait(); event.Dispose() } is
                // quite common, and we must support it.  If the waiter woke up and disposed of
                // the event object before the setter has finished, however, we would try to set a
                // now-disposed Win32 event.  Crash!  To deal with this race, we use a lock to
                // protect access to the event object when setting and disposing of it.  We also
                // double-check that the event has not become null in the meantime when in the lock.

                lock (eventObj)
                {
                    if (m_eventObj != null)
                    {
                        // If somebody is waiting, we must set the event.
                        m_eventObj.Set();
                    }
                }
            }

#if DEBUG
            m_lastSetTime = Environment.TickCount;
#endif
        }
Esempio n. 18
0
 internal void Remove(T e)
 {
     T[] array = m_array;
     using (LockHolder.Hold(m_lock))
     {
         for (int i = 0; i < m_array.Length; i++)
         {
             if (m_array[i] == e)
             {
                 Volatile.Write(ref m_array[i], null);
                 break;
             }
         }
     }
 }
Esempio n. 19
0
        private void StartInternal(object parameter)
        {
            using (LockHolder.Hold(_lock))
            {
                if (!GetThreadStateBit(ThreadState.Unstarted))
                {
                    throw new ThreadStateException(SR.ThreadState_AlreadyStarted);
                }

                bool     waitingForThreadStart = false;
                GCHandle threadHandle          = GCHandle.Alloc(this);
                _threadStartArg = parameter;

                try
                {
                    if (!CreateThread(threadHandle))
                    {
                        throw new OutOfMemoryException();
                    }

                    // Skip cleanup if any asynchronous exception happens while waiting for the thread start
                    waitingForThreadStart = true;

                    // Wait until the new thread either dies or reports itself as started
                    while (GetThreadStateBit(ThreadState.Unstarted) && !JoinInternal(0))
                    {
                        Yield();
                    }

                    waitingForThreadStart = false;
                }
                finally
                {
                    Debug.Assert(!waitingForThreadStart, "Leaked threadHandle");
                    if (!waitingForThreadStart)
                    {
                        threadHandle.Free();
                        _threadStartArg = null;
                    }
                }

                if (GetThreadStateBit(ThreadState.Unstarted))
                {
                    // Lack of memory is the only expected reason for thread creation failure
                    throw new ThreadStartException(new OutOfMemoryException());
                }
            }
        }
Esempio n. 20
0
File: Timer.cs Progetto: rivy/corert
 public void Close()
 {
     using (LockHolder.Hold(TimerQueue.Instance.Lock))
     {
         // prevent ThreadAbort while updating state
         try { }
         finally
         {
             if (!m_canceled)
             {
                 m_canceled = true;
                 TimerQueue.Instance.DeleteTimer(this);
             }
         }
     }
 }
Esempio n. 21
0
        /// <summary>
        /// Asynchronously waits to enter the <see cref="SemaphoreSlim"/>,
        /// using a 32-bit signed integer to measure the time interval,
        /// while observing a <see cref="T:System.Threading.CancellationToken"/>.
        /// </summary>
        /// <param name="millisecondsTimeout">
        /// The number of milliseconds to wait, or <see cref="Timeout.Infinite"/>(-1) to wait indefinitely.
        /// </param>
        /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken"/> to observe.</param>
        /// <returns>
        /// A task that will complete with a result of true if the current thread successfully entered
        /// the <see cref="SemaphoreSlim"/>, otherwise with a result of false.
        /// </returns>
        /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
        /// disposed.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a negative number other than -1,
        /// which represents an infinite time-out.
        /// </exception>
        public Task <bool> WaitAsync(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            CheckDispose();

            // Validate input
            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException(
                          nameof(millisecondsTimeout), millisecondsTimeout, SR.SemaphoreSlim_Wait_TimeoutWrong);
            }

            // Bail early for cancellation
            if (cancellationToken.IsCancellationRequested)
            {
                return(Task.FromCancellation <bool>(cancellationToken));
            }

            using (LockHolder.Hold(m_lock))
            {
                // If there are counts available, allow this waiter to succeed.
                if (m_currentCount > 0)
                {
                    --m_currentCount;
                    if (m_waitHandle != null && m_currentCount == 0)
                    {
                        m_waitHandle.Reset();
                    }
                    return(s_trueTask);
                }
                else if (millisecondsTimeout == 0)
                {
                    // No counts, if timeout is zero fail fast
                    return(s_falseTask);
                }
                // If there aren't, create and return a task to the caller.
                // The task will be completed either when they've successfully acquired
                // the semaphore or when the timeout expired or cancellation was requested.
                else
                {
                    Debug.Assert(m_currentCount == 0, "m_currentCount should never be negative");
                    var asyncWaiter = CreateAndAddAsyncWaiter();
                    return((millisecondsTimeout == Timeout.Infinite && !cancellationToken.CanBeCanceled) ?
                           asyncWaiter :
                           WaitUntilCountOrTimeoutAsync(asyncWaiter, millisecondsTimeout, cancellationToken));
                }
            }
        }
Esempio n. 22
0
        /// <summary>
        /// Sets the hash code in a thread-safe way.
        /// </summary>
        public static int SetHashCode(int syncIndex, int hashCode)
        {
            Debug.Assert((0 < syncIndex) && (syncIndex < s_unusedEntryIndex));

            // Acquire the lock to ensure we are updating the latest version of s_entries.  This
            // lock may be avoided if we store the hash code and Monitor synchronization data in
            // the same object accessed by a reference.
            using (LockHolder.Hold(s_usedEntriesLock))
            {
                int currentHash = s_entries[syncIndex].HashCode;
                if (currentHash != 0)
                {
                    return(currentHash);
                }
                s_entries[syncIndex].HashCode = hashCode;
                return(hashCode);
            }
        }
Esempio n. 23
0
        /// <summary>
        /// Grows the sync table.  If memory is not available, it throws an OOM exception keeping
        /// the state valid.
        /// </summary>
        private static void Grow()
        {
            Debug.Assert(s_freeEntriesLock.IsAcquired);

            int oldSize = s_entries.Length;
            int newSize = CalculateNewSize(oldSize);

            Entry[] newEntries = new Entry[newSize];

            using (LockHolder.Hold(s_usedEntriesLock))
            {
                // Copy the shallow content of the table
                Array.Copy(s_entries, newEntries, oldSize);

                // Publish the new table.  Lock-free reader threads must not see the new value of
                // s_entries until all the content is copied to the new table.
                Volatile.Write(ref s_entries, newEntries);
            }
        }
Esempio n. 24
0
        /// <summary>Performs the asynchronous wait.</summary>
        /// <param name="millisecondsTimeout">The timeout.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The task to return to the caller.</returns>
        private async Task <bool> WaitUntilCountOrTimeoutAsync(TaskNode asyncWaiter, int millisecondsTimeout, CancellationToken cancellationToken)
        {
            Debug.Assert(asyncWaiter != null, "Waiter should have been constructed");
            Debug.Assert(m_lock.IsAcquired, "Requires the lock be held");

            // Wait until either the task is completed, timeout occurs, or cancellation is requested.
            // We need to ensure that the Task.Delay task is appropriately cleaned up if the await
            // completes due to the asyncWaiter completing, so we use our own token that we can explicitly
            // cancel, and we chain the caller's supplied token into it.
            using (var cts = cancellationToken.CanBeCanceled ?
                             CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default(CancellationToken)) :
                             new CancellationTokenSource())
            {
                var waitCompleted = Task.WhenAny(asyncWaiter, Task.Delay(millisecondsTimeout, cts.Token));
                if (asyncWaiter == await waitCompleted.ConfigureAwait(false))
                {
                    cts.Cancel(); // ensure that the Task.Delay task is cleaned up
                    return(true); // successfully acquired
                }
            }

            // If we get here, the wait has timed out or been canceled.

            // If the await completed synchronously, we still hold the lock.  If it didn't,
            // we no longer hold the lock.  As such, acquire it.
            using (LockHolder.Hold(m_lock))
            {
                // Remove the task from the list.  If we're successful in doing so,
                // we know that no one else has tried to complete this waiter yet,
                // so we can safely cancel or timeout.
                if (RemoveAsyncWaiter(asyncWaiter))
                {
                    cancellationToken.ThrowIfCancellationRequested(); // cancellation occurred
                    return(false);                                    // timeout occurred
                }
            }

            // The waiter had already been removed, which means it's already completed or is about to
            // complete, so let it, and don't return until it does.
            return(await asyncWaiter.ConfigureAwait(false));
        }
Esempio n. 25
0
        /// <summary>
        /// Assigns a sync table entry to the object in a thread-safe way.
        /// </summary>
        public static unsafe int AssignEntry(object obj, int *pHeader)
        {
            // Allocate the synchronization object outside the lock
            Lock lck = new Lock();
            DeadEntryCollector collector = new DeadEntryCollector();
            DependentHandle    handle    = new DependentHandle(obj, collector);

            try
            {
                using (LockHolder.Hold(s_lock))
                {
                    // After acquiring the lock check whether another thread already assigned the sync entry
                    if (ObjectHeader.GetSyncEntryIndex(*pHeader, out int hashOrIndex))
                    {
                        return(hashOrIndex);
                    }

                    int syncIndex;
                    if (s_freeEntryList != 0)
                    {
                        // Grab a free entry from the list
                        syncIndex = s_freeEntryList;

                        ref Entry freeEntry = ref s_entries[syncIndex];
                        s_freeEntryList = freeEntry.Next;
                        freeEntry.Next  = 0;
                    }
                    else
                    {
                        if (s_unusedEntryIndex >= s_entries.Length)
                        {
                            // No free entries, use the slow path.  This call may OOM.
                            Grow();
                        }

                        // Grab the next unused entry
                        Debug.Assert(s_unusedEntryIndex < s_entries.Length);
                        syncIndex = s_unusedEntryIndex++;
                    }

                    ref Entry entry = ref s_entries[syncIndex];
Esempio n. 26
0
        /// <summary>
        /// Releases the resources used by this <see cref="T:System.Threading.ThreadLocal{T}" /> instance.
        /// </summary>
        /// <param name="disposing">
        /// A Boolean value that indicates whether this method is being called due to a call to <see cref="Dispose()"/>.
        /// </param>
        /// <remarks>
        /// Unlike most of the members of <see cref="T:System.Threading.ThreadLocal{T}"/>, this method is not thread-safe.
        /// </remarks>
        protected virtual void Dispose(bool disposing)
        {
            int id;

            using (LockHolder.Hold(s_idManager.m_lock))
            {
                id             = ~m_idComplement;
                m_idComplement = 0;

                if (id < 0 || !m_initialized)
                {
                    Debug.Assert(id >= 0 || !m_initialized, "expected id >= 0 if initialized");

                    // Handle double Dispose calls or disposal of an instance whose constructor threw an exception.
                    return;
                }
                m_initialized = false;

                for (LinkedSlot linkedSlot = m_linkedSlot.Next; linkedSlot != null; linkedSlot = linkedSlot.Next)
                {
                    LinkedSlotVolatile[] slotArray = linkedSlot.SlotArray;

                    if (slotArray == null)
                    {
                        // The thread that owns this slotArray has already finished.
                        continue;
                    }

                    // Remove the reference from the LinkedSlot to the slot table.
                    linkedSlot.SlotArray = null;

                    // And clear the references from the slot table to the linked slot and the value so that
                    // both can get garbage collected.
                    slotArray[id].Value.Value = default(T);
                    slotArray[id].Value       = null;
                }
            }
            m_linkedSlot = null;
            s_idManager.ReturnId(id);
        }
Esempio n. 27
0
        /// <summary>
        /// Creates a LinkedSlot and inserts it into the linked list for this ThreadLocal instance.
        /// </summary>
        private void CreateLinkedSlot(LinkedSlotVolatile[] slotArray, int id, T value)
        {
            // Create a LinkedSlot
            var linkedSlot = new LinkedSlot(slotArray);

            // Insert the LinkedSlot into the linked list maintained by this ThreadLocal<> instance and into the slot array
            using (LockHolder.Hold(s_idManager.m_lock))
            {
                // Check that the instance has not been disposed. It is important to check this under a lock, since
                // Dispose also executes under a lock.
                if (!m_initialized)
                {
                    throw new ObjectDisposedException(SR.ThreadLocal_Disposed);
                }

                LinkedSlot firstRealNode = m_linkedSlot.Next;

                //
                // Insert linkedSlot between nodes m_linkedSlot and firstRealNode.
                // (m_linkedSlot is the dummy head node that should always be in the front.)
                //
                linkedSlot.Next     = firstRealNode;
                linkedSlot.Previous = m_linkedSlot;
                linkedSlot.Value    = value;

                if (firstRealNode != null)
                {
                    firstRealNode.Previous = linkedSlot;
                }
                m_linkedSlot.Next = linkedSlot;

                // Assigning the slot under a lock prevents a race with Dispose (dispose also acquires the lock).
                // Otherwise, it would be possible that the ThreadLocal instance is disposed, another one gets created
                // with the same ID, and the write would go to the wrong instance.
                slotArray[id].Value = linkedSlot;
            }
        }
Esempio n. 28
0
        internal void Fire()
        {
            bool canceled = false;

            lock (TimerQueue.Instance)
            {
                canceled = _canceled;
                if (!canceled)
                {
                    _callbacksRunning++;
                }
            }

            if (canceled)
            {
                return;
            }

            CallCallback();

            bool shouldSignal = false;

            using (LockHolder.Hold(TimerQueue.Instance.Lock))
            {
                _callbacksRunning--;
                if (_canceled && _callbacksRunning == 0 && _notifyWhenNoCallbacksRunning != null)
                {
                    shouldSignal = true;
                }
            }

            if (shouldSignal)
            {
                SignalNoCallbacksRunning();
            }
        }
Esempio n. 29
0
        //
        // Fire any timers that have expired, and update the native timer to schedule the rest of them.
        //
        private void FireNextTimers()
        {
            //
            // we fire the first timer on this thread; any other timers that might have fired are queued
            // to the ThreadPool.
            //
            TimerQueueTimer timerToFireOnThisThread = null;

            using (LockHolder.Hold(Lock))
            {
                //
                // since we got here, that means our previous timer has fired.
                //
                ReleaseTimer();
                m_currentNativeTimerDuration = UInt32.MaxValue;

                bool haveTimerToSchedule        = false;
                uint nextAppDomainTimerDuration = uint.MaxValue;

                int nowTicks = TickCount;

                //
                // Sweep through all timers.  The ones that have reached their due time
                // will fire.  We will calculate the next native timer due time from the
                // other timers.
                //
                TimerQueueTimer timer = m_timers;
                while (timer != null)
                {
                    Debug.Assert(timer.m_dueTime != Timer.UnsignedInfiniteTimeout);

                    uint elapsed = (uint)(nowTicks - timer.m_startTicks);
                    if (elapsed >= timer.m_dueTime)
                    {
                        //
                        // Remember the next timer in case we delete this one
                        //
                        TimerQueueTimer nextTimer = timer.m_next;

                        if (timer.m_period != Timer.UnsignedInfiniteTimeout)
                        {
                            timer.m_startTicks = nowTicks;
                            timer.m_dueTime    = timer.m_period;

                            //
                            // This is a repeating timer; schedule it to run again.
                            //
                            if (timer.m_dueTime < nextAppDomainTimerDuration)
                            {
                                haveTimerToSchedule        = true;
                                nextAppDomainTimerDuration = timer.m_dueTime;
                            }
                        }
                        else
                        {
                            //
                            // Not repeating; remove it from the queue
                            //
                            DeleteTimer(timer);
                        }

                        //
                        // If this is the first timer, we'll fire it on this thread.  Otherwise, queue it
                        // to the ThreadPool.
                        //
                        if (timerToFireOnThisThread == null)
                        {
                            timerToFireOnThisThread = timer;
                        }
                        else
                        {
                            QueueTimerCompletion(timer);
                        }

                        timer = nextTimer;
                    }
                    else
                    {
                        //
                        // This timer hasn't fired yet.  Just update the next time the native timer fires.
                        //
                        uint remaining = timer.m_dueTime - elapsed;
                        if (remaining < nextAppDomainTimerDuration)
                        {
                            haveTimerToSchedule        = true;
                            nextAppDomainTimerDuration = remaining;
                        }
                        timer = timer.m_next;
                    }
                }

                if (haveTimerToSchedule)
                {
                    EnsureAppDomainTimerFiresBy(nextAppDomainTimerDuration);
                }
            }

            //
            // Fire the user timer outside of the lock!
            //
            if (timerToFireOnThisThread != null)
            {
                timerToFireOnThisThread.Fire();
            }
        }
Esempio n. 30
0
        /// <summary>
        /// Exits the <see cref="SemaphoreSlim"/> a specified number of times.
        /// </summary>
        /// <param name="releaseCount">The number of times to exit the semaphore.</param>
        /// <returns>The previous count of the <see cref="SemaphoreSlim"/>.</returns>
        /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="releaseCount"/> is less
        /// than 1.</exception>
        /// <exception cref="T:System.Threading.SemaphoreFullException">The <see cref="SemaphoreSlim"/> has
        /// already reached its maximum size.</exception>
        /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
        /// disposed.</exception>
        public int Release(int releaseCount)
        {
            CheckDispose();

            // Validate input
            if (releaseCount < 1)
            {
                throw new ArgumentOutOfRangeException(
                          nameof(releaseCount), releaseCount, SR.SemaphoreSlim_Release_CountWrong);
            }
            int returnCount;

            using (LockHolder.Hold(m_lock))
            {
                // Read the m_currentCount into a local variable to avoid unnecessary volatile accesses inside the lock.
                int currentCount = m_currentCount;
                returnCount = currentCount;

                // If the release count would result exceeding the maximum count, throw SemaphoreFullException.
                if (m_maxCount - currentCount < releaseCount)
                {
                    throw new SemaphoreFullException();
                }

                // Increment the count by the actual release count
                currentCount += releaseCount;

                // Signal to any synchronous waiters
                int waitCount = m_waitCount;

                int waitersToNotify = Math.Min(releaseCount, waitCount);
                for (int i = 0; i < waitersToNotify; i++)
                {
                    m_condition.SignalOne();
                }

                // Now signal to any asynchronous waiters, if there are any.  While we've already
                // signaled the synchronous waiters, we still hold the lock, and thus
                // they won't have had an opportunity to acquire this yet.  So, when releasing
                // asynchronous waiters, we assume that all synchronous waiters will eventually
                // acquire the semaphore.  That could be a faulty assumption if those synchronous
                // waits are canceled, but the wait code path will handle that.
                if (m_asyncHead != null)
                {
                    Debug.Assert(m_asyncTail != null, "tail should not be null if head isn't null");
                    int maxAsyncToRelease = currentCount - waitCount;
                    while (maxAsyncToRelease > 0 && m_asyncHead != null)
                    {
                        --currentCount;
                        --maxAsyncToRelease;

                        // Get the next async waiter to release and queue it to be completed
                        var waiterTask = m_asyncHead;
                        RemoveAsyncWaiter(waiterTask); // ensures waiterTask.Next/Prev are null
                        QueueWaiterTask(waiterTask);
                    }
                }
                m_currentCount = currentCount;

                // Exposing wait handle if it is not null
                if (m_waitHandle != null && returnCount == 0 && currentCount > 0)
                {
                    m_waitHandle.Set();
                }
            }

            // And return the count
            return(returnCount);
        }