1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite Executive Regressions KM-Test
5  * PROGRAMMER:      Aleksey Bragin <aleksey@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 
10 #define NDEBUG
11 #include <debug.h>
12 
13 static
14 VOID
15 NTAPI
16 TestTimerApcRoutine(IN PVOID TimerContext,
17                     IN ULONG TimerLowValue,
18                     IN LONG TimerHighValue)
19 
20 {
21     ULONG *ApcCount = (ULONG *)TimerContext;
22     DPRINT("Timer Apc called!\n");
23     (*ApcCount)++;
24 }
25 
26 START_TEST(ExTimer)
27 {
28     UNICODE_STRING TimerName;
29     OBJECT_ATTRIBUTES ObjectAttributes;
30     HANDLE TimerHandle;
31     HANDLE HandleOpened;
32     LARGE_INTEGER DueTime;
33     BOOLEAN PreviousState, CurrentState;
34     NTSTATUS Status;
35     ULONG ApcCount;
36 
37     // Create the timer
38     RtlInitUnicodeString(&TimerName, L"\\TestTimer");
39     InitializeObjectAttributes(&ObjectAttributes, &TimerName, 0, NULL, NULL);
40     Status = ZwCreateTimer(&TimerHandle, TIMER_ALL_ACCESS,
41         &ObjectAttributes, NotificationTimer);
42     ok(Status == STATUS_SUCCESS, "ZwCreateTimer failed with Status=0x%08lX", Status);
43 
44     // Open the timer
45     Status = ZwOpenTimer(&HandleOpened, TIMER_ALL_ACCESS, &ObjectAttributes);
46     ok(Status == STATUS_SUCCESS, "ZwOpenTimer failed with Status=0x%08lX", Status);
47 
48     // Set the timer, to some rather high value so it doesn't expire
49     DPRINT("Set timer 1\n");
50     DueTime.LowPart = -10000;
51     DueTime.HighPart = -10;
52     PreviousState = TRUE;
53     Status = ZwSetTimer(HandleOpened, &DueTime, NULL, NULL, FALSE, 0L, &PreviousState);
54     ok(Status == STATUS_SUCCESS, "ZwSetTimer failed with Status=0x%08lX", Status);
55     ok(PreviousState == FALSE, "Incorrect PreviousState returned when setting the timer");
56 
57     // Cancel the timer
58     CurrentState = TRUE;
59     Status = ZwCancelTimer(HandleOpened, &CurrentState);
60     ok(Status == STATUS_SUCCESS, "ZwCancelTimer failed with Status=0x%08lX", Status);
61     ok(CurrentState == FALSE, "Incorrect CurrentState returned when canceling the timer");
62 
63     // Set the timer to some small value, because we'll wait for it to expire
64     DPRINT("Set timer 2\n");
65     DueTime.LowPart = -100;
66     DueTime.HighPart = -1;
67     PreviousState = TRUE;
68     Status = ZwSetTimer(HandleOpened, &DueTime, NULL, NULL, FALSE, 0L, &PreviousState);
69     ok(Status == STATUS_SUCCESS, "ZwSetTimer failed with Status=0x%08lX", Status);
70     ok(PreviousState == FALSE, "Incorrect PreviousState returned when setting the timer");
71 
72     // Wait until it expires
73     DPRINT("Wait till timer expires\n");
74     Status = ZwWaitForSingleObject(HandleOpened, FALSE, NULL);
75     ok(Status == STATUS_SUCCESS, "ZwWaitForSingleObject failed with Status=0x%08lX", Status);
76 
77     // And cancel it
78     DPRINT("Cancel it\n");
79     CurrentState = FALSE;
80     Status = ZwCancelTimer(HandleOpened, &CurrentState);
81     ok(Status == STATUS_SUCCESS, "ZwCancelTimer failed with Status=0x%08lX", Status);
82     ok(CurrentState == TRUE, "Incorrect CurrentState returned when setting the timer");
83 
84     // Test it with APC: Set, Cancel, check if APC has been called
85     DPRINT("Set timer with Apc (3)\n");
86     ApcCount = 0;
87     DueTime.LowPart = -10000;
88     DueTime.HighPart = -10;
89     PreviousState = FALSE;
90     Status = ZwSetTimer(HandleOpened, &DueTime,
91         (PTIMER_APC_ROUTINE)TestTimerApcRoutine, &ApcCount, FALSE,
92         0L, &PreviousState);
93 
94     ok(Status == STATUS_SUCCESS, "ZwSetTimer failed with Status=0x%08lX", Status);
95     ok(PreviousState == TRUE, "Incorrect PreviousState returned when setting the timer");
96 
97     DPRINT("Cancel it\n");
98     CurrentState = TRUE;
99     Status = ZwCancelTimer(HandleOpened, &CurrentState);
100     ok(Status == STATUS_SUCCESS, "ZwCancelTimer failed with Status=0x%08lX", Status);
101     ok(CurrentState == FALSE, "Incorrect CurrentState returned when cancelling the timer");
102     ok(ApcCount == 0, "Incorrect count of TimerApcRoutine calls: %ld, should be 0\n", ApcCount);
103 
104     // Test setting the timer two times in a row, APC routine must not be called
105     DPRINT("Set timer with Apc (4)\n");
106     ApcCount = 0;
107     DueTime.LowPart = -10000;
108     DueTime.HighPart = -10;
109     PreviousState = TRUE;
110     Status = ZwSetTimer(HandleOpened, &DueTime,
111         (PTIMER_APC_ROUTINE)TestTimerApcRoutine, &ApcCount, FALSE,
112         0L, &PreviousState);
113     ok(Status == STATUS_SUCCESS, "ZwSetTimer failed with Status=0x%08lX", Status);
114     ok(PreviousState == FALSE, "Incorrect PreviousState returned when setting the timer");
115 
116     // Set small due time, since we have to wait for timer to finish
117     DPRINT("Set timer with Apc (5)\n");
118     DueTime.LowPart = -10;
119     DueTime.HighPart = -1;
120     PreviousState = TRUE;
121     Status = ZwSetTimer(HandleOpened, &DueTime,
122         (PTIMER_APC_ROUTINE)TestTimerApcRoutine, &ApcCount, FALSE,
123         0L, &PreviousState);
124     ok(Status == STATUS_SUCCESS, "ZwSetTimer failed with Status=0x%08lX", Status);
125     ok(PreviousState == FALSE, "Incorrect PreviousState returned when setting the timer");
126 
127     // Now wait till it's finished, and then check APC call
128     DPRINT("Wait for it\n");
129     Status = ZwWaitForSingleObject(HandleOpened, FALSE, NULL);
130     ok(Status == STATUS_SUCCESS, "ZwWaitForSingleObject failed with Status=0x%08lX", Status);
131 
132     CurrentState = FALSE;
133     Status = ZwCancelTimer(HandleOpened, &CurrentState);
134     ok(Status == STATUS_SUCCESS, "ZwCancelTimer failed with Status=0x%08lX", Status);
135     ok(CurrentState == TRUE, "Incorrect CurrentState returned when cancelling the timer");
136     ok(ApcCount == 1, "Incorrect count of TimerApcRoutine calls: %ld, should be 1\n", ApcCount);
137 
138     // Cleanup...
139     Status = ZwClose(HandleOpened);
140     ok(Status == STATUS_SUCCESS, "ZwClose failed with Status=0x%08lX", Status);
141 
142     Status = ZwClose(TimerHandle);
143     ok(Status == STATUS_SUCCESS, "ZwClose failed with Status=0x%08lX", Status);
144 }
145