FreeRDP
Loading...
Searching...
No Matches
TestSynchAPC.c
1
19#include <winpr/wtypes.h>
20#include <winpr/thread.h>
21#include <winpr/synch.h>
22
23typedef struct
24{
25 BOOL error;
26 BOOL called;
27} UserApcArg;
28
29static void CALLBACK userApc(ULONG_PTR arg)
30{
31 UserApcArg* userArg = (UserApcArg*)arg;
32 userArg->called = TRUE;
33}
34
35static DWORD WINAPI uncleanThread(LPVOID lpThreadParameter)
36{
37 /* this thread post an APC that will never get executed */
38 UserApcArg* userArg = (UserApcArg*)lpThreadParameter;
39 if (!QueueUserAPC((PAPCFUNC)userApc, _GetCurrentThread(), (ULONG_PTR)lpThreadParameter))
40 {
41 userArg->error = TRUE;
42 return 1;
43 }
44
45 return 0;
46}
47
48static DWORD WINAPI cleanThread(LPVOID lpThreadParameter)
49{
50 Sleep(500);
51
52 SleepEx(500, TRUE);
53 return 0;
54}
55
56typedef struct
57{
58 HANDLE timer1;
59 DWORD timer1Calls;
60 HANDLE timer2;
61 DWORD timer2Calls;
62 BOOL endTest;
63} UncleanCloseData;
64
65static VOID CALLBACK Timer1APCProc(LPVOID lpArg, DWORD dwTimerLowValue, DWORD dwTimerHighValue)
66{
67 UncleanCloseData* data = (UncleanCloseData*)lpArg;
68 data->timer1Calls++;
69 (void)CloseHandle(data->timer2);
70 data->endTest = TRUE;
71}
72
73static VOID CALLBACK Timer2APCProc(LPVOID lpArg, DWORD dwTimerLowValue, DWORD dwTimerHighValue)
74{
75 UncleanCloseData* data = (UncleanCloseData*)lpArg;
76 data->timer2Calls++;
77}
78
79static DWORD /*WINAPI*/ closeHandleTest(LPVOID lpThreadParameter)
80{
81 LARGE_INTEGER dueTime = { 0 };
82 UncleanCloseData* data = (UncleanCloseData*)lpThreadParameter;
83 data->endTest = FALSE;
84
85 dueTime.QuadPart = -500;
86 if (!SetWaitableTimer(data->timer1, &dueTime, 0, Timer1APCProc, lpThreadParameter, FALSE))
87 return 1;
88
89 dueTime.QuadPart = -900;
90 if (!SetWaitableTimer(data->timer2, &dueTime, 0, Timer2APCProc, lpThreadParameter, FALSE))
91 return 1;
92
93 while (!data->endTest)
94 {
95 SleepEx(100, TRUE);
96 }
97 return 0;
98}
99
100int TestSynchAPC(int argc, char* argv[])
101{
102 HANDLE thread = NULL;
103 UserApcArg userApcArg;
104
105 userApcArg.error = FALSE;
106 userApcArg.called = FALSE;
107
108 WINPR_UNUSED(argc);
109 WINPR_UNUSED(argv);
110
111 /* first post an APC and check it is executed during a SleepEx */
112 if (!QueueUserAPC((PAPCFUNC)userApc, _GetCurrentThread(), (ULONG_PTR)&userApcArg))
113 return 1;
114
115 if (SleepEx(100, FALSE) != 0)
116 return 2;
117
118 if (SleepEx(100, TRUE) != WAIT_IO_COMPLETION)
119 return 3;
120
121 if (!userApcArg.called)
122 return 4;
123
124 userApcArg.called = FALSE;
125
126 /* test that the APC is cleaned up even when not called */
127 thread = CreateThread(NULL, 0, uncleanThread, &userApcArg, 0, NULL);
128 if (!thread)
129 return 10;
130 (void)WaitForSingleObject(thread, INFINITE);
131 (void)CloseHandle(thread);
132
133 if (userApcArg.called || userApcArg.error)
134 return 11;
135
136 /* test a remote APC queuing */
137 thread = CreateThread(NULL, 0, cleanThread, &userApcArg, 0, NULL);
138 if (!thread)
139 return 20;
140
141 if (!QueueUserAPC((PAPCFUNC)userApc, thread, (ULONG_PTR)&userApcArg))
142 return 21;
143
144 (void)WaitForSingleObject(thread, INFINITE);
145 (void)CloseHandle(thread);
146
147 if (!userApcArg.called)
148 return 22;
149
150 return 0;
151}