Reactos
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
11static LONG s_record_count = 0;
12static DWORD s_record[MAX_RECORD + 1] = { 0 };
13static BOOL s_terminate_all = FALSE;
14
15static 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};
23static const SIZE_T s_expected_count = _countof(s_expected);
24
25static 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
32static 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
51static 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
64static 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
77static VOID NTAPI DoUserAPC1(ULONG_PTR Parameter)
78{
79 ok_int((int)Parameter, 1);
80 AddValueToRecord(4);
81}
82
83static VOID NTAPI DoUserAPC2(ULONG_PTR Parameter)
84{
85 ok_int((int)Parameter, 2);
86 AddValueToRecord(5);
87}
88
89static VOID NTAPI DoUserAPC3(ULONG_PTR Parameter)
90{
91 ok_int((int)Parameter, 3);
92 AddValueToRecord(6);
93 s_terminate_all = TRUE;
94}
95
96static 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
138static void TestForSleepEx(void)
139{
140 JustDoIt(ThreadFunc1);
141}
142
143static void TestForWaitForSingleObjectEx(void)
144{
145 JustDoIt(ThreadFunc2);
146}
147
148static DWORD WINAPI ThreadFunc3(LPVOID arg)
149{
150 return 0;
151}
152
153static 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
180START_TEST(QueueUserAPC)
181{
182 TestForSleepEx();
183 TestForWaitForSingleObjectEx();
184 TestMultipleUserAPCs();
185}