Ejemplo n.º 1
0
        /// <summary>
        /// Unblocks a wait block.
        /// </summary>
        /// <param name="waitBlock">The wait block to unblock.</param>
        private void Unblock(WaitBlock *waitBlock)
        {
            int flags;

            // Clear the spinning flag.
            do
            {
                flags = waitBlock->Flags;
            } while (Interlocked.CompareExchange(
                         ref waitBlock->Flags,
                         flags & ~WaiterSpinning,
                         flags
                         ) != flags);

            if ((flags & WaiterSpinning) == 0)
            {
#if RIGOROUS_CHECKS
                System.Diagnostics.Trace.Assert(_wakeEvent != IntPtr.Zero);
#endif
                NativeMethods.NtReleaseKeyedEvent(
                    _wakeEvent,
                    new IntPtr(waitBlock),
                    false,
                    IntPtr.Zero
                    );
            }
        }
Ejemplo n.º 2
0
        private void VerifyWaitersList()
        {
            bool firstSharedWaiterInList = false;

            if (_firstSharedWaiter == _waitersListHead)
            {
                firstSharedWaiterInList = true;
            }

            for (
                WaitBlock *wb = _waitersListHead->Flink;
                wb != _waitersListHead;
                wb = wb->Flink
                )
            {
                System.Diagnostics.Trace.Assert(wb == wb->Flink->Blink);
                System.Diagnostics.Trace.Assert((wb->Flags & ~WaiterFlags) == 0);

                if (_firstSharedWaiter == wb)
                {
                    firstSharedWaiterInList = true;
                }
            }

            System.Diagnostics.Trace.Assert(firstSharedWaiterInList);
        }
Ejemplo n.º 3
0
        private static void InsertTailList(WaitBlock *listHead, WaitBlock *entry)
        {
            WaitBlock *blink;

            blink           = listHead->Blink;
            entry->Flink    = listHead;
            entry->Blink    = blink;
            blink->Flink    = entry;
            listHead->Blink = entry;
        }
Ejemplo n.º 4
0
        private static void InsertHeadList(WaitBlock *listHead, WaitBlock *entry)
        {
            WaitBlock *flink;

            flink           = listHead->Flink;
            entry->Flink    = flink;
            entry->Blink    = listHead;
            flink->Blink    = entry;
            listHead->Flink = entry;
        }
Ejemplo n.º 5
0
        private static WaitBlock *RemoveHeadList(WaitBlock *listHead)
        {
            WaitBlock *flink;
            WaitBlock *entry;

            entry           = listHead->Flink;
            flink           = entry->Flink;
            listHead->Flink = flink;
            flink->Blink    = listHead;

            return(entry);
        }
Ejemplo n.º 6
0
        private static bool RemoveEntryList(WaitBlock *entry)
        {
            WaitBlock *blink;
            WaitBlock *flink;

            flink        = entry->Flink;
            blink        = entry->Blink;
            blink->Flink = flink;
            flink->Blink = blink;

            return(flink == blink);
        }
