Major overhaul to fix problem in InterlockedApi functions. All work now. See unit test for example of use. 16-bit structure alignment is critical.

pull/60/head
David Hall 2019-06-18 12:54:41 -06:00
parent ceff427cb9
commit f679e75e88
2 changed files with 113 additions and 9 deletions

View File

@ -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;
}
}
}

View File

@ -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]);
}
}
}