mirror of https://github.com/dahall/Vanara.git
Major overhaul to fix problem in InterlockedApi functions. All work now. See unit test for example of use. 16-bit structure alignment is critical.
parent
ceff427cb9
commit
f679e75e88
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Vanara.Extensions;
|
||||
|
||||
namespace Vanara.PInvoke
|
||||
{
|
||||
|
@ -32,7 +33,7 @@ namespace Vanara.PInvoke
|
|||
// InitializeSListHead( PSLIST_HEADER ListHead );
|
||||
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
|
||||
[PInvokeData("interlockedapi.h", MSDNShortId = "4e34f947-1687-4ea9-aaa1-8d8dc11dad70")]
|
||||
public static extern void InitializeSListHead(IntPtr ListHead);
|
||||
public static extern void InitializeSListHead(out SLIST_HEADER ListHead);
|
||||
|
||||
/// <summary>
|
||||
/// <para>Removes all items from a singly linked list. Access to the list is synchronized on a multiprocessor system.</para>
|
||||
|
@ -57,7 +58,7 @@ namespace Vanara.PInvoke
|
|||
// InterlockedFlushSList( PSLIST_HEADER ListHead );
|
||||
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
|
||||
[PInvokeData("interlockedapi.h", MSDNShortId = "3fde3377-8a98-4976-a350-2c173b209e8c")]
|
||||
public static extern IntPtr InterlockedFlushSList(IntPtr ListHead);
|
||||
public static extern IntPtr InterlockedFlushSList(in SLIST_HEADER ListHead);
|
||||
|
||||
/// <summary>
|
||||
/// <para>Removes an item from the front of a singly linked list. Access to the list is synchronized on a multiprocessor system.</para>
|
||||
|
@ -80,7 +81,7 @@ namespace Vanara.PInvoke
|
|||
// InterlockedPopEntrySList( PSLIST_HEADER ListHead );
|
||||
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
|
||||
[PInvokeData("interlockedapi.h", MSDNShortId = "10760fd4-5973-4ab0-991c-7a5951c798a4")]
|
||||
public static extern IntPtr InterlockedPopEntrySList(IntPtr ListHead);
|
||||
public static extern IntPtr InterlockedPopEntrySList(in SLIST_HEADER ListHead);
|
||||
|
||||
/// <summary>
|
||||
/// <para>Inserts an item at the front of a singly linked list. Access to the list is synchronized on a multiprocessor system.</para>
|
||||
|
@ -106,7 +107,7 @@ namespace Vanara.PInvoke
|
|||
// InterlockedPushEntrySList( PSLIST_HEADER ListHead, __drv_aliasesMem PSLIST_ENTRY ListEntry );
|
||||
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
|
||||
[PInvokeData("interlockedapi.h", MSDNShortId = "60e3b6f7-f556-4699-be90-db7330cfb8ca")]
|
||||
public static extern IntPtr InterlockedPushEntrySList(IntPtr ListHead, ref SLIST_ENTRY ListEntry);
|
||||
public static extern IntPtr InterlockedPushEntrySList(in SLIST_HEADER ListHead, IntPtr ListEntry);
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a singly-linked list at the front of another singly linked list. Access to the lists is synchronized on a multiprocessor system.
|
||||
|
@ -126,7 +127,7 @@ namespace Vanara.PInvoke
|
|||
// ListEnd, _In_ ULONG Count); https://msdn.microsoft.com/en-us/library/windows/desktop/hh448545(v=vs.85).aspx
|
||||
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
|
||||
[PInvokeData("WinBase.h", MSDNShortId = "hh448545")]
|
||||
public static extern IntPtr InterlockedPushListSList(IntPtr ListHead, ref SLIST_ENTRY List, ref SLIST_ENTRY ListEnd, uint Count);
|
||||
public static extern IntPtr InterlockedPushListSList(in SLIST_HEADER ListHead, IntPtr List, IntPtr ListEnd, uint Count);
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
|
@ -165,7 +166,7 @@ namespace Vanara.PInvoke
|
|||
// InterlockedPushListSListEx( PSLIST_HEADER ListHead, PSLIST_ENTRY List, PSLIST_ENTRY ListEnd, ULONG Count );
|
||||
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
|
||||
[PInvokeData("interlockedapi.h", MSDNShortId = "f4f334c6-fda8-4c5f-9177-b672c8aed6b3")]
|
||||
public static extern IntPtr InterlockedPushListSListEx(IntPtr ListHead, ref SLIST_ENTRY List, ref SLIST_ENTRY ListEnd, uint Count);
|
||||
public static extern IntPtr InterlockedPushListSListEx(in SLIST_HEADER ListHead, IntPtr List, IntPtr ListEnd, uint Count);
|
||||
|
||||
/// <summary>
|
||||
/// <para>Retrieves the number of entries in the specified singly linked list.</para>
|
||||
|
@ -195,16 +196,34 @@ namespace Vanara.PInvoke
|
|||
// PSLIST_HEADER ListHead );
|
||||
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
|
||||
[PInvokeData("interlockedapi.h", MSDNShortId = "3f9b4481-647f-457f-bdfb-62e6ae4198e5")]
|
||||
public static extern ushort QueryDepthSList(IntPtr ListHead);
|
||||
public static extern ushort QueryDepthSList(in SLIST_HEADER ListHead);
|
||||
|
||||
/// <summary>An <c>SLIST_ENTRY</c> structure describes an entry in a sequenced singly linked list.</summary>
|
||||
// typedef struct _SLIST_ENTRY { struct _SLIST_ENTRY *Next;} SLIST_ENTRY, *PSLIST_ENTRY; https://msdn.microsoft.com/en-us/library/windows/hardware/ff563805(v=vs.85).aspx
|
||||
[PInvokeData("Wdm.h", MSDNShortId = "ff563805")]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[PInvokeData("winnt.h")]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 16)]
|
||||
public struct SLIST_ENTRY
|
||||
{
|
||||
/// <summary>Pointer to the next entry in the list, or <c>NULL</c> if there is no next entry in the list.</summary>
|
||||
public IntPtr Next;
|
||||
|
||||
/// <summary>The next entry in the list, or <see langword="null"/> if there is no next entry in the list.</summary>
|
||||
public SLIST_ENTRY? NextEntry => Next.ToNullableStructure<SLIST_ENTRY>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// An <c>SLIST_HEADER</c> structure is an opaque structure that serves as the header for a sequenced singly linked list. For more
|
||||
/// information, see Singly and Doubly Linked Lists.
|
||||
/// </para>
|
||||
/// <para>On 64-bit platforms, <c>SLIST_HEADER</c> structures must be 16-byte aligned.</para>
|
||||
/// </summary>
|
||||
[PInvokeData("winnt.h")]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 16)]
|
||||
public struct SLIST_HEADER
|
||||
{
|
||||
public ulong Alignment;
|
||||
public ulong Region;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Vanara.Extensions;
|
||||
using Vanara.InteropServices;
|
||||
using static Vanara.PInvoke.AdvApi32;
|
||||
using static Vanara.PInvoke.Kernel32;
|
||||
|
||||
namespace Vanara.PInvoke.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class InterlockedApiTests
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 32)]
|
||||
private struct PROGRAM_ITEM
|
||||
{
|
||||
public SLIST_ENTRY ItemEntry;
|
||||
public uint Signature;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void InterlockedTest()
|
||||
{
|
||||
const uint max = 10;
|
||||
|
||||
// Initialize the list header to a MEMORY_ALLOCATION_ALIGNMENT boundary.
|
||||
InitializeSListHead(out var listHead);
|
||||
|
||||
// Insert 10 items into the list.
|
||||
for (var Count = 1U; Count <= max; Count += 1)
|
||||
{
|
||||
var pProgramItem = new PROGRAM_ITEM { Signature = Count }.StructureToPtr(Marshal.AllocHGlobal, out _);
|
||||
InterlockedPushEntrySList(listHead, pProgramItem);
|
||||
}
|
||||
|
||||
Assert.That(QueryDepthSList(listHead), Is.EqualTo(max));
|
||||
|
||||
// Remove 10 items from the list and display the signature.
|
||||
for (var Count = max; Count >= 1; Count -= 1)
|
||||
{
|
||||
var pListEntry = InterlockedPopEntrySList(listHead);
|
||||
|
||||
var programItem = pListEntry.ToNullableStructure<PROGRAM_ITEM>();
|
||||
if (!programItem.HasValue)
|
||||
Assert.Fail("NULL from InterlockedPopEntrySList");
|
||||
Assert.That(Count, Is.EqualTo(programItem.Value.Signature));
|
||||
|
||||
Marshal.FreeHGlobal(pListEntry);
|
||||
}
|
||||
|
||||
// Flush the list and verify that the items are gone.
|
||||
Assert.That(InterlockedFlushSList(listHead), Is.EqualTo(IntPtr.Zero));
|
||||
Assert.That(InterlockedPopEntrySList(listHead), Is.EqualTo(IntPtr.Zero));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void InterlockedTest2()
|
||||
{
|
||||
const uint max = 10;
|
||||
|
||||
// Initialize the list header to a MEMORY_ALLOCATION_ALIGNMENT boundary.
|
||||
InitializeSListHead(out var listHead);
|
||||
|
||||
// Create 10 item list in memory.
|
||||
var items = new IntPtr[max];
|
||||
for (var Count = 0U; Count < max; Count += 1)
|
||||
{
|
||||
items[Count] = new PROGRAM_ITEM { ItemEntry = new SLIST_ENTRY { Next = Count == 0 ? IntPtr.Zero : items[Count - 1] }, Signature = Count + 1 }.StructureToPtr(Marshal.AllocHGlobal, out _);
|
||||
}
|
||||
|
||||
// Add list and check
|
||||
Assert.That(InterlockedPushListSListEx(listHead, items[0], items[max - 1], max), Is.EqualTo(IntPtr.Zero));
|
||||
Assert.That(QueryDepthSList(listHead), Is.EqualTo(max));
|
||||
|
||||
// Flush the list and verify that the items are gone.
|
||||
Assert.That(InterlockedFlushSList(listHead), Is.EqualTo(items[0]));
|
||||
Assert.That(InterlockedPopEntrySList(listHead), Is.EqualTo(IntPtr.Zero));
|
||||
|
||||
// Free items
|
||||
for (var Count = 0U; Count < max; Count += 1)
|
||||
Marshal.FreeHGlobal(items[Count]);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue