[KMTESTS]
[reactos.git] / rostests / kmtests / ntos_ke / KeMutex.c
1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Mutant/Mutex test
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
6 */
7
8 #include <kmt_test.h>
9
10 static
11 _IRQL_requires_min_(PASSIVE_LEVEL)
12 _IRQL_requires_max_(DISPATCH_LEVEL)
13 BOOLEAN
14 (NTAPI
15 *pKeAreAllApcsDisabled)(VOID);
16
17 #define ULONGS_PER_POINTER (sizeof(PVOID) / sizeof(ULONG))
18 #define MUTANT_SIZE (2 + 6 * ULONGS_PER_POINTER)
19
20 C_ASSERT(sizeof(DISPATCHER_HEADER) == 8 + 2 * sizeof(PVOID));
21 C_ASSERT(sizeof(KMUTANT) == sizeof(DISPATCHER_HEADER) + 3 * sizeof(PVOID) + sizeof(PVOID));
22 C_ASSERT(sizeof(KMUTANT) == MUTANT_SIZE * sizeof(ULONG));
23
24 #define CheckMutex(Mutex, Held, New, ExpectedApcDisable) do { \
25 PKTHREAD Thread = KeGetCurrentThread(); \
26 ok_eq_uint((Mutex)->Header.Type, MutantObject); \
27 ok_eq_uint((Mutex)->Header.Abandoned, 0x55); \
28 ok_eq_uint((Mutex)->Header.Size, MUTANT_SIZE); \
29 ok_eq_uint((Mutex)->Header.DpcActive, 0x55); \
30 ok_eq_pointer((Mutex)->Header.WaitListHead.Flink, \
31 &(Mutex)->Header.WaitListHead); \
32 ok_eq_pointer((Mutex)->Header.WaitListHead.Blink, \
33 &(Mutex)->Header.WaitListHead); \
34 if (Held) \
35 { \
36 ok_eq_long((Mutex)->Header.SignalState, 0); \
37 ok_eq_pointer((Mutex)->MutantListEntry.Flink, &Thread->MutantListHead); \
38 ok_eq_pointer((Mutex)->MutantListEntry.Blink, &Thread->MutantListHead); \
39 ok_eq_pointer(Thread->MutantListHead.Flink, &(Mutex)->MutantListEntry); \
40 ok_eq_pointer(Thread->MutantListHead.Blink, &(Mutex)->MutantListEntry); \
41 ok_eq_pointer((Mutex)->OwnerThread, Thread); \
42 } \
43 else \
44 { \
45 ok_eq_long((Mutex)->Header.SignalState, 1); \
46 if (New) \
47 { \
48 ok_eq_pointer((Mutex)->MutantListEntry.Flink, \
49 (PVOID)0x5555555555555555ULL); \
50 ok_eq_pointer((Mutex)->MutantListEntry.Blink, \
51 (PVOID)0x5555555555555555ULL); \
52 } \
53 ok_eq_pointer(Thread->MutantListHead.Flink, &Thread->MutantListHead); \
54 ok_eq_pointer(Thread->MutantListHead.Blink, &Thread->MutantListHead); \
55 ok_eq_pointer((Mutex)->OwnerThread, NULL); \
56 } \
57 ok_eq_uint((Mutex)->Abandoned, 0); \
58 ok_eq_uint((Mutex)->ApcDisable, ExpectedApcDisable); \
59 } while (0)
60
61 #define CheckApcs(KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, Irql) do \
62 { \
63 ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled); \
64 ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled); \
65 if (pKeAreAllApcsDisabled) \
66 ok_eq_bool(pKeAreAllApcsDisabled(), AllApcsDisabled); \
67 ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled); \
68 ok_irql(Irql); \
69 } while (0)
70
71 static
72 VOID
73 TestMutant(VOID)
74 {
75 NTSTATUS Status;
76 KMUTANT Mutant;
77 LONG State;
78 PKTHREAD Thread = KeGetCurrentThread();
79
80 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
81 RtlFillMemory(&Mutant, sizeof(Mutant), 0x55);
82 KeInitializeMutant(&Mutant, FALSE);
83 CheckMutex(&Mutant, FALSE, TRUE, 0);
84 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
85
86 RtlFillMemory(&Mutant, sizeof(Mutant), 0x55);
87 KeInitializeMutant(&Mutant, TRUE);
88 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
89 CheckMutex(&Mutant, TRUE, TRUE, 0);
90 State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
91 ok_eq_long(State, 0);
92 CheckMutex(&Mutant, FALSE, FALSE, 0);
93 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
94
95 /* Acquire and release */
96 Status = KeWaitForSingleObject(&Mutant,
97 Executive,
98 KernelMode,
99 FALSE,
100 NULL);
101 ok_eq_hex(Status, STATUS_SUCCESS);
102 CheckMutex(&Mutant, TRUE, TRUE, 0);
103 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
104
105 State = KeReleaseMutant(&Mutant, 1, FALSE, FALSE);
106 ok_eq_long(State, 0);
107 CheckMutex(&Mutant, FALSE, FALSE, 0);
108 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
109 }
110
111 static
112 VOID
113 TestMutex(VOID)
114 {
115 NTSTATUS Status;
116 KMUTEX Mutex;
117 LONG State;
118 PKTHREAD Thread = KeGetCurrentThread();
119
120 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
121 RtlFillMemory(&Mutex, sizeof(Mutex), 0x55);
122 KeInitializeMutex(&Mutex, 0);
123 CheckMutex(&Mutex, FALSE, TRUE, 1);
124 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
125
126 RtlFillMemory(&Mutex, sizeof(Mutex), 0x55);
127 KeInitializeMutex(&Mutex, 123);
128 CheckMutex(&Mutex, FALSE, TRUE, 1);
129 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
130
131 Status = KeWaitForSingleObject(&Mutex,
132 Executive,
133 KernelMode,
134 FALSE,
135 NULL);
136 ok_eq_hex(Status, STATUS_SUCCESS);
137 CheckMutex(&Mutex, TRUE, FALSE, 1);
138 CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
139
140 State = KeReleaseMutex(&Mutex, FALSE);
141 ok_eq_long(State, 0);
142 CheckMutex(&Mutex, FALSE, FALSE, 1);
143 CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
144 }
145
146 START_TEST(KeMutex)
147 {
148 pKeAreAllApcsDisabled = KmtGetSystemRoutineAddress(L"KeAreAllApcsDisabled");
149 if (skip(pKeAreAllApcsDisabled != NULL, "KeAreAllApcsDisabled unavailable\n"))
150 {
151 /* We can live without this function here */
152 }
153
154 TestMutant();
155 TestMutex();
156 }