1 #include <windows.h>
2 #include <stdio.h>
3 #include <tchar.h>
4 
5 #define N_TIMEOUT	3
6 
7 /*******************************************************************************/
8 
9 typedef struct _TEST *PTEST;
10 
11 typedef VOID (*PFNTEST)(PTEST Test, HANDLE hEvent);
12 
13 typedef struct _TEST
14 {
15   TCHAR *description;
16   BOOL Result;
17   PFNTEST Routine;
18   int id;
19 } TEST;
20 
21 static TEST Tests[3];
22 
23 VOID RunTests(VOID)
24 {
25   int i, nTests;
26   static HANDLE hEvent;
27 
28   hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
29   if(hEvent == NULL)
30   {
31     _tprintf(_T("Unable to create event!"));
32     return;
33   }
34 
35   nTests = sizeof(Tests) / sizeof(TEST);
36 
37   for(i = 0; i < nTests; i++)
38   {
39     Tests[i].id = i + 1;
40 
41     if(Tests[i].Routine == NULL)
42     {
43       continue;
44     }
45 
46     _tprintf(_T("+++ TEST %d: %s\n"), Tests[i].id, Tests[i].description);
47 
48     Tests[i].Routine(&Tests[i], hEvent);
49 
50     WaitForSingleObject(hEvent, INFINITE);
51 
52     _tprintf(_T("\n\n"));
53   }
54 
55   CloseHandle(hEvent);
56 }
57 
58 VOID PrintTestResults(VOID)
59 {
60   int i, nTests, nsuccess = 0, nfailed = 0;
61   TCHAR *status;
62 
63   nTests = sizeof(Tests) / sizeof(TEST);
64 
65   for(i = 0; i < nTests; i++)
66   {
67     if(Tests[i].Routine == NULL)
68     {
69       status = _T("SKIPPED");
70     }
71     else if(Tests[i].Result == TRUE)
72     {
73       status = _T("SUCCESS");
74       nsuccess++;
75     }
76     else
77     {
78       status = _T("FAILED ");
79       nfailed++;
80     }
81 
82     _tprintf(_T("Test %d: %s %s\n"), i, status, Tests[i].description);
83   }
84 
85   _tprintf(_T("\nTests succeeded: %d, failed: %d\n"), nsuccess, nfailed);
86   if(nfailed == 0)
87   {
88     _tprintf(_T("  ALL TESTS SUCCESSFUL!\n"));
89   }
90 }
91 
92 /*******************************************************************************/
93 
94 typedef struct _TESTINFO
95 {
96   PTEST Test;
97   int secsleft;
98   HANDLE hTimer;
99   HANDLE hEvent;
100   /* additional stuff */
101   union
102   {
103     struct
104     {
105       HANDLE Dummy;
106     } Test1;
107     struct
108     {
109       HANDLE hWaitEvent;
110     } Test2;
111     struct
112     {
113       HANDLE hWaitEvent;
114       HANDLE hNotification;
115     } Test3;
116   };
117 } TESTINFO, *PTESTINFO;
118 
119 VOID CALLBACK TimerCallback1(PVOID Param, BOOLEAN Fired)
120 {
121   PTESTINFO Info = (PTESTINFO)Param;
122 
123   _tprintf(_T("[%d]TimerCallback(0x%x, %d) called (%d)\n"), (int)Info->Test->id, (int)Info->hTimer, (int)Fired, --Info->secsleft);
124 
125   if(Info->secsleft == 0)
126   {
127     BOOL stat;
128 
129     _tprintf(_T("[%d]Timout finished, delete timer queue..."), (int)Info->Test->id);
130     stat = DeleteTimerQueueTimer(NULL, Info->hTimer, NULL);
131     if(stat)
132       _tprintf(_T("returned OK -> test FAILED!\n"));
133     else
134     {
135       int error = GetLastError();
136 
137       switch(error)
138       {
139         case ERROR_IO_PENDING:
140           _tprintf(_T("OK, Overlapped I/O operation in progress\n"));
141           /* this test is only successful in this case */
142           Info->Test->Result = TRUE;
143           break;
144         default:
145           _tprintf(_T("Failed, LastError: %d\n"), (int)GetLastError());
146           break;
147       }
148     }
149 
150     /* set the event to continue tests */
151     SetEvent(Info->hEvent);
152   }
153 }
154 
155 VOID Test1(PTEST Test, HANDLE hEvent)
156 {
157   static TESTINFO Info;
158 
159   Info.Test = Test;
160   Info.hEvent = hEvent;
161   Info.secsleft = N_TIMEOUT;
162 
163   if(!CreateTimerQueueTimer(&Info.hTimer, NULL, TimerCallback1, &Info, 1000, 1000, 0))
164   {
165     _tprintf(_T("[%d]CreateTimerQueueTimer() failed, LastError: %d!"), (int)Info.Test->id, (int)GetLastError());
166     /* we failed, set the event to continue tests */
167     SetEvent(hEvent);
168     return;
169   }
170 
171   _tprintf(_T("[%d]CreateTimerQueueTimer() created timer 0x%x, countdown (%d sec)...\n"), (int)Info.Test->id, (int)Info.hTimer, (int)Info.secsleft);
172 }
173 
174 /*******************************************************************************/
175 
176 VOID CALLBACK TimerCallback2(PVOID Param, BOOLEAN Fired)
177 {
178   PTESTINFO Info = (PTESTINFO)Param;
179 
180   _tprintf(_T("[%d]TimerCallback(0x%x, %d) called (%d)\n"), (int)Info->Test->id, (int)Info->hTimer, (int)Fired, --Info->secsleft);
181 
182   if(Info->secsleft == 0)
183   {
184     /* set the event to continue tests */
185     SetEvent(Info->Test2.hWaitEvent);
186 
187     /* sleep a bit */
188     Sleep(1500);
189   }
190 }
191 
192 VOID Test2(PTEST Test, HANDLE hEvent)
193 {
194   static TESTINFO Info;
195   BOOL stat;
196 
197   Info.Test = Test;
198   Info.hEvent = hEvent;
199   Info.secsleft = N_TIMEOUT;
200 
201   Info.Test2.hWaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
202   if(Info.Test2.hWaitEvent == NULL)
203   {
204     _tprintf(_T("[%d]Unable to create event!\n"), (int)Info.Test->id);
205     return;
206   }
207 
208   if(!CreateTimerQueueTimer(&Info.hTimer, NULL, TimerCallback2, &Info, 1000, 1000, 0))
209   {
210     _tprintf(_T("[%d]CreateTimerQueueTimer() failed, LastError: %d!"), (int)Info.Test->id, (int)GetLastError());
211 
212     CloseHandle(Info.Test2.hWaitEvent);
213     /* we failed, set the event to continue tests */
214     SetEvent(hEvent);
215     return;
216   }
217 
218   _tprintf(_T("[%d]CreateTimerQueueTimer() created timer 0x%x, countdown (%d sec)...\n"), (int)Test->id, (int)Info.hTimer, (int)Info.secsleft);
219 
220   WaitForSingleObject(Info.Test2.hWaitEvent, INFINITE);
221 
222   _tprintf(_T("[%d]Timout finished, delete timer queue..."), (int)Test->id);
223   stat = DeleteTimerQueueTimer(NULL, Info.hTimer, INVALID_HANDLE_VALUE);
224   if(stat)
225   {
226     _tprintf(_T("OK\n"));
227     /* this test is only successful in this case */
228     Test->Result = TRUE;
229   }
230   else
231   {
232     int error = GetLastError();
233 
234     switch(error)
235     {
236       case ERROR_IO_PENDING:
237         _tprintf(_T("FAILED, Overlapped I/O operation in progress\n"));
238         break;
239       default:
240         _tprintf(_T("Failed, LastError: %d\n"), (int)GetLastError());
241         break;
242     }
243   }
244 
245   SetEvent(Info.hEvent);
246 }
247 
248 /*******************************************************************************/
249 
250 VOID CALLBACK TimerCallback3(PVOID Param, BOOLEAN Fired)
251 {
252   PTESTINFO Info = (PTESTINFO)Param;
253 
254   _tprintf(_T("[%d]TimerCallback(0x%x, %d) called (%d)\n"), (int)Info->Test->id, (int)Info->hTimer, (int)Fired, --Info->secsleft);
255 
256   if(Info->secsleft == 0)
257   {
258     /* set the event to continue tests */
259     SetEvent(Info->Test3.hWaitEvent);
260 
261     /* sleep a bit */
262     Sleep(1500);
263   }
264 }
265 
266 VOID Test3(PTEST Test, HANDLE hEvent)
267 {
268   static TESTINFO Info;
269   BOOL stat;
270 
271   Info.Test = Test;
272   Info.hEvent = hEvent;
273   Info.secsleft = N_TIMEOUT;
274 
275   Info.Test3.hWaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
276   if(Info.Test3.hWaitEvent == NULL)
277   {
278     _tprintf(_T("[%d]Unable to create event!\n"), (int)Info.Test->id);
279     return;
280   }
281 
282   Info.Test3.hNotification = CreateEvent(NULL, FALSE, FALSE, NULL);
283   if(Info.Test3.hNotification == NULL)
284   {
285     _tprintf(_T("[%d]Unable to create notification event!\n"), (int)Info.Test->id);
286     return;
287   }
288 
289   if(!CreateTimerQueueTimer(&Info.hTimer, NULL, TimerCallback3, &Info, 1000, 1000, 0))
290   {
291     _tprintf(_T("[%d]CreateTimerQueueTimer() failed, LastError: %d!"), (int)Info.Test->id, (int)GetLastError());
292 
293     CloseHandle(Info.Test3.hWaitEvent);
294     CloseHandle(Info.Test3.hNotification);
295     /* we failed, set the event to continue tests */
296     SetEvent(hEvent);
297     return;
298   }
299 
300   _tprintf(_T("[%d]CreateTimerQueueTimer() created timer 0x%x, countdown (%d sec)...\n"), (int)Test->id, (int)Info.hTimer, (int)Info.secsleft);
301 
302   WaitForSingleObject(Info.Test3.hWaitEvent, INFINITE);
303 
304   _tprintf(_T("[%d]Timout finished, delete timer queue..."), (int)Test->id);
305   stat = DeleteTimerQueueTimer(NULL, Info.hTimer, Info.Test3.hNotification);
306   if(stat)
307   {
308     _tprintf(_T("returned OK -> test FAILED!\n"));
309   }
310   else
311   {
312     int error = GetLastError();
313 
314     switch(error)
315     {
316       case ERROR_IO_PENDING:
317         _tprintf(_T("OK, Overlapped I/O operation in progress\n"));
318         /* this test is only successful in this case */
319         Test->Result = TRUE;
320         break;
321       default:
322         _tprintf(_T("Failed, LastError: %d\n"), (int)GetLastError());
323         break;
324     }
325   }
326 
327   WaitForSingleObject(Info.Test3.hNotification, INFINITE);
328 
329   CloseHandle(Info.Test3.hWaitEvent);
330   CloseHandle(Info.Test3.hNotification);
331 
332   SetEvent(Info.hEvent);
333 }
334 
335 /*******************************************************************************/
336 
337 VOID
338 InitTests(VOID)
339 {
340   ZeroMemory(Tests, sizeof(Tests));
341 
342   Tests[0].description = _T("non-blocking DeleteTimerQueueTimer() call from callback");
343   Tests[0].Routine = Test1;
344 
345   Tests[1].description = _T("blocking DeleteTimerQueueTimer() call");
346   Tests[1].Routine = Test2;
347 
348   Tests[2].description = _T("blocking DeleteTimerQueueTimer() call with specified event");
349   Tests[2].Routine = Test3;
350 }
351 
352 int main(int argc, char* argv[])
353 {
354   _tprintf(_T("+++ TimerQueue test running +++\n\n"));
355 
356   InitTests();
357 
358   RunTests();
359 
360   _tprintf(_T("\n+++ RESULTS +++\n"));
361 
362   PrintTestResults();
363 
364   return 0;
365 }
366