Ejemplo n.º 7
0
        private void Dispose(bool disposing)
        {
            if (_waitersListHead != null)
            {
                Marshal.FreeHGlobal((IntPtr)_waitersListHead);
                _waitersListHead = null;
            }

            if (_wakeEvent != IntPtr.Zero)
            {
                NativeMethods.CloseHandle(_wakeEvent);
                _wakeEvent = IntPtr.Zero;
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Wakes one exclusive waiter.
        /// </summary>
        private void WakeExclusive()
        {
            WaitBlock *wb;
            WaitBlock *exclusiveWb = null;

            _lock.Acquire();

            try
            {
                wb = _waitersListHead->Flink;

                if (
                    wb != _waitersListHead &&
                    (wb->Flags & WaiterExclusive) != 0
                    )
                {
                    exclusiveWb = RemoveHeadList(_waitersListHead);
                    wb          = _waitersListHead->Flink;
#if ENABLE_STATISTICS
                    _exclusiveWaitersCount--;
#endif
                }

                if (wb == _waitersListHead)
                {
                    int value;

                    // No more waiters. Clear the waiters bit.
                    do
                    {
                        value = _value;
                    } while (Interlocked.CompareExchange(
                                 ref _value,
                                 value & ~LockWaiters,
                                 value
                                 ) != value);
                }
            }
            finally
            {
                _lock.Release();
            }

            if (exclusiveWb != null)
            {
                this.Unblock(exclusiveWb);
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Creates a FairResourceLock, specifying a spin count.
        /// </summary>
        /// <param name="spinCount">
        /// The number of times to spin before going to sleep.
        /// </param>
        public FairResourceLock(int spinCount)
        {
            _value     = 0;
            _lock      = new SpinLock();
            _spinCount = Environment.ProcessorCount != 1 ? spinCount : 0;

            _waitersListHead        = (WaitBlock *)Marshal.AllocHGlobal(WaitBlock.SizeOf);
            _waitersListHead->Flink = _waitersListHead;
            _waitersListHead->Blink = _waitersListHead;
            _waitersListHead->Flags = 0;
            _firstSharedWaiter      = _waitersListHead;

#if !DEFER_EVENT_CREATION
            _wakeEvent = this.CreateWakeEvent();
#endif
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Inserts a wait block into the waiters list.
        /// </summary>
        /// <param name="waitBlock">The wait block to insert.</param>
        /// <param name="position">Specifies where to insert the wait block.</param>
        private void InsertWaitBlock(WaitBlock *waitBlock, ListPosition position)
        {
            switch (position)
            {
            case ListPosition.First:
                InsertHeadList(_waitersListHead, waitBlock);
                break;

            case ListPosition.LastExclusive:
                InsertTailList(_firstSharedWaiter, waitBlock);
                break;

            case ListPosition.Last:
                InsertTailList(_waitersListHead, waitBlock);
                break;
            }
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Wakes multiple shared waiters.
        /// </summary>
        private void WakeShared()
        {
            WaitBlock wakeList = new WaitBlock();
            WaitBlock* wb;

            wakeList.Flink = &wakeList;
            wakeList.Blink = &wakeList;

            _lock.Acquire();

            try
            {
                wb = _firstSharedWaiter;

                while (true)
                {
                    WaitBlock* flink;

                    if (wb == _waitersListHead)
                    {
                        int value;

                        // No more waiters. Clear the waiters bit.
                        do
                        {
                            value = _value;
                        } while (Interlocked.CompareExchange(
                            ref _value,
                            value & ~LockWaiters,
                            value
                            ) != value);

                        break;
                    }
#if RIGOROUS_CHECKS
                    // We shouldn't have *any* exclusive waiters at this 
                    // point since we started at _firstSharedWaiter.
                    if ((wb->Flags & WaiterExclusive) != 0)
                        System.Diagnostics.Trace.Fail("Exclusive waiter behind shared waiters!");

#endif

                    // Remove the waiter and add it to the wake list.
                    flink = wb->Flink;
                    RemoveEntryList(wb);
                    InsertTailList(&wakeList, wb);
#if ENABLE_STATISTICS
                    _sharedWaitersCount--;
#endif
                    wb = flink;
                }

                // Reset the first shared waiter pointer.
                _firstSharedWaiter = _waitersListHead;
            }
            finally
            {
                _lock.Release();
            }

            // Carefully traverse the wake list and wake each waiter.
            wb = wakeList.Flink;

            while (wb != &wakeList)
            {
                WaitBlock* flink;

                flink = wb->Flink;
                this.Unblock(wb);
                wb = flink;
            }
        }
Ejemplo n.º 12
0
        private void Dispose(bool disposing)
        {
            if (_waitersListHead != null)
            {
                Marshal.FreeHGlobal((IntPtr)_waitersListHead);
                _waitersListHead = null;
            }

            if (_wakeEvent != IntPtr.Zero)
            {
                NativeMethods.CloseHandle(_wakeEvent);
                _wakeEvent = IntPtr.Zero;
            }
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Blocks on a wait block.
        /// </summary>
        /// <param name="waitBlock">The wait block to block on.</param>
        private void Block(WaitBlock *waitBlock)
        {
            int flags;

            // Spin for a while.
            for (int j = 0; j < _spinCount; j++)
            {
                if ((Thread.VolatileRead(ref waitBlock->Flags) & WaiterSpinning) == 0)
                {
                    break;
                }
            }

#if DEFER_EVENT_CREATION
            IntPtr wakeEvent;

            wakeEvent = Interlocked.CompareExchange(ref _wakeEvent, IntPtr.Zero, IntPtr.Zero);

            if (wakeEvent == IntPtr.Zero)
            {
                wakeEvent = this.CreateWakeEvent();

                if (Interlocked.CompareExchange(ref _wakeEvent, wakeEvent, IntPtr.Zero) != IntPtr.Zero)
                {
                    NativeMethods.CloseHandle(wakeEvent);
                }
            }
#endif
            // Clear the spinning flag.
            do
            {
                flags = waitBlock->Flags;
            } while (Interlocked.CompareExchange(
                         ref waitBlock->Flags,
                         flags & ~WaiterSpinning,
                         flags
                         ) != flags);

            // Go to sleep if necessary.
            if ((flags & WaiterSpinning) != 0)
            {
#if ENABLE_STATISTICS
                if ((waitBlock->Flags & WaiterExclusive) != 0)
                {
                    Interlocked.Increment(ref _acqExclSlpCount);
                }
                else
                {
                    Interlocked.Increment(ref _acqShrdSlpCount);
                }
#endif
                if (NativeMethods.NtWaitForKeyedEvent(
                        _wakeEvent,
                        new IntPtr(waitBlock),
                        false,
                        IntPtr.Zero
                        ) != 0)
                {
                    throw new Exception(Utils.MsgFailedToWaitIndefinitely);
                }
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Acquires the lock in shared mode, blocking
        /// if necessary.
        /// </summary>
        /// <remarks>
        /// Exclusive acquires are given precedence over shared
        /// acquires.
        /// </remarks>
        public void AcquireShared()
        {
            int value;
            int i = 0;

#if ENABLE_STATISTICS
            Interlocked.Increment(ref _acqShrdCount);
#endif
            while (true)
            {
                value = _value;

                // Try to obtain the lock.
                // Note that we don't acquire if there are waiters and
                // the lock is already owned in shared mode, in order to
                // give exclusive acquires precedence.
                if (
                    (value & LockOwned) == 0 ||
                    ((value & LockWaiters) == 0 && ((value >> LockSharedOwnersShift) & LockSharedOwnersMask) != 0)
                    )
                {
                    if ((value & LockOwned) == 0)
                    {
#if RIGOROUS_CHECKS
                        System.Diagnostics.Trace.Assert(((value >> LockSharedOwnersShift) & LockSharedOwnersMask) == 0);
#endif
                        if (Interlocked.CompareExchange(
                                ref _value,
                                value + LockOwned + LockSharedOwnersIncrement,
                                value
                                ) == value)
                        {
                            break;
                        }
                    }
                    else
                    {
                        if (Interlocked.CompareExchange(
                                ref _value,
                                value + LockSharedOwnersIncrement,
                                value
                                ) == value)
                        {
                            break;
                        }
                    }
                }
                else if (i >= _spinCount)
                {
                    // We need to wait.
                    WaitBlock waitBlock;

                    waitBlock.Flags = WaiterSpinning;

                    // Obtain the waiters list lock.
                    _lock.Acquire();

                    try
                    {
                        // Try to set the waiters bit.
                        if (Interlocked.CompareExchange(
                                ref _value,
                                value | LockWaiters,
                                value
                                ) != value)
                        {
#if ENABLE_STATISTICS
                            Interlocked.Increment(ref _insWaitBlkRetryCount);
#endif
                            continue;
                        }

                        // Put our wait block behind other waiters.
                        this.InsertWaitBlock(&waitBlock, ListPosition.Last);

                        // Set the first shared waiter pointer.
                        if (
                            waitBlock.Blink == _waitersListHead ||
                            (waitBlock.Blink->Flags & WaiterExclusive) != 0
                            )
                        {
                            _firstSharedWaiter = &waitBlock;
                        }
#if ENABLE_STATISTICS
                        _sharedWaitersCount++;

                        if (_peakShrdWtrsCount < _sharedWaitersCount)
                        {
                            _peakShrdWtrsCount = _sharedWaitersCount;
                        }
#endif
                    }
                    finally
                    {
                        _lock.Release();
                    }

#if ENABLE_STATISTICS
                    Interlocked.Increment(ref _acqShrdBlkCount);
#endif
                    this.Block(&waitBlock);

                    // Go back and try again.
                    continue;
                }

#if ENABLE_STATISTICS
                Interlocked.Increment(ref _acqShrdContCount);
#endif
                i++;
            }
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Creates a FairResourceLock, specifying a spin count.
        /// </summary>
        /// <param name="spinCount">
        /// The number of times to spin before going to sleep.
        /// </param>
        public FairResourceLock(int spinCount)
        {
            _value = 0;
            _lock = new SpinLock();
            _spinCount = Environment.ProcessorCount != 1 ? spinCount : 0;

            _waitersListHead = (WaitBlock*)Marshal.AllocHGlobal(WaitBlock.SizeOf);
            _waitersListHead->Flink = _waitersListHead;
            _waitersListHead->Blink = _waitersListHead;
            _waitersListHead->Flags = 0;
            _firstSharedWaiter = _waitersListHead;

#if !DEFER_EVENT_CREATION
            _wakeEvent = this.CreateWakeEvent();
#endif
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Wakes multiple shared waiters.
        /// </summary>
        private void WakeShared()
        {
            WaitBlock  wakeList = new WaitBlock();
            WaitBlock *wb;

            wakeList.Flink = &wakeList;
            wakeList.Blink = &wakeList;

            _lock.Acquire();

            try
            {
                wb = _firstSharedWaiter;

                while (true)
                {
                    WaitBlock *flink;

                    if (wb == _waitersListHead)
                    {
                        int value;

                        // No more waiters. Clear the waiters bit.
                        do
                        {
                            value = _value;
                        } while (Interlocked.CompareExchange(
                                     ref _value,
                                     value & ~LockWaiters,
                                     value
                                     ) != value);

                        break;
                    }
#if RIGOROUS_CHECKS
                    // We shouldn't have *any* exclusive waiters at this
                    // point since we started at _firstSharedWaiter.
                    if ((wb->Flags & WaiterExclusive) != 0)
                    {
                        System.Diagnostics.Trace.Fail("Exclusive waiter behind shared waiters!");
                    }
#endif

                    // Remove the waiter and add it to the wake list.
                    flink = wb->Flink;
                    RemoveEntryList(wb);
                    InsertTailList(&wakeList, wb);
#if ENABLE_STATISTICS
                    _sharedWaitersCount--;
#endif
                    wb = flink;
                }

                // Reset the first shared waiter pointer.
                _firstSharedWaiter = _waitersListHead;
            }
            finally
            {
                _lock.Release();
            }

            // Carefully traverse the wake list and wake each waiter.
            wb = wakeList.Flink;

            while (wb != &wakeList)
            {
                WaitBlock *flink;

                flink = wb->Flink;
                this.Unblock(wb);
                wb = flink;
            }
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Wakes either one exclusive waiter or multiple shared waiters.
        /// </summary>
        private void Wake()
        {
            WaitBlock  wakeList = new WaitBlock();
            WaitBlock *wb;
            WaitBlock *exclusiveWb = null;

            wakeList.Flink = &wakeList;
            wakeList.Blink = &wakeList;

            _lock.Acquire();

            try
            {
                bool first = true;

                while (true)
                {
                    wb = _waitersListHead->Flink;

                    if (wb == _waitersListHead)
                    {
                        int value;

                        // No more waiters. Clear the waiters bit.
                        do
                        {
                            value = _value;
                        } while (Interlocked.CompareExchange(
                                     ref _value,
                                     value & ~LockWaiters,
                                     value
                                     ) != value);

                        break;
                    }

                    // If this is an exclusive waiter, don't wake
                    // anyone else.
                    if (first && (wb->Flags & WaiterExclusive) != 0)
                    {
                        exclusiveWb = RemoveHeadList(_waitersListHead);
#if ENABLE_STATISTICS
                        _exclusiveWaitersCount--;
#endif
                        break;
                    }

#if RIGOROUS_CHECKS
                    // If this is not the first waiter we have looked at
                    // and it is an exclusive waiter, then we have a bug -
                    // we should have stopped upon encountering the first
                    // exclusive waiter (previous block), so this means
                    // we have an exclusive waiter *behind* shared waiters.
                    if (!first && (wb->Flags & WaiterExclusive) != 0)
                    {
                        System.Diagnostics.Trace.Fail("Exclusive waiter behind shared waiters!");
                    }
#endif
                    // Remove the (shared) waiter and add it to the wake list.
                    wb = RemoveHeadList(_waitersListHead);
                    InsertTailList(&wakeList, wb);
#if ENABLE_STATISTICS
                    _sharedWaitersCount--;
#endif

                    first = false;
                }

                if (exclusiveWb == null)
                {
                    // If we removed shared waiters, we removed all of them.
                    // Reset the first shared waiter pointer.
                    // Note that this also applies if we haven't woken anyone
                    // at all; this just becomes a redundant assignment.
                    _firstSharedWaiter = _waitersListHead;
                }
            }
            finally
            {
                _lock.Release();
            }

            // If we removed one exclusive waiter, unblock it.
            if (exclusiveWb != null)
            {
                this.Unblock(exclusiveWb);
                return;
            }

            // Carefully traverse the wake list and wake each shared waiter.
            wb = wakeList.Flink;

            while (wb != &wakeList)
            {
                WaitBlock *flink;

                flink = wb->Flink;
                this.Unblock(wb);
                wb = flink;
            }
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Wakes either one exclusive waiter or multiple shared waiters.
        /// </summary>
        private void Wake()
        {
            WaitBlock wakeList = new WaitBlock();
            WaitBlock* wb;
            WaitBlock* exclusiveWb = null;

            wakeList.Flink = &wakeList;
            wakeList.Blink = &wakeList;

            _lock.Acquire();

            try
            {
                bool first = true;

                while (true)
                {
                    wb = _waitersListHead->Flink;

                    if (wb == _waitersListHead)
                    {
                        int value;

                        // No more waiters. Clear the waiters bit.
                        do
                        {
                            value = _value;
                        } while (Interlocked.CompareExchange(
                            ref _value,
                            value & ~LockWaiters,
                            value
                            ) != value);

                        break;
                    }

                    // If this is an exclusive waiter, don't wake 
                    // anyone else.
                    if (first && (wb->Flags & WaiterExclusive) != 0)
                    {
                        exclusiveWb = RemoveHeadList(_waitersListHead);
#if ENABLE_STATISTICS
                        _exclusiveWaitersCount--;

#endif
                        break;
                    }

#if RIGOROUS_CHECKS
                    // If this is not the first waiter we have looked at 
                    // and it is an exclusive waiter, then we have a bug - 
                    // we should have stopped upon encountering the first 
                    // exclusive waiter (previous block), so this means 
                    // we have an exclusive waiter *behind* shared waiters.
                    if (!first && (wb->Flags & WaiterExclusive) != 0)
                    {
                        System.Diagnostics.Trace.Fail("Exclusive waiter behind shared waiters!");
                    }

#endif
                    // Remove the (shared) waiter and add it to the wake list.
                    wb = RemoveHeadList(_waitersListHead);
                    InsertTailList(&wakeList, wb);
#if ENABLE_STATISTICS
                    _sharedWaitersCount--;
#endif

                    first = false;
                }

                if (exclusiveWb == null)
                {
                    // If we removed shared waiters, we removed all of them. 
                    // Reset the first shared waiter pointer.
                    // Note that this also applies if we haven't woken anyone 
                    // at all; this just becomes a redundant assignment.
                    _firstSharedWaiter = _waitersListHead;
                }
            }
            finally
            {
                _lock.Release();
            }

            // If we removed one exclusive waiter, unblock it.
            if (exclusiveWb != null)
            {
                this.Unblock(exclusiveWb);
                return;
            }

            // Carefully traverse the wake list and wake each shared waiter.
            wb = wakeList.Flink;

            while (wb != &wakeList)
            {
                WaitBlock* flink;

                flink = wb->Flink;
                this.Unblock(wb);
                wb = flink;
            }
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Acquires the lock in shared mode, blocking 
        /// if necessary.
        /// </summary>
        /// <remarks>
        /// Exclusive acquires are given precedence over shared 
        /// acquires.
        /// </remarks>
        public void AcquireShared()
        {
            int value;
            int i = 0;

#if ENABLE_STATISTICS
            Interlocked.Increment(ref _acqShrdCount);

#endif
            while (true)
            {
                value = _value;

                // Try to obtain the lock.
                // Note that we don't acquire if there are waiters and 
                // the lock is already owned in shared mode, in order to 
                // give exclusive acquires precedence.
                if (
                    (value & LockOwned) == 0 ||
                    ((value & LockWaiters) == 0 && ((value >> LockSharedOwnersShift) & LockSharedOwnersMask) != 0)
                    )
                {
                    if ((value & LockOwned) == 0)
                    {
#if RIGOROUS_CHECKS
                        System.Diagnostics.Trace.Assert(((value >> LockSharedOwnersShift) & LockSharedOwnersMask) == 0);

#endif
                        if (Interlocked.CompareExchange(
                            ref _value,
                            value + LockOwned + LockSharedOwnersIncrement,
                            value
                            ) == value)
                            break;
                    }
                    else
                    {
                        if (Interlocked.CompareExchange(
                            ref _value,
                            value + LockSharedOwnersIncrement,
                            value
                            ) == value)
                            break;
                    }
                }
                else if (i >= _spinCount)
                {
                    // We need to wait.
                    WaitBlock waitBlock;

                    waitBlock.Flags = WaiterSpinning;

                    // Obtain the waiters list lock.
                    _lock.Acquire();

                    try
                    {
                        // Try to set the waiters bit.
                        if (Interlocked.CompareExchange(
                            ref _value,
                            value | LockWaiters,
                            value
                            ) != value)
                        {
#if ENABLE_STATISTICS
                            Interlocked.Increment(ref _insWaitBlkRetryCount);

#endif
                            continue;
                        }

                        // Put our wait block behind other waiters.
                        this.InsertWaitBlock(&waitBlock, ListPosition.Last);

                        // Set the first shared waiter pointer.
                        if (
                            waitBlock.Blink == _waitersListHead ||
                            (waitBlock.Blink->Flags & WaiterExclusive) != 0
                            )
                        {
                            _firstSharedWaiter = &waitBlock;
                        }
#if ENABLE_STATISTICS

                        _sharedWaitersCount++;

                        if (_peakShrdWtrsCount < _sharedWaitersCount)
                            _peakShrdWtrsCount = _sharedWaitersCount;
#endif
                    }
                    finally
                    {
                        _lock.Release();
                    }

#if ENABLE_STATISTICS
                    Interlocked.Increment(ref _acqShrdBlkCount);
#endif
                    this.Block(&waitBlock);

                    // Go back and try again.
                    continue;
                }

#if ENABLE_STATISTICS
                Interlocked.Increment(ref _acqShrdContCount);
#endif
                i++;
            }
        }