1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*=====================================================================
6**
7** Source: test2.c
8**
9** Purpose: Tests that APCs are not executed if a thread never enters an
10** alertable state after they are queued.
11**
12**
13**===================================================================*/
14
15#include <palsuite.h>
16
17const int ChildThreadSleepTime = 2000;
18const int InterruptTime = 1000;
19
20DWORD ChildThread;
21BOOL InAPC;
22
23/* synchronization events */
24static HANDLE hSyncEvent1 = NULL;
25static HANDLE hSyncEvent2 = NULL;
26
27/* thread result because we have no GetExitCodeThread() API */
28static BOOL bThreadResult = FAIL;
29
30
31VOID PALAPI APCFunc(ULONG_PTR dwParam)
32{
33 InAPC = TRUE;
34}
35
36DWORD PALAPI SleeperProc(LPVOID lpParameter)
37{
38 DWORD ret;
39
40 /* signal the main thread that we're ready to proceed */
41 if( ! SetEvent( hSyncEvent1 ) )
42 {
43 Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
44 bThreadResult = FAIL;
45 goto done;
46 }
47
48 /* wait for notification from the main thread */
49 ret = WaitForSingleObject( hSyncEvent2, 20000 );
50 if( ret != WAIT_OBJECT_0 )
51 {
52 Trace( "ERROR:WaitForSingleObject() returned %lu, "
53 "expected WAIT_OBJECT_0\n",
54 ret );
55 bThreadResult = FAIL;
56 goto done;
57 }
58
59 /* call our sleep function */
60 Sleep( ChildThreadSleepTime );
61
62 /* success if we reach here */
63 bThreadResult = PASS;
64
65
66done:
67
68 /* signal the main thread that we're finished */
69 if( ! SetEvent( hSyncEvent1 ) )
70 {
71 Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
72 bThreadResult = FAIL;
73 }
74
75 /* return success or failure */
76 return bThreadResult;
77}
78
79
80int __cdecl main (int argc, char **argv)
81{
82 /* local variables */
83 HANDLE hThread = 0;
84 int ret;
85 BOOL bResult = FAIL;
86
87 /* initialize the PAL */
88 if (0 != (PAL_Initialize(argc, argv)))
89 {
90 return FAIL;
91 }
92
93 InAPC = FALSE;
94
95 /* create a pair of synchronization events to coordinate our threads */
96 hSyncEvent1 = CreateEvent( NULL, FALSE, FALSE, NULL );
97 if( hSyncEvent1 == NULL )
98 {
99 Trace( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
100 goto cleanup;
101 }
102
103 hSyncEvent2 = CreateEvent( NULL, FALSE, FALSE, NULL );
104 if( hSyncEvent2 == NULL )
105 {
106 Trace( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
107 goto cleanup;
108 }
109
110 /* create a child thread */
111 hThread = CreateThread( NULL,
112 0,
113 (LPTHREAD_START_ROUTINE)SleeperProc,
114 0,
115 0,
116 &ChildThread);
117
118 if (hThread == NULL)
119 {
120 Trace( "ERROR:%lu:CreateThread() call failed\n",
121 GetLastError());
122 goto cleanup;
123 }
124
125
126 /* wait on our synchronization event to ensure the thread is running */
127 ret = WaitForSingleObject( hSyncEvent1, 20000 );
128 if( ret != WAIT_OBJECT_0 )
129 {
130 Trace( "ERROR:WaitForSingleObject() returned %lu, "
131 "expected WAIT_OBJECT_0\n",
132 ret );
133 goto cleanup;
134 }
135
136 /* queue a user APC on the child thread */
137 ret = QueueUserAPC(APCFunc, hThread, 0);
138 if (ret == 0)
139 {
140 Trace( "ERROR:%lu:QueueUserAPC() call failed\n",
141 GetLastError());
142 goto cleanup;
143 }
144
145 /* signal the child thread to continue */
146 if( ! SetEvent( hSyncEvent2 ) )
147 {
148 Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
149 goto cleanup;
150 }
151
152 /* wait on our synchronization event to ensure the other thread is done */
153 ret = WaitForSingleObject( hSyncEvent1, 20000 );
154 if( ret != WAIT_OBJECT_0 )
155 {
156 Trace( "ERROR:WaitForSingleObject() returned %lu, "
157 "expected WAIT_OBJECT_0\n",
158 ret );
159 goto cleanup;
160 }
161
162 /* check that the thread executed successfully */
163 if( bThreadResult == FAIL )
164 {
165 goto cleanup;
166 }
167
168
169 /* check whether the APC function was executed */
170 if( InAPC )
171 {
172 Trace( "FAIL:APC function was executed but shouldn't have been\n" );
173 goto cleanup;
174 }
175
176 /* success if we reach here */
177 bResult = PASS;
178
179
180cleanup:
181 /* wait for the other thread to finish */
182 if( hThread != NULL )
183 {
184 ret = WaitForSingleObject( hThread, INFINITE );
185 if (ret == WAIT_FAILED)
186 {
187 Trace( "ERROR:%lu:WaitForSingleObject() returned %lu, "
188 "expected WAIT_OBJECT_0\n",
189 ret );
190 bResult = FAIL;
191 }
192 }
193
194 /* close our synchronization handles */
195 if( hSyncEvent1 != NULL )
196 {
197 if( ! CloseHandle( hSyncEvent1 ) )
198 {
199 Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
200 bResult = FAIL;
201 }
202 }
203
204 if( hSyncEvent2 != NULL )
205 {
206 if( ! CloseHandle( hSyncEvent2 ) )
207 {
208 Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
209 bResult = FAIL;
210 }
211 }
212
213 if( bResult == FAIL )
214 {
215 Fail( "test failed\n" );
216 }
217
218
219 /* terminate the PAL */
220 PAL_Terminate();
221
222 /* return success */
223 return PASS;
224}
225