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: test6.c
8**
9** Dependencies: PAL_Initialize
10** PAL_Terminate
11** CreateEvent
12** SetEvent
13** CreateThread
14** ResumeThread
15** WaitForMultipleObjectsEx
16** CloseHandle
17**
18** Purpose:
19**
20** Test to ensure proper operation of the QueueUserAPC()
21** API by trying to queue APC functions on a thread that
22** has already terminated.
23**
24**
25**===========================================================================*/
26#include <palsuite.h>
27
28
29static BOOL bAPCExecuted = FALSE;
30
31VOID PALAPI APCFunc( ULONG_PTR dwParam )
32{
33 bAPCExecuted = TRUE;
34}
35
36/**
37 * ThreadFunc
38 *
39 * Dummy thread function for APC queuing.
40 */
41DWORD PALAPI ThreadFunc( LPVOID param )
42{
43 int i;
44
45 /* simulate some activity */
46 for( i=0; i<250000; i++ )
47 ;
48
49 return 0;
50}
51
52
53int __cdecl main( int argc, char **argv )
54
55{
56 /* local variables */
57 HANDLE hThread = NULL;
58 DWORD IDThread;
59 DWORD ret;
60
61 /* PAL initialization */
62 if( (PAL_Initialize(argc, argv)) != 0 )
63 {
64 return( FAIL );
65 }
66
67 /* run another dummy thread to cause notification of the library */
68 hThread = CreateThread( NULL, /* no security attributes */
69 0, /* use default stack size */
70 (LPTHREAD_START_ROUTINE) ThreadFunc, /* thread function */
71 (LPVOID) NULL, /* pass thread index as */
72 /* function argument */
73 CREATE_SUSPENDED, /* create suspended */
74 &IDThread ); /* returns thread id */
75
76 /* Check the return value for success. */
77 if( hThread == NULL )
78 {
79 /* error creating thread */
80 Fail( "ERROR:%lu:CreateThread call failed\n", GetLastError() );
81 }
82
83 /* Resume the suspended thread */
84 ResumeThread( hThread );
85
86 /* wait on the other thread to complete */
87 ret = WaitForSingleObject( hThread, INFINITE );
88 if( ret != WAIT_OBJECT_0 )
89 {
90 Trace( "ERROR:WaitForSingleObject() returned %lu, "
91 "expected WAIT_OBJECT_0\n",
92 ret );
93 if( ! CloseHandle( hThread ) )
94 {
95 Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
96 }
97 Fail( "test failed\n" );
98 }
99
100 /* queue our APC on the finished thread */
101 ret = QueueUserAPC( APCFunc, hThread, 0 );
102 if( ret != 0 )
103 {
104 Trace( "ERROR:QueueUserAPC call succeeded on a terminated thread\n" );
105 if( ! CloseHandle( hThread ) )
106 {
107 Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
108 }
109 Fail( "test failed\n" );
110 }
111
112 if( ! CloseHandle( hThread ) )
113 {
114 Fail( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
115 }
116
117 /* dummy check that the APC function wasn't actually executed */
118 if( bAPCExecuted != FALSE )
119 {
120 Fail( "ERROR:APC function was executed\n" );
121 }
122
123
124 /* PAL termination */
125 PAL_Terminate();
126
127 /* return success */
128 return PASS;
129}
130