FreeRDP
TestSynchAPC.c
1 
19 #include <winpr/wtypes.h>
20 #include <winpr/thread.h>
21 #include <winpr/synch.h>
22 
23 typedef struct
24 {
25  BOOL error;
26  BOOL called;
27 } UserApcArg;
28 
29 static void CALLBACK userApc(ULONG_PTR arg)
30 {
31  UserApcArg* userArg = (UserApcArg*)arg;
32  userArg->called = TRUE;
33 }
34 
35 static 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 
48 static DWORD WINAPI cleanThread(LPVOID lpThreadParameter)
49 {
50  Sleep(500);
51 
52  SleepEx(500, TRUE);
53  return 0;
54 }
55 
56 typedef struct
57 {
58  HANDLE timer1;
59  DWORD timer1Calls;
60  HANDLE timer2;
61  DWORD timer2Calls;
62  BOOL endTest;
63 } UncleanCloseData;
64 
65 static 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 
73 static VOID CALLBACK Timer2APCProc(LPVOID lpArg, DWORD dwTimerLowValue, DWORD dwTimerHighValue)
74 {
75  UncleanCloseData* data = (UncleanCloseData*)lpArg;
76  data->timer2Calls++;
77 }
78 
79 static 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 
100 int 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 #if 0
151  /* test cleanup of timer completions */
152  memset(&uncleanCloseData, 0, sizeof(uncleanCloseData));
153  uncleanCloseData.timer1 = CreateWaitableTimerA(NULL, FALSE, NULL);
154  if (!uncleanCloseData.timer1)
155  return 31;
156 
157  uncleanCloseData.timer2 = CreateWaitableTimerA(NULL, FALSE, NULL);
158  if (!uncleanCloseData.timer2)
159  return 32;
160 
161  thread = CreateThread(NULL, 0, closeHandleTest, &uncleanCloseData, 0, NULL);
162  if (!thread)
163  return 33;
164 
165  (void)WaitForSingleObject(thread, INFINITE);
166 (void)CloseHandle(thread);
167 
168  if (uncleanCloseData.timer1Calls != 1 || uncleanCloseData.timer2Calls != 0)
169  return 34;
170 (void)CloseHandle(uncleanCloseData.timer1);
171 #endif
172  return 0;
173 }