Author: tfaber
Date: Wed Jul 13 21:17:55 2011
New Revision: 52674
URL:
http://svn.reactos.org/svn/reactos?rev=52674&view=rev
Log:
[KMTESTS/EX]
- ExResource part 2: test concurrent acquisition of a resource in multiple threads
- ExInterlocked part 2: check calling convention correctness
- these show quite a number of bugs in ReactOS ;)
Modified:
branches/GSoC_2011/KMTestSuite/kmtests/ntos_ex/ExInterlocked.c
branches/GSoC_2011/KMTestSuite/kmtests/ntos_ex/ExResource.c
Modified: branches/GSoC_2011/KMTestSuite/kmtests/ntos_ex/ExInterlocked.c
URL:
http://svn.reactos.org/svn/reactos/branches/GSoC_2011/KMTestSuite/kmtests/n…
==============================================================================
--- branches/GSoC_2011/KMTestSuite/kmtests/ntos_ex/ExInterlocked.c [iso-8859-1]
(original)
+++ branches/GSoC_2011/KMTestSuite/kmtests/ntos_ex/ExInterlocked.c [iso-8859-1] Wed Jul 13
21:17:55 2011
@@ -40,6 +40,36 @@
static KSPIN_LOCK SpinLock;
+typedef struct
+{
+ int esi, edi, ebx, ebp, esp;
+} PROCESSOR_STATE, *PPROCESSOR_STATE;
+
+#if defined(_MSC_VER) && defined(_M_IX86)
+#define SaveState(State) do \
+{ \
+ __asm lea ecx, [State] \
+ __asm mov [ecx], esi \
+ __asm mov [ecx+4], edi \
+ __asm mov [ecx+8], ebx \
+ __asm mov [ecx+12], ebp \
+ __asm mov [ecx+16], esp \
+} while (0)
+
+#define CheckState(OldState, NewState) do \
+{ \
+ ok_eq_hex((OldState)->esi, (NewState)->esi); \
+ ok_eq_hex((OldState)->edi, (NewState)->edi); \
+ ok_eq_hex((OldState)->ebx, (NewState)->ebx); \
+ ok_eq_hex((OldState)->ebp, (NewState)->ebp); \
+ ok_eq_hex((OldState)->esp, (NewState)->esp); \
+} while (0)
+
+#else
+#define SaveState(State)
+#define CheckState(OldState, NewState)
+#endif
+
static
LARGE_INTEGER
Large(
@@ -57,7 +87,10 @@
Type Value##Type = Val; \
Status = STATUS_SUCCESS; \
_SEH2_TRY { \
+ SaveState(OldState); \
Ret##Type = Function(&Value##Type, Xchg, Cmp, ##__VA_ARGS__); \
+ SaveState(NewState); \
+ CheckState(&OldState, &NewState); \
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
Status = _SEH2_GetExceptionCode(); \
} _SEH2_END; \
@@ -75,8 +108,11 @@
Type Exchange##Type = Xchg; \
Status = STATUS_SUCCESS; \
_SEH2_TRY { \
+ SaveState(OldState); \
Ret##Type = Function(&Value##Type, &Exchange##Type, \
&Compare##Type, ##__VA_ARGS__); \
+ SaveState(NewState); \
+ CheckState(&OldState, &NewState); \
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
Status = _SEH2_GetExceptionCode(); \
} _SEH2_END; \
@@ -94,7 +130,10 @@
Type Value##Type = Val; \
Status = STATUS_SUCCESS; \
_SEH2_TRY { \
+ SaveState(OldState); \
Ret##Type = Function(&Value##Type, Op, ##__VA_ARGS__); \
+ SaveState(NewState); \
+ CheckState(&OldState, &NewState); \
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
Status = _SEH2_GetExceptionCode(); \
} _SEH2_END; \
@@ -110,7 +149,10 @@
Type Value##Type = Val; \
Status = STATUS_SUCCESS; \
_SEH2_TRY { \
+ SaveState(OldState); \
Ret##Type = Function(&Value##Type, ##__VA_ARGS__); \
+ SaveState(NewState); \
+ CheckState(&OldState, &NewState); \
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
Status = _SEH2_GetExceptionCode(); \
} _SEH2_END; \
@@ -126,7 +168,10 @@
Type Value##Type = Val; \
Status = STATUS_SUCCESS; \
_SEH2_TRY { \
+ SaveState(OldState); \
Ret##Type = Function(&Value##Type, Op, ##__VA_ARGS__); \
+ SaveState(NewState); \
+ CheckState(&OldState, &NewState); \
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
Status = _SEH2_GetExceptionCode(); \
} _SEH2_END; \
@@ -141,7 +186,10 @@
Type Value##Type = Val; \
Status = STATUS_SUCCESS; \
_SEH2_TRY { \
+ SaveState(OldState); \
Function(&Value##Type, Op, ##__VA_ARGS__); \
+ SaveState(NewState); \
+ CheckState(&OldState, &NewState); \
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { \
Status = _SEH2_GetExceptionCode(); \
} _SEH2_END; \
@@ -163,6 +211,7 @@
{
NTSTATUS Status;
PKSPIN_LOCK pSpinLock = &SpinLock;
+ PROCESSOR_STATE OldState, NewState;
/* on x86, most of these are supported intrinsicly and don't need a spinlock! */
#if defined _M_IX86 || defined _M_AMD64
Modified: branches/GSoC_2011/KMTestSuite/kmtests/ntos_ex/ExResource.c
URL:
http://svn.reactos.org/svn/reactos/branches/GSoC_2011/KMTestSuite/kmtests/n…
==============================================================================
--- branches/GSoC_2011/KMTestSuite/kmtests/ntos_ex/ExResource.c [iso-8859-1] (original)
+++ branches/GSoC_2011/KMTestSuite/kmtests/ntos_ex/ExResource.c [iso-8859-1] Wed Jul 13
21:17:55 2011
@@ -15,6 +15,8 @@
//#define NDEBUG
#include <debug.h>
+
+/* 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!
* This declaration can be removed once ROS headers are corrected */
@@ -39,15 +41,15 @@
KSPIN_LOCK SpinLock;
} ERESOURCE_2K3, *PERESOURCE_2K3;
-#define CheckResourceFields(Res) do
\
+#define CheckResourceFields(Res, Reinit) do
\
{
\
ok_eq_pointer((Res)->SystemResourcesList.Flink->Blink,
&(Res)->SystemResourcesList); \
ok_eq_pointer((Res)->SystemResourcesList.Blink->Flink,
&(Res)->SystemResourcesList); \
- ok_eq_pointer((Res)->OwnerTable, NULL);
\
+ if (!Reinit) ok_eq_pointer((Res)->OwnerTable, NULL);
\
ok_eq_int((Res)->ActiveCount, 0);
\
ok_eq_uint((Res)->Flag, 0);
\
- ok_eq_pointer((Res)->SharedWaiters, NULL);
\
- ok_eq_pointer((Res)->ExclusiveWaiters, NULL);
\
+ if (!Reinit) ok_eq_pointer((Res)->SharedWaiters, NULL);
\
+ if (!Reinit) ok_eq_pointer((Res)->ExclusiveWaiters, NULL);
\
ok_eq_pointer((PVOID)(Res)->OwnerThreads[0].OwnerThread, NULL);
\
ok_eq_ulong((Res)->OwnerThreads[0].TableSize, 0LU);
\
ok_eq_pointer((PVOID)(Res)->OwnerThreads[1].OwnerThread, NULL);
\
@@ -206,6 +208,201 @@
CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
}
+typedef BOOLEAN (NTAPI *PACQUIRE_FUNCTION)(PERESOURCE, BOOLEAN);
+
+typedef struct
+{
+ HANDLE Handle;
+ PKTHREAD Thread;
+ PERESOURCE Res;
+ KEVENT InEvent;
+ KEVENT OutEvent;
+ PACQUIRE_FUNCTION AcquireResource;
+ BOOLEAN Wait;
+ BOOLEAN RetExpected;
+} THREAD_DATA, *PTHREAD_DATA;
+
+static
+VOID
+NTAPI
+AcquireResourceThread(
+ 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");
+
+ ok_bool_false(KeSetEvent(&ThreadData->OutEvent, 0, TRUE), "KeSetEvent
returned");
+ Status = KeWaitForSingleObject(&ThreadData->InEvent, Executive, KernelMode,
FALSE, NULL);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+
+ if (Ret)
+ ExReleaseResource(ThreadData->Res);
+ KeLeaveCriticalRegion();
+}
+
+static
+VOID
+InitThreadData(
+ PTHREAD_DATA ThreadData,
+ PERESOURCE Res,
+ PACQUIRE_FUNCTION AcquireFunction)
+{
+ ThreadData->Res = Res;
+ KeInitializeEvent(&ThreadData->InEvent, NotificationEvent, FALSE);
+ KeInitializeEvent(&ThreadData->OutEvent, NotificationEvent, FALSE);
+ ThreadData->AcquireResource = AcquireFunction;
+}
+
+static
+NTSTATUS
+StartThread(
+ PTHREAD_DATA ThreadData,
+ PLARGE_INTEGER Timeout,
+ BOOLEAN Wait,
+ BOOLEAN RetExpected)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ OBJECT_ATTRIBUTES Attributes;
+
+ 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);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ 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);
+}
+
+static
+VOID
+FinishThread(
+ PTHREAD_DATA ThreadData)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ KeSetEvent(&ThreadData->InEvent, 0, TRUE);
+ Status = KeWaitForSingleObject(ThreadData->Thread, Executive, KernelMode, FALSE,
NULL);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+
+ ObDereferenceObject(ThreadData->Thread);
+ Status = ZwClose(ThreadData->Handle);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ KeClearEvent(&ThreadData->InEvent);
+ KeClearEvent(&ThreadData->OutEvent);
+}
+
+static
+VOID
+TestResourceWithThreads(
+ IN PERESOURCE Res)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ THREAD_DATA ThreadDataShared;
+ THREAD_DATA ThreadDataShared2;
+ THREAD_DATA ThreadDataExclusive;
+ THREAD_DATA ThreadDataSharedStarve;
+ THREAD_DATA ThreadDataSharedWait;
+ LARGE_INTEGER Timeout;
+ Timeout.QuadPart = -10 * 1000 * 10; /* 10 ms */
+
+ InitThreadData(&ThreadDataShared, Res, ExAcquireResourceSharedLite);
+ InitThreadData(&ThreadDataShared2, Res, ExAcquireResourceSharedLite);
+ InitThreadData(&ThreadDataExclusive, Res, ExAcquireResourceExclusiveLite);
+ InitThreadData(&ThreadDataSharedStarve, Res, ExAcquireSharedStarveExclusive);
+ InitThreadData(&ThreadDataSharedWait, Res, ExAcquireSharedWaitForExclusive);
+
+ /* have a thread acquire the resource shared */
+ Status = StartThread(&ThreadDataShared, NULL, FALSE, TRUE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+ ok_eq_int(Res->ActiveCount, 1);
+
+ /* a second thread should be able to acquire the resource shared */
+ Status = StartThread(&ThreadDataShared2, NULL, FALSE, TRUE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+ ok_eq_int(Res->ActiveCount, 2);
+ FinishThread(&ThreadDataShared2);
+ CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+ ok_eq_int(Res->ActiveCount, 1);
+
+ /* now have a thread that tries to acquire the resource exclusive -- it should fail
*/
+ Status = StartThread(&ThreadDataExclusive, NULL, FALSE, FALSE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+ ok_eq_int(Res->ActiveCount, 1);
+ FinishThread(&ThreadDataExclusive);
+ CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+ ok_eq_int(Res->ActiveCount, 1);
+
+ /* as above, but this time it should block */
+ Status = StartThread(&ThreadDataExclusive, &Timeout, TRUE, TRUE);
+ ok_eq_hex(Status, STATUS_TIMEOUT);
+ CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
+ ok_eq_int(Res->ActiveCount, 1);
+
+ /* now try another shared one -- it should fail */
+ Status = StartThread(&ThreadDataShared2, NULL, FALSE, FALSE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
+ ok_eq_int(Res->ActiveCount, 1);
+ FinishThread(&ThreadDataShared2);
+
+ /* same for ExAcquireSharedWaitForExclusive */
+ Status = StartThread(&ThreadDataSharedWait, NULL, FALSE, FALSE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
+ ok_eq_int(Res->ActiveCount, 1);
+ FinishThread(&ThreadDataSharedWait);
+
+ /* ExAcquireSharedStarveExclusive must get access though! */
+ Status = StartThread(&ThreadDataSharedStarve, NULL, TRUE, TRUE);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
+ ok_eq_int(Res->ActiveCount, 2);
+ FinishThread(&ThreadDataSharedStarve);
+ CheckResourceStatus(Res, FALSE, 0LU, 1LU, 0LU);
+ ok_eq_int(Res->ActiveCount, 1);
+
+ /* block another shared one */
+ Status = StartThread(&ThreadDataShared2, &Timeout, TRUE, TRUE);
+ ok_eq_hex(Status, STATUS_TIMEOUT);
+ CheckResourceStatus(Res, FALSE, 0LU, 1LU, 1LU);
+ ok_eq_int(Res->ActiveCount, 1);
+
+ /* finish the very first one */
+ FinishThread(&ThreadDataShared);
+
+ /* now the blocked exclusive one should get the resource */
+ Status = KeWaitForSingleObject(&ThreadDataExclusive.OutEvent, Executive,
KernelMode, FALSE, NULL);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ CheckResourceStatus(Res, FALSE, 0LU, 0LU, 1LU);
+ ok_eq_int(Res->ActiveCount, 1);
+ ok_eq_uint((Res->Flag & ResourceOwnedExclusive) != 0, 1);
+
+ FinishThread(&ThreadDataExclusive);
+ CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+
+ /* now the blocked shared one should resume */
+ Status = KeWaitForSingleObject(&ThreadDataShared2.OutEvent, Executive,
KernelMode, FALSE, NULL);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+ CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+ ok_eq_int(Res->ActiveCount, 1);
+ FinishThread(&ThreadDataShared2);
+ CheckResourceStatus(Res, FALSE, 0LU, 0LU, 0LU);
+ ok_eq_int(Res->ActiveCount, 0);
+}
+
START_TEST(ExResource)
{
NTSTATUS Status;
@@ -228,7 +425,7 @@
memset(&Res, 0x55, sizeof Res);
Status = ExInitializeResourceLite(&Res);
ok_eq_hex(Status, STATUS_SUCCESS);
- CheckResourceFields((PERESOURCE_2K3)&Res);
+ CheckResourceFields((PERESOURCE_2K3)&Res, FALSE);
CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
@@ -246,10 +443,12 @@
ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
+ TestResourceWithThreads(&Res);
+
/* ExReinitializeResourceLite cleans up after us */
Status = ExReinitializeResourceLite(&Res);
ok_eq_hex(Status, STATUS_SUCCESS);
- CheckResourceFields((PERESOURCE_2K3)&Res);
+ CheckResourceFields((PERESOURCE_2K3)&Res, TRUE);
CheckResourceStatus(&Res, FALSE, 0LU, 0LU, 0LU);
Status = ExDeleteResourceLite(&Res);