From a41364e4e42f7517a6eaddbdf91a67add7df95a0 Mon Sep 17 00:00:00 2001 From: wj32 Date: Mon, 17 Aug 2009 08:21:34 +0000 Subject: [PATCH] added some lock-free structures git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1719 21ef857c-d57f-4fe0-8362-d861dc6d29cd --- trunk/KProcessHacker/include/sync.h | 9 +- trunk/ProcessHacker.Common/FreeList.cs | 8 +- .../ProcessHacker.Common.csproj | 2 + .../Threading/FastQueue.cs | 78 +++++++++++++ .../Threading/FastStack.cs | 109 ++++++++++++++++++ 5 files changed, 195 insertions(+), 11 deletions(-) create mode 100644 trunk/ProcessHacker.Common/Threading/FastQueue.cs create mode 100644 trunk/ProcessHacker.Common/Threading/FastStack.cs diff --git a/trunk/KProcessHacker/include/sync.h b/trunk/KProcessHacker/include/sync.h index c2a6b97de..e344ea75e 100644 --- a/trunk/KProcessHacker/include/sync.h +++ b/trunk/KProcessHacker/include/sync.h @@ -76,13 +76,8 @@ FORCEINLINE VOID KphAcquireBitSpinLock( __in LONG Bit ) { - /* Fast path - try to acquire the lock outside of the loop first. */ - if (InterlockedBitTestAndSet(Value, Bit)) - { - /* Slow path - lock was already acquired by someone else; spin. */ - while (InterlockedBitTestAndSet(Value, Bit)) - YieldProcessor(); - } + while (InterlockedBitTestAndSet(Value, Bit)) + YieldProcessor(); } /* KphReleaseBitSpinLock diff --git a/trunk/ProcessHacker.Common/FreeList.cs b/trunk/ProcessHacker.Common/FreeList.cs index dc740b61d..6b2588b30 100644 --- a/trunk/ProcessHacker.Common/FreeList.cs +++ b/trunk/ProcessHacker.Common/FreeList.cs @@ -30,11 +30,11 @@ namespace ProcessHacker.Common public class FreeList where T : IResettable, new() { - private class FreeListEntry - where T : IResettable, new() + private class FreeListEntry + where U : IResettable, new() { - public T Object; - public FreeListEntry Next; + public U Object; + public FreeListEntry Next; } private FreeListEntry _listHead = null; diff --git a/trunk/ProcessHacker.Common/ProcessHacker.Common.csproj b/trunk/ProcessHacker.Common/ProcessHacker.Common.csproj index 1cef04a00..8866cb027 100644 --- a/trunk/ProcessHacker.Common/ProcessHacker.Common.csproj +++ b/trunk/ProcessHacker.Common/ProcessHacker.Common.csproj @@ -70,9 +70,11 @@ + + diff --git a/trunk/ProcessHacker.Common/Threading/FastQueue.cs b/trunk/ProcessHacker.Common/Threading/FastQueue.cs new file mode 100644 index 000000000..85fbca674 --- /dev/null +++ b/trunk/ProcessHacker.Common/Threading/FastQueue.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace ProcessHacker.Common.Threading +{ + public class FastQueue : IEnumerable + { + private class FastQueueNode + { + public U Value; + public FastQueueNode Next; + } + + private int _count = 0; + // The head node. The next pointer of the head node always points + // to the least recently added node - the node to dequeue first. + private FastQueueNode _head; + // The tail node. This is always the most recently added node. + private FastQueueNode _tail; + // Note: all next pointers point to less recently added nodes (i.e. + // the next node to dequeue). + + public FastQueue() + { + _head = new FastQueueNode(); + _tail = _head; + _tail.Next = null; + } + + public int Count + { + get { return _count; } + } + + public T Dequeue() + { + throw new NotImplementedException(); + } + + public void Enqueue(T value) + { + throw new NotImplementedException(); + + FastQueueNode tail; + FastQueueNode tailNext; + FastQueueNode node; + + // Create a new queue node. + node = new FastQueueNode(); + node.Value = value; + node.Next = null; + + // Add the node to the tail of the list, atomically. + // We have to set the next pointer of the current tail node + // and then replace the tail pointer with our new node. + while (true) + { + tailNext = _tail.Next; + + while (true) + { + tail = _tail; + } + } + } + + public IEnumerator GetEnumerator() + { + return null; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)this).GetEnumerator(); + } + } +} diff --git a/trunk/ProcessHacker.Common/Threading/FastStack.cs b/trunk/ProcessHacker.Common/Threading/FastStack.cs new file mode 100644 index 000000000..42fd55a71 --- /dev/null +++ b/trunk/ProcessHacker.Common/Threading/FastStack.cs @@ -0,0 +1,109 @@ +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using System; + +namespace ProcessHacker.Common.Threading +{ + public class FastStack : IEnumerable + { + private class FastStackNode + { + public U Value; + public FastStackNode Next; + } + + private int _count = 0; + private FastStackNode _bottom = null; + + public int Count + { + get { return _count; } + } + + public T Peek() + { + FastStackNode bottom; + + bottom = _bottom; + + if (bottom == null) + throw new InvalidOperationException("The stack is empty."); + + return bottom.Value; + } + + public T Pop() + { + FastStackNode bottom; + + // Atomically replace the bottom of the stack. + while (true) + { + bottom = _bottom; + + // If the bottom of the stack is null, the + // stack is empty. + if (bottom == null) + throw new InvalidOperationException("The stack is empty."); + + // Try to replace the pointer. + if (Interlocked.CompareExchange>( + ref _bottom, + bottom.Next, + bottom + ) == bottom) + { + // Success. + return bottom.Value; + } + } + } + + public void Push(T value) + { + FastStackNode bottom; + FastStackNode entry; + + entry = new FastStackNode(); + entry.Value = value; + + // Atomically replace the bottom of the stack. + while (true) + { + bottom = _bottom; + entry.Next = bottom; + + // Try to replace the pointer. + if (Interlocked.CompareExchange>( + ref _bottom, + entry, + bottom + ) == bottom) + { + // Success. + break; + } + } + } + + public IEnumerator GetEnumerator() + { + FastStackNode entry; + + entry = _bottom; + + // Start the enumeration. + while (entry != null) + { + yield return entry.Value; + entry = entry.Next; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)this).GetEnumerator(); + } + } +}