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/ntos_ex/ExInterlocked.c?rev=52674&r1=52673&r2=52674&view=diff
==============================================================================
--- 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/ntos_ex/ExResource.c?rev=52674&r1=52673&r2=52674&view=diff
==============================================================================
--- 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);


Reply via email to