1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
4 * PURPOSE: Tests for QueueUserAPC, SleepEx, WaitForSingleObjectEx etc.
5 * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
6 */
7 #include "precomp.h"
8
9 #define MAX_RECORD 30
10
11 static LONG s_record_count = 0;
12 static DWORD s_record[MAX_RECORD + 1] = { 0 };
13 static BOOL s_terminate_all = FALSE;
14
15 static const DWORD s_expected[] =
16 {
17 0, 1, 7, 8, 4,
18 2, 1, 9, 10, 5,
19 2, 1, 11, 12, 13,
20 6, 2, 3, 14, 15,
21 16
22 };
23 static const SIZE_T s_expected_count = _countof(s_expected);
24
AddValueToRecord(DWORD dwValue)25 static void AddValueToRecord(DWORD dwValue)
26 {
27 LONG next = InterlockedIncrement(&s_record_count) - 1;
28 if (next < MAX_RECORD)
29 s_record[next] = dwValue;
30 }
31
CheckRecord(void)32 static VOID CheckRecord(void)
33 {
34 SIZE_T i, count = min(s_record_count, s_expected_count);
35
36 for (i = 0; i < count; ++i)
37 {
38 ok(s_record[i] == s_expected[i], "s_record[%u]: got %lu vs expected %lu\n",
39 (INT)i, s_record[i], s_expected[i]);
40 }
41
42 count = abs((int)s_record_count - (int)s_expected_count);
43 for (i = 0; i < count; ++i)
44 {
45 ok(s_record_count == s_expected_count,
46 "s_record_count: got %u vs expected %u\n",
47 (int)s_record_count, (int)s_expected_count);
48 }
49 }
50
ThreadFunc1(LPVOID arg)51 static DWORD WINAPI ThreadFunc1(LPVOID arg)
52 {
53 AddValueToRecord(0);
54 while (!s_terminate_all)
55 {
56 AddValueToRecord(1);
57 ok_long(SleepEx(INFINITE, TRUE), WAIT_IO_COMPLETION);
58 AddValueToRecord(2);
59 }
60 AddValueToRecord(3);
61 return 0;
62 }
63
ThreadFunc2(LPVOID arg)64 static DWORD WINAPI ThreadFunc2(LPVOID arg)
65 {
66 AddValueToRecord(0);
67 while (!s_terminate_all)
68 {
69 AddValueToRecord(1);
70 ok_long(WaitForSingleObjectEx(GetCurrentThread(), INFINITE, TRUE), WAIT_IO_COMPLETION);
71 AddValueToRecord(2);
72 }
73 AddValueToRecord(3);
74 return 0;
75 }
76
DoUserAPC1(ULONG_PTR Parameter)77 static VOID NTAPI DoUserAPC1(ULONG_PTR Parameter)
78 {
79 ok_int((int)Parameter, 1);
80 AddValueToRecord(4);
81 }
82
DoUserAPC2(ULONG_PTR Parameter)83 static VOID NTAPI DoUserAPC2(ULONG_PTR Parameter)
84 {
85 ok_int((int)Parameter, 2);
86 AddValueToRecord(5);
87 }
88
DoUserAPC3(ULONG_PTR Parameter)89 static VOID NTAPI DoUserAPC3(ULONG_PTR Parameter)
90 {
91 ok_int((int)Parameter, 3);
92 AddValueToRecord(6);
93 s_terminate_all = TRUE;
94 }
95
JustDoIt(LPTHREAD_START_ROUTINE fn)96 static void JustDoIt(LPTHREAD_START_ROUTINE fn)
97 {
98 HANDLE hThread;
99 DWORD dwThreadId;
100
101 s_terminate_all = FALSE;
102 s_record_count = 0;
103 ZeroMemory(s_record, sizeof(s_record));
104
105 hThread = CreateThread(NULL, 0, fn, NULL, 0, &dwThreadId);
106 ok(hThread != NULL, "hThread was NULL\n");
107
108 Sleep(100);
109
110 AddValueToRecord(7);
111 ok_long(QueueUserAPC(DoUserAPC1, hThread, 1), 1);
112 AddValueToRecord(8);
113
114 Sleep(100);
115
116 AddValueToRecord(9);
117 ok_long(QueueUserAPC(DoUserAPC2, hThread, 2), 1);
118 AddValueToRecord(10);
119
120 Sleep(100);
121
122 AddValueToRecord(11);
123 ok_long(QueueUserAPC(DoUserAPC3, hThread, 3), 1);
124 AddValueToRecord(12);
125
126 AddValueToRecord(13);
127 ok_long(WaitForSingleObject(hThread, 5 * 1000), WAIT_OBJECT_0);
128 AddValueToRecord(14);
129
130 AddValueToRecord(15);
131 ok_int(CloseHandle(hThread), TRUE);
132 hThread = NULL;
133 AddValueToRecord(16);
134
135 CheckRecord();
136 }
137
TestForSleepEx(void)138 static void TestForSleepEx(void)
139 {
140 JustDoIt(ThreadFunc1);
141 }
142
TestForWaitForSingleObjectEx(void)143 static void TestForWaitForSingleObjectEx(void)
144 {
145 JustDoIt(ThreadFunc2);
146 }
147
ThreadFunc3(LPVOID arg)148 static DWORD WINAPI ThreadFunc3(LPVOID arg)
149 {
150 return 0;
151 }
152
TestMultipleUserAPCs(void)153 static void TestMultipleUserAPCs(void)
154 {
155 HANDLE hThread;
156 DWORD dwThreadId;
157
158 s_record_count = 0;
159
160 hThread = CreateThread(NULL, 0, ThreadFunc3, NULL, CREATE_SUSPENDED, &dwThreadId);
161 ok(hThread != NULL, "hThread was NULL\n");
162
163 ok_long(QueueUserAPC(DoUserAPC1, hThread, 1), 1);
164 ok_long(QueueUserAPC(DoUserAPC2, hThread, 2), 1);
165 ok_long(QueueUserAPC(DoUserAPC3, hThread, 3), 1);
166
167 ok_long(s_record_count, 0);
168
169 ResumeThread(hThread);
170
171 ok_long(WaitForSingleObject(hThread, 5 * 1000), WAIT_OBJECT_0);
172 ok_int(CloseHandle(hThread), TRUE);
173
174 ok_long(s_record_count, 3);
175 ok_long(s_record[0], 4);
176 ok_long(s_record[1], 5);
177 ok_long(s_record[2], 6);
178 }
179
START_TEST(QueueUserAPC)180 START_TEST(QueueUserAPC)
181 {
182 TestForSleepEx();
183 TestForWaitForSingleObjectEx();
184 TestMultipleUserAPCs();
185 }
186