//#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!
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);
}
PACQUIRE_FUNCTION AcquireResource;
BOOLEAN Wait;
BOOLEAN RetExpected;
+ PKSTART_ROUTINE StartRoutine;
} THREAD_DATA, *PTHREAD_DATA;
static
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
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);
ok_eq_hex(Status, STATUS_SUCCESS);
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));
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);