HLSF single thread pass, dead lock on multi thread test
Signed-off-by: Youmu Liu <105042599+Nitload-NSI@users.noreply.github.com>
This commit is contained in:
@@ -63,7 +63,6 @@ namespace StgSharp.HighPerformance.Memory
|
||||
return new hlsfHandle(handle, size);
|
||||
}
|
||||
|
||||
fallback:
|
||||
i = level;
|
||||
s = segmentIndex;
|
||||
while (!TryPopLevelForAllocation(i, s, out handle))
|
||||
@@ -79,8 +78,7 @@ namespace StgSharp.HighPerformance.Memory
|
||||
throw new OverflowException("Out of memory: Unable to allocate new 16MB block or find suitable bucket for allocation.");
|
||||
}
|
||||
|
||||
Thread.Sleep(0);
|
||||
goto fallback;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,15 +87,17 @@ namespace StgSharp.HighPerformance.Memory
|
||||
if (handle != null)
|
||||
{
|
||||
AcquireEntryNextLock(handle);
|
||||
uint allocSize = (uint)((segmentIndex + 1) * levelSizeArray[level]);
|
||||
SliceMemory(handle, (segmentIndex + 1) * levelSizeArray[level]);
|
||||
handle->Level = level;
|
||||
handle->Size = allocSize;
|
||||
SetEntryState(handle, EntryState.Allocated);
|
||||
}
|
||||
|
||||
return new hlsfHandle(handle, size);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ReleaseEntryNextLock(handle);
|
||||
ReleaseEntrySpinLock(handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,26 +105,32 @@ namespace StgSharp.HighPerformance.Memory
|
||||
{
|
||||
Entry* current = e;
|
||||
ulong n = e->NextNear;
|
||||
Entry* next = e;
|
||||
Entry* next = (Entry*)n;
|
||||
|
||||
ulong originOffset = e->Position - (ulong)m_Buffer;
|
||||
ulong finalOffset = originOffset + (ulong)offset;
|
||||
ulong end = e->Position + e->Size - (ulong)m_Buffer;
|
||||
int remainSize = (int)(e->Size - offset);
|
||||
|
||||
AcquireEntryNextLock(e);
|
||||
AcquireEntryPrevLock(next);
|
||||
AcquireEntryBothLocks(e);
|
||||
if (next != null) {
|
||||
AcquireEntryPrevLock(next);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if ((originOffset & 63) != 0) {
|
||||
throw new InvalidOperationException("Entry position offset is not aligned to 64 bytes.");
|
||||
}
|
||||
|
||||
int minLevel = Math.Max((BitOperations.TrailingZeroCount(originOffset) - 6) / 2, 0);
|
||||
int i = minLevel >= levelSizeArray.Length ? levelSizeArray.Length - 1 : minLevel;
|
||||
|
||||
for (; i < levelSizeArray.Length; i++)
|
||||
{
|
||||
int levelSize = levelSizeArray[i];
|
||||
int blockCount = remainSize / levelSize % 4;
|
||||
ulong board = (finalOffset + (ulong)levelSize - 1) & ~((ulong)levelSize - 1);
|
||||
int blockCount = (int)(ulong.Min(board, end) / (ulong)levelSize);
|
||||
if (blockCount == 0)
|
||||
{
|
||||
break;
|
||||
@@ -145,7 +151,9 @@ namespace StgSharp.HighPerformance.Memory
|
||||
newEntry->PreviousNear = (ulong)current;
|
||||
newEntry->NextNear = n;
|
||||
current->NextNear = (ulong)newEntry;
|
||||
next->PreviousNear = (ulong)newEntry;
|
||||
if (next != null) {
|
||||
next->PreviousNear = (ulong)newEntry;
|
||||
}
|
||||
|
||||
newEntry->Level = i;
|
||||
PushLevel(i, blockCount - 1, bucket);
|
||||
@@ -160,16 +168,16 @@ namespace StgSharp.HighPerformance.Memory
|
||||
ReleaseEntryNextLock(old);
|
||||
AcquireEntryNextLock(current);
|
||||
}
|
||||
if (remainSize <= 0)
|
||||
{
|
||||
ReleaseEntryNextLock(current);
|
||||
ReleaseEntryPrevLock(next);
|
||||
|
||||
if (remainSize <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (; i >= 0; i--)
|
||||
{
|
||||
int levelSize = levelSizeArray[i];
|
||||
int blockCount = remainSize / levelSize % 4;
|
||||
ulong board = (finalOffset + (ulong)levelSize - 1) & ~((ulong)levelSize - 1);
|
||||
int blockCount = (int)(ulong.Min(board, end) / (ulong)levelSize);
|
||||
if (blockCount == 0)
|
||||
{
|
||||
continue;
|
||||
@@ -188,9 +196,11 @@ namespace StgSharp.HighPerformance.Memory
|
||||
|
||||
// link new entry
|
||||
newEntry->PreviousNear = (ulong)current;
|
||||
current->NextNear = (ulong)newEntry;
|
||||
newEntry->NextNear = n;
|
||||
next->PreviousNear = (ulong)newEntry;
|
||||
current->NextNear = (ulong)newEntry;
|
||||
if (next != null) {
|
||||
next->PreviousNear = (ulong)newEntry;
|
||||
}
|
||||
|
||||
newEntry->Level = i;
|
||||
PushLevel(i, blockCount - 1, bucket);
|
||||
@@ -216,9 +226,10 @@ namespace StgSharp.HighPerformance.Memory
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Release locks in reverse order
|
||||
ReleaseEntryNextLock(current);
|
||||
ReleaseEntryPrevLock(next);
|
||||
ReleaseEntryBothLocks(e);
|
||||
if (next != null) {
|
||||
ReleaseEntryPrevLock(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -324,6 +324,7 @@ namespace StgSharp.HighPerformance.Memory
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (previous != null) {
|
||||
previous->NextLevel = n;
|
||||
}
|
||||
@@ -381,7 +382,9 @@ namespace StgSharp.HighPerformance.Memory
|
||||
}
|
||||
|
||||
int thread = Environment.CurrentManagedThreadId;
|
||||
return Interlocked.CompareExchange(ref node->PrevLock, thread, 0) == 0;
|
||||
return
|
||||
Interlocked.CompareExchange(ref node->PrevLock, thread, 0) == 0 ||
|
||||
Volatile.Read(ref node->PrevLock) == thread;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -422,7 +425,9 @@ namespace StgSharp.HighPerformance.Memory
|
||||
}
|
||||
|
||||
int thread = Environment.CurrentManagedThreadId;
|
||||
return Interlocked.CompareExchange(ref node->NextLock, thread, 0) == 0;
|
||||
return
|
||||
Interlocked.CompareExchange(ref node->NextLock, thread, 0) == 0 ||
|
||||
Volatile.Read(ref node->NextLock) == thread;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -461,20 +466,59 @@ namespace StgSharp.HighPerformance.Memory
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryAcquireBucketNodePrevLock(node))
|
||||
int thread = Environment.CurrentManagedThreadId;
|
||||
int retryCount = 0;
|
||||
|
||||
while (retryCount < 1000)
|
||||
{
|
||||
if (TryAcquireBucketNodeNextLock(node))
|
||||
if (Interlocked.CompareExchange(ref node->PrevLock, thread, 0) == 0 ||
|
||||
Volatile.Read(ref node->PrevLock) == thread)
|
||||
{
|
||||
return true;
|
||||
} else
|
||||
{
|
||||
ReleaseBucketNodePrevLock(node); // 回滚
|
||||
return false;
|
||||
if (Interlocked.CompareExchange(ref node->NextLock, thread, 0) == 0 ||
|
||||
Volatile.Read(ref node->NextLock) == thread)
|
||||
{
|
||||
return true;
|
||||
} else
|
||||
{
|
||||
Volatile.Write(ref node->PrevLock, 0);
|
||||
}
|
||||
}
|
||||
|
||||
retryCount++;
|
||||
Thread.Sleep(0); // 让出 CPU
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void AcquireBucketNodeBothLocks(BucketNode* node)
|
||||
{
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int thread = Environment.CurrentManagedThreadId;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref node->PrevLock, thread, 0) == 0 ||
|
||||
Volatile.Read(ref node->PrevLock) == thread)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref node->NextLock, thread, 0) == 0 ||
|
||||
Volatile.Read(ref node->NextLock) == thread)
|
||||
{
|
||||
return;
|
||||
} else
|
||||
{
|
||||
Volatile.Write(ref node->PrevLock, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Thread.Sleep(0); // 让出 CPU
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void ReleaseBucketNodeBothLocks(BucketNode* node)
|
||||
{
|
||||
@@ -486,17 +530,6 @@ namespace StgSharp.HighPerformance.Memory
|
||||
ReleaseBucketNodeNextLock(node);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void AcquireBucketNodeBothLocks(BucketNode* node)
|
||||
{
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AcquireBucketNodePrevLock(node);
|
||||
AcquireBucketNodeNextLock(node);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,44 @@ namespace StgSharp.HighPerformance.Memory
|
||||
|
||||
private object _lock = new object();
|
||||
|
||||
public void DisplayAllocatedEntryLayout(bool singleStep)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
Entry* cur = _spareMemory;
|
||||
while (cur != null)
|
||||
{
|
||||
if (cur->State == EntryState.Allocated)
|
||||
{
|
||||
Console.WriteLine(EntryToString(cur));
|
||||
if (singleStep) {
|
||||
Console.ReadKey();
|
||||
}
|
||||
}
|
||||
cur = (Entry*)cur->PreviousNear;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DisplayEmptyEntryLayout(bool singleStep)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
Entry* cur = _spareMemory;
|
||||
while (cur != null)
|
||||
{
|
||||
if (cur->State == EntryState.Empty)
|
||||
{
|
||||
Console.WriteLine(EntryToString(cur));
|
||||
if (singleStep) {
|
||||
Console.ReadKey();
|
||||
}
|
||||
}
|
||||
cur = (Entry*)cur->PreviousNear;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DisplayEntryLayout(bool singleStep)
|
||||
{
|
||||
lock (_lock)
|
||||
|
||||
@@ -28,13 +28,6 @@
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using hlsfHandle = StgSharp.HighPerformance.Memory.HybridLayerSegregatedFitAllocationHandle;
|
||||
|
||||
namespace StgSharp.HighPerformance.Memory
|
||||
@@ -75,9 +68,6 @@ namespace StgSharp.HighPerformance.Memory
|
||||
|
||||
// Step 7: Push the merged entry back to appropriate bucket
|
||||
PushLevel(finalLevel, finalSegment, (BucketNode*)e->Position);
|
||||
|
||||
// Note: If mergedEntry is different from original e, the original e
|
||||
// and any merged entries have already been freed to _entries by MergeAndRemoveFromBuckets
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -49,16 +49,16 @@ namespace StgSharp.HighPerformance.Memory
|
||||
|
||||
private bool AssertBackwardBoundary(ulong current, Entry* target, int level)
|
||||
{
|
||||
int size = (level * 2) + 6;
|
||||
ulong align = current >> size;
|
||||
return align == target->Position >> size && align == (current + target->Size) >> size;
|
||||
ulong align = (ulong)levelSizeArray[level + 1];
|
||||
ulong targetOffset = target->Position - (ulong)m_Buffer;
|
||||
return current / align == targetOffset / align;
|
||||
}
|
||||
|
||||
private bool AssertForwardBoundary(ulong current, Entry* target, int level)
|
||||
{
|
||||
int size = (level * 2) + 6;
|
||||
ulong align = current >> size;
|
||||
return align == target->Position >> size && align == (current - target->Size) >> size;
|
||||
ulong align = (ulong)levelSizeArray[level + 1];
|
||||
ulong targetOffset = target->Position + target->Size - (ulong)m_Buffer;
|
||||
return current / align == targetOffset / align;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -209,6 +209,10 @@ namespace StgSharp.HighPerformance.Memory
|
||||
return;
|
||||
}
|
||||
AcquireEntrySpinLock(entry);
|
||||
entry->LockBuffer = 0;
|
||||
entry->State = EntryState.Empty;
|
||||
entry->PreviousNear = EmptyHandle;
|
||||
entry->NextNear = EmptyHandle;
|
||||
_entries.Free((nuint)entry);
|
||||
}
|
||||
|
||||
@@ -308,15 +312,13 @@ namespace StgSharp.HighPerformance.Memory
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int GetEntryState(Entry* entry)
|
||||
{
|
||||
return entry != null ? Volatile.Read(ref entry->State) : 0;
|
||||
return Volatile.Read(ref entry->State);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void SetEntryState(Entry* entry, int newState)
|
||||
{
|
||||
if (entry != null) {
|
||||
Volatile.Write(ref entry->State, newState);
|
||||
}
|
||||
Volatile.Write(ref entry->State, newState);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -343,7 +345,6 @@ namespace StgSharp.HighPerformance.Memory
|
||||
return GetEntryState(entry) == EntryState.Merging;
|
||||
}
|
||||
|
||||
// Entry 前驱锁操作(控制PreviousNear字段)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool TryAcquireEntryPrevLock(Entry* entry)
|
||||
{
|
||||
@@ -352,7 +353,9 @@ namespace StgSharp.HighPerformance.Memory
|
||||
}
|
||||
|
||||
int thread = Environment.CurrentManagedThreadId;
|
||||
return Interlocked.CompareExchange(ref entry->PrevLock, thread, 0) == 0;
|
||||
return
|
||||
Interlocked.CompareExchange(ref entry->PrevLock, thread, 0) == 0 ||
|
||||
Volatile.Read(ref entry->PrevLock) == thread;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -392,7 +395,9 @@ namespace StgSharp.HighPerformance.Memory
|
||||
}
|
||||
|
||||
int thread = Environment.CurrentManagedThreadId;
|
||||
return Interlocked.CompareExchange(ref entry->NextLock, thread, 0) == 0;
|
||||
return
|
||||
Interlocked.CompareExchange(ref entry->NextLock, thread, 0) == 0 ||
|
||||
Volatile.Read(ref entry->NextLock) == thread;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -432,17 +437,23 @@ namespace StgSharp.HighPerformance.Memory
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryAcquireEntryPrevLock(entry))
|
||||
int thread = Environment.CurrentManagedThreadId;
|
||||
|
||||
// 尝试同时获取前后锁
|
||||
if (Interlocked.CompareExchange(ref entry->PrevLock, thread, 0) == 0 ||
|
||||
Volatile.Read(ref entry->PrevLock) == thread)
|
||||
{
|
||||
if (TryAcquireEntryNextLock(entry))
|
||||
if (Interlocked.CompareExchange(ref entry->NextLock, thread, 0) == 0 ||
|
||||
Volatile.Read(ref entry->NextLock) == thread)
|
||||
{
|
||||
return true;
|
||||
} else
|
||||
{
|
||||
ReleaseEntryPrevLock(entry); // 回滚
|
||||
return false;
|
||||
// 回滚前锁
|
||||
Volatile.Write(ref entry->PrevLock, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -464,8 +475,22 @@ namespace StgSharp.HighPerformance.Memory
|
||||
return;
|
||||
}
|
||||
|
||||
AcquireEntryPrevLock(entry);
|
||||
AcquireEntryNextLock(entry);
|
||||
int thread = Environment.CurrentManagedThreadId;
|
||||
|
||||
// 循环直到成功获取两个锁
|
||||
while (true)
|
||||
{
|
||||
if ((Interlocked.CompareExchange(ref entry->PrevLock, thread, 0) == 0 ||
|
||||
Volatile.Read(ref entry->PrevLock) == thread) &&
|
||||
(Interlocked.CompareExchange(ref entry->NextLock, thread, 0) == 0 ||
|
||||
Volatile.Read(ref entry->NextLock) == thread)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 回滚前锁
|
||||
Volatile.Write(ref entry->PrevLock, 0);
|
||||
Thread.Sleep(0);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Reference in New Issue
Block a user