[USP10_WINETEST] Sync with Wine Staging 2.9. CORE-13362
[reactos.git] / rostests / kmtests / ntos_ex / ExResource.c
index f87f5b3..74c2dc8 100644 (file)
 //#define NDEBUG
 #include <debug.h>
 
+static
+_IRQL_requires_max_(APC_LEVEL)
+_Acquires_lock_(_Global_critical_region_)
+PVOID
+(NTAPI
+*pExEnterCriticalRegionAndAcquireResourceShared)(
+    _Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_shared_lock_(*_Curr_)
+        PERESOURCE Resource);
+
+static
+_IRQL_requires_max_(APC_LEVEL)
+_Acquires_lock_(_Global_critical_region_)
+PVOID
+(NTAPI
+*pExEnterCriticalRegionAndAcquireResourceExclusive)(
+    _Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_exclusive_lock_(*_Curr_)
+        PERESOURCE Resource);
+
+static
+_IRQL_requires_max_(APC_LEVEL)
+_Acquires_lock_(_Global_critical_region_)
+PVOID
+(NTAPI
+*pExEnterCriticalRegionAndAcquireSharedWaitForExclusive)(
+    _Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_lock_(*_Curr_)
+        PERESOURCE Resource);
+
+static
+_IRQL_requires_max_(DISPATCH_LEVEL)
+_Releases_lock_(_Global_critical_region_)
+VOID
+(FASTCALL
+*pExReleaseResourceAndLeaveCriticalRegion)(
+    _Inout_ _Requires_lock_held_(*_Curr_) _Releases_lock_(*_Curr_)
+        PERESOURCE Resource);
+
+static
+_IRQL_requires_min_(PASSIVE_LEVEL)
+_IRQL_requires_max_(DISPATCH_LEVEL)
+BOOLEAN
+(NTAPI
+*pKeAreAllApcsDisabled)(VOID);
+
 /* TODO: This is getting pretty long, make it somehow easier to read if possible */
 
 /* TODO: this is the Windows Server 2003 version! ROS should use this!
@@ -137,65 +180,83 @@ TestResourceUndocumentedShortcuts(
     LONG Count = 0;
 
     ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
-    ok_eq_uint(KeAreAllApcsDisabled(), AreApcsDisabled);
+    if (pKeAreAllApcsDisabled)
+        ok_eq_uint(pKeAreAllApcsDisabled(), AreApcsDisabled);
 
+    if (skip(pExEnterCriticalRegionAndAcquireResourceShared &&
+             pExEnterCriticalRegionAndAcquireSharedWaitForExclusive &&
+             pExEnterCriticalRegionAndAcquireResourceExclusive &&
+             pExReleaseResourceAndLeaveCriticalRegion, "No shortcuts\n"))
+    {
+        return;
+    }
     /* ExEnterCriticalRegionAndAcquireResourceShared, ExEnterCriticalRegionAndAcquireSharedWaitForExclusive */
     Count = 0;
-    Ret = ExEnterCriticalRegionAndAcquireResourceShared(Res); ++Count;
+    Ret = pExEnterCriticalRegionAndAcquireResourceShared(Res); ++Count;
     ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
     ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
-    ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+    if (pKeAreAllApcsDisabled)
+        ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
     CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
 
-    Ret = ExEnterCriticalRegionAndAcquireResourceShared(Res); ++Count;
+    Ret = pExEnterCriticalRegionAndAcquireResourceShared(Res); ++Count;
     ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
     ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
-    ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+    if (pKeAreAllApcsDisabled)
+        ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
     CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
 
-    ExEnterCriticalRegionAndAcquireSharedWaitForExclusive(Res); ++Count;
+    pExEnterCriticalRegionAndAcquireSharedWaitForExclusive(Res); ++Count;
     ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
     ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
-    ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+    if (pKeAreAllApcsDisabled)
+        ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
     CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
 
     while (Count-- > 1)
     {
-        ExReleaseResourceAndLeaveCriticalRegion(Res);
+        pExReleaseResourceAndLeaveCriticalRegion(Res);
         ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
-        ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+        if (pKeAreAllApcsDisabled)
+            ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
         CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
     }
 
-    ExReleaseResourceAndLeaveCriticalRegion(Res);
+    pExReleaseResourceAndLeaveCriticalRegion(Res);
     ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
-    ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+    if (pKeAreAllApcsDisabled)
+        ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
     CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
 
     /* ExEnterCriticalRegionAndAcquireResourceExclusive */
     Count = 0;
     ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
-    ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
-    Ret = ExEnterCriticalRegionAndAcquireResourceExclusive(Res); ++Count;
+    if (pKeAreAllApcsDisabled)
+        ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
+    Ret = pExEnterCriticalRegionAndAcquireResourceExclusive(Res); ++Count;
     ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
     ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
-    ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+    if (pKeAreAllApcsDisabled)
+        ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
     CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
 
-    Ret = ExEnterCriticalRegionAndAcquireResourceExclusive(Res); ++Count;
+    Ret = pExEnterCriticalRegionAndAcquireResourceExclusive(Res); ++Count;
     ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
     ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
-    ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+    if (pKeAreAllApcsDisabled)
+        ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
     CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
 
-    ExReleaseResourceAndLeaveCriticalRegion(Res); --Count;
+    pExReleaseResourceAndLeaveCriticalRegion(Res); --Count;
     ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
-    ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled);
+    if (pKeAreAllApcsDisabled)
+        ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
     CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
 
-    ExReleaseResourceAndLeaveCriticalRegion(Res); --Count;
+    pExReleaseResourceAndLeaveCriticalRegion(Res); --Count;
     ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
-    ok_eq_uint(KeAreAllApcsDisabled(), AreApcsDisabled);
+    if (pKeAreAllApcsDisabled)
+        ok_eq_uint(pKeAreAllApcsDisabled(), AreApcsDisabled);
     CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
 }
 
@@ -211,6 +272,7 @@ typedef struct
     PACQUIRE_FUNCTION AcquireResource;
     BOOLEAN Wait;
     BOOLEAN RetExpected;
+    PKSTART_ROUTINE StartRoutine;
 } THREAD_DATA, *PTHREAD_DATA;
 
 static
@@ -241,15 +303,27 @@ AcquireResourceThread(
 
 static
 VOID
-InitThreadData(
+InitThreadDataEx(
     PTHREAD_DATA ThreadData,
     PERESOURCE Res,
-    PACQUIRE_FUNCTION AcquireFunction)
+    PACQUIRE_FUNCTION AcquireFunction,
+    PKSTART_ROUTINE StartRoutine)
 {
     ThreadData->Res = Res;
     KeInitializeEvent(&ThreadData->InEvent, NotificationEvent, FALSE);
     KeInitializeEvent(&ThreadData->OutEvent, NotificationEvent, FALSE);
     ThreadData->AcquireResource = AcquireFunction;
+    ThreadData->StartRoutine = StartRoutine;
+}
+
+static
+VOID
+InitThreadData(
+    PTHREAD_DATA ThreadData,
+    PERESOURCE Res,
+    PACQUIRE_FUNCTION AcquireFunction)
+{
+    InitThreadDataEx(ThreadData, Res, AcquireFunction, AcquireResourceThread);
 }
 
 static
@@ -266,9 +340,9 @@ StartThread(
     ThreadData->Wait = Wait;
     ThreadData->RetExpected = RetExpected;
     InitializeObjectAttributes(&Attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
-    Status = PsCreateSystemThread(&ThreadData->Handle, GENERIC_ALL, &Attributes, NULL, NULL, AcquireResourceThread, ThreadData);
+    Status = PsCreateSystemThread(&ThreadData->Handle, GENERIC_ALL, &Attributes, NULL, NULL, ThreadData->StartRoutine, ThreadData);
     ok_eq_hex(Status, STATUS_SUCCESS);
-    Status = ObReferenceObjectByHandle(ThreadData->Handle, SYNCHRONIZE, PsThreadType, KernelMode, (PVOID *)&ThreadData->Thread, NULL);
+    Status = ObReferenceObjectByHandle(ThreadData->Handle, SYNCHRONIZE, *PsThreadType, KernelMode, (PVOID *)&ThreadData->Thread, NULL);
     ok_eq_hex(Status, STATUS_SUCCESS);
 
     return KeWaitForSingleObject(&ThreadData->OutEvent, Executive, KernelMode, FALSE, Timeout);
@@ -394,12 +468,73 @@ TestResourceWithThreads(
     ok_eq_int(Res->ActiveCount, 0);
 }
 
+static
+VOID
+NTAPI
+TestOwnerRes(
+    PVOID Context)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    PTHREAD_DATA ThreadData = Context;
+    BOOLEAN Ret;
+
+    KeEnterCriticalRegion();
+    Ret = ThreadData->AcquireResource(ThreadData->Res, ThreadData->Wait);
+    if (ThreadData->RetExpected)
+        ok_bool_true(Ret, "AcquireResource returned");
+    else
+        ok_bool_false(Ret, "AcquireResource returned");
+    KeLeaveCriticalRegion();
+
+    ExReleaseResourceForThreadLite(ThreadData->Res, (ULONG_PTR)ThreadData->Res | 3);
+
+    ok_bool_false(KeSetEvent(&ThreadData->OutEvent, 0, TRUE), "KeSetEvent returned");
+    Status = KeWaitForSingleObject(&ThreadData->InEvent, Executive, KernelMode, FALSE, NULL);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+}
+
+static
+VOID
+TestResourceWithOwner(
+    IN PERESOURCE Res)
+{
+    NTSTATUS Status;
+    THREAD_DATA ThreadDataOwner;
+
+    InitThreadDataEx(&ThreadDataOwner, Res, ExAcquireResourceExclusiveLite, TestOwnerRes);
+
+    KeEnterCriticalRegion();
+    ok_bool_true(ExAcquireResourceExclusiveLite(Res, FALSE), "ExAcquireResourceExclusiveLite returned");
+    ExSetResourceOwnerPointer(Res, (PVOID)(ULONG_PTR)3);
+    ExReleaseResourceForThreadLite(Res, 3);
+
+    ok_bool_true(ExAcquireResourceExclusiveLite(Res, FALSE), "ExAcquireResourceExclusiveLite returned");
+    ExSetResourceOwnerPointer(Res, (PVOID)((ULONG_PTR)Res | 3));
+    KeLeaveCriticalRegion();
+
+    Status = StartThread(&ThreadDataOwner, NULL, FALSE, FALSE);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    FinishThread(&ThreadDataOwner);
+}
+
 START_TEST(ExResource)
 {
     NTSTATUS Status;
     ERESOURCE Res;
     KIRQL Irql;
 
+    pExEnterCriticalRegionAndAcquireResourceShared = KmtGetSystemRoutineAddress(L"ExEnterCriticalRegionAndAcquireResourceShared");
+    pExEnterCriticalRegionAndAcquireSharedWaitForExclusive = KmtGetSystemRoutineAddress(L"ExEnterCriticalRegionAndAcquireSharedWaitForExclusive");
+    pExEnterCriticalRegionAndAcquireResourceExclusive = KmtGetSystemRoutineAddress(L"ExEnterCriticalRegionAndAcquireResourceExclusive");
+    pExReleaseResourceAndLeaveCriticalRegion = KmtGetSystemRoutineAddress(L"ExReleaseResourceAndLeaveCriticalRegion");
+    pKeAreAllApcsDisabled = KmtGetSystemRoutineAddress(L"KeAreAllApcsDisabled");
+
+    if (skip(pKeAreAllApcsDisabled != NULL, "KeAreAllApcsDisabled unavailable\n"))
+    {
+        /* We can live without this function here */
+    }
+
     /* this must be true even with the different structure versions */
     ASSERT(sizeof(ERESOURCE) == sizeof(ERESOURCE_2K3));
 
@@ -442,6 +577,9 @@ START_TEST(ExResource)
     CheckResourceFields((PERESOURCE_2K3)&Res, TRUE);
     CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
 
+    TestResourceWithOwner(&Res);
+    CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
+
     Status = ExDeleteResourceLite(&Res);
     ok_eq_hex(Status, STATUS_SUCCESS);