1 /* 2 * PROJECT: ReactOS API tests 3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory 4 * PURPOSE: Tests for the NtQueryInformationProcess API 5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org> 6 */ 7 8 #include "precomp.h" 9 10 static LARGE_INTEGER TestStartTime; 11 12 static 13 void 14 Test_ProcessTimes(void) 15 { 16 #define SPIN_TIME 1000000 17 NTSTATUS Status; 18 KERNEL_USER_TIMES Times1; 19 KERNEL_USER_TIMES Times2; 20 ULONG Length; 21 LARGE_INTEGER Time1, Time2; 22 23 /* Everything is NULL */ 24 Status = NtQueryInformationProcess(NULL, 25 ProcessTimes, 26 NULL, 27 0, 28 NULL); 29 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 30 31 /* Right size, invalid process */ 32 Status = NtQueryInformationProcess(NULL, 33 ProcessTimes, 34 NULL, 35 sizeof(KERNEL_USER_TIMES), 36 NULL); 37 ok_hex(Status, STATUS_INVALID_HANDLE); 38 39 /* Valid process, no buffer */ 40 Status = NtQueryInformationProcess(NtCurrentProcess(), 41 ProcessTimes, 42 NULL, 43 0, 44 NULL); 45 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 46 47 /* Unaligned buffer, wrong size */ 48 Status = NtQueryInformationProcess(NtCurrentProcess(), 49 ProcessTimes, 50 (PVOID)2, 51 0, 52 NULL); 53 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 54 55 /* Unaligned buffer, correct size */ 56 Status = NtQueryInformationProcess(NtCurrentProcess(), 57 ProcessTimes, 58 (PVOID)2, 59 sizeof(KERNEL_USER_TIMES), 60 NULL); 61 ok_hex(Status, STATUS_DATATYPE_MISALIGNMENT); 62 63 /* Buffer too small */ 64 Status = NtQueryInformationProcess(NtCurrentProcess(), 65 ProcessTimes, 66 NULL, 67 sizeof(KERNEL_USER_TIMES) - 1, 68 NULL); 69 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 70 71 /* Right buffer size but NULL pointer */ 72 Status = NtQueryInformationProcess(NtCurrentProcess(), 73 ProcessTimes, 74 NULL, 75 sizeof(KERNEL_USER_TIMES), 76 NULL); 77 ok_hex(Status, STATUS_ACCESS_VIOLATION); 78 79 /* Buffer too large */ 80 Status = NtQueryInformationProcess(NtCurrentProcess(), 81 ProcessTimes, 82 NULL, 83 sizeof(KERNEL_USER_TIMES) + 1, 84 NULL); 85 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 86 87 /* Buffer too small, ask for length */ 88 Length = 0x55555555; 89 Status = NtQueryInformationProcess(NtCurrentProcess(), 90 ProcessTimes, 91 NULL, 92 sizeof(KERNEL_USER_TIMES) - 1, 93 &Length); 94 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 95 ok_dec(Length, 0x55555555); 96 97 Status = NtQuerySystemTime(&Time1); 98 ok_hex(Status, STATUS_SUCCESS); 99 100 /* Do some busy waiting to increase UserTime */ 101 do 102 { 103 Status = NtQuerySystemTime(&Time2); 104 if (!NT_SUCCESS(Status)) 105 { 106 ok(0, "NtQuerySystemTime failed with %lx\n", Status); 107 break; 108 } 109 } while (Time2.QuadPart - Time1.QuadPart < SPIN_TIME); 110 111 /* Valid parameters, no return length */ 112 Status = NtQuerySystemTime(&Time1); 113 ok_hex(Status, STATUS_SUCCESS); 114 115 RtlFillMemory(&Times1, sizeof(Times1), 0x55); 116 Status = NtQueryInformationProcess(NtCurrentProcess(), 117 ProcessTimes, 118 &Times1, 119 sizeof(KERNEL_USER_TIMES), 120 NULL); 121 ok_hex(Status, STATUS_SUCCESS); 122 ros_skip_flaky 123 ok(Times1.CreateTime.QuadPart < TestStartTime.QuadPart, 124 "CreateTime is %I64u, expected < %I64u\n", Times1.CreateTime.QuadPart, TestStartTime.QuadPart); 125 ok(Times1.CreateTime.QuadPart > TestStartTime.QuadPart - 100000000LL, 126 "CreateTime is %I64u, expected > %I64u\n", Times1.CreateTime.QuadPart, TestStartTime.QuadPart - 100000000LL); 127 ok(Times1.ExitTime.QuadPart == 0, 128 "ExitTime is %I64u, expected 0\n", Times1.ExitTime.QuadPart); 129 ok(Times1.KernelTime.QuadPart != 0, "KernelTime is 0\n"); 130 ros_skip_flaky 131 ok(Times1.UserTime.QuadPart != 0, "UserTime is 0\n"); 132 133 /* Do some busy waiting to increase UserTime */ 134 do 135 { 136 Status = NtQuerySystemTime(&Time2); 137 if (!NT_SUCCESS(Status)) 138 { 139 ok(0, "NtQuerySystemTime failed with %lx\n", Status); 140 break; 141 } 142 } while (Time2.QuadPart - Time1.QuadPart < SPIN_TIME); 143 144 /* Again, this time with a return length */ 145 Length = 0x55555555; 146 RtlFillMemory(&Times2, sizeof(Times2), 0x55); 147 Status = NtQueryInformationProcess(NtCurrentProcess(), 148 ProcessTimes, 149 &Times2, 150 sizeof(KERNEL_USER_TIMES), 151 &Length); 152 ok_hex(Status, STATUS_SUCCESS); 153 ok_dec(Length, sizeof(KERNEL_USER_TIMES)); 154 ok(Times1.CreateTime.QuadPart == Times2.CreateTime.QuadPart, 155 "CreateTimes not equal: %I64u != %I64u\n", Times1.CreateTime.QuadPart, Times2.CreateTime.QuadPart); 156 ok(Times2.ExitTime.QuadPart == 0, 157 "ExitTime is %I64u, expected 0\n", Times2.ExitTime.QuadPart); 158 ok(Times2.KernelTime.QuadPart != 0, "KernelTime is 0\n"); 159 ok(Times2.UserTime.QuadPart != 0, "UserTime is 0\n"); 160 161 /* Compare the two sets of KernelTime/UserTime values */ 162 Status = NtQuerySystemTime(&Time2); 163 ok_hex(Status, STATUS_SUCCESS); 164 /* Time values must have increased */ 165 ok(Times2.KernelTime.QuadPart > Times1.KernelTime.QuadPart, 166 "KernelTime values inconsistent. Expected %I64u > %I64u\n", Times2.KernelTime.QuadPart, Times1.KernelTime.QuadPart); 167 ros_skip_flaky 168 ok(Times2.UserTime.QuadPart > Times1.UserTime.QuadPart, 169 "UserTime values inconsistent. Expected %I64u > %I64u\n", Times2.UserTime.QuadPart, Times1.UserTime.QuadPart); 170 /* They can't have increased by more than wall clock time difference (we only have one thread) */ 171 ros_skip_flaky 172 ok(Times2.KernelTime.QuadPart - Times1.KernelTime.QuadPart < Time2.QuadPart - Time1.QuadPart, 173 "KernelTime values inconsistent. Expected %I64u - %I64u < %I64u\n", 174 Times2.KernelTime.QuadPart, Times1.KernelTime.QuadPart, Time2.QuadPart - Time1.QuadPart); 175 ok(Times2.UserTime.QuadPart - Times1.UserTime.QuadPart < Time2.QuadPart - Time1.QuadPart, 176 "UserTime values inconsistent. Expected %I64u - %I64u < %I64u\n", 177 Times2.UserTime.QuadPart, Times1.UserTime.QuadPart, Time2.QuadPart - Time1.QuadPart); 178 179 trace("KernelTime1 = %I64u\n", Times1.KernelTime.QuadPart); 180 trace("KernelTime2 = %I64u\n", Times2.KernelTime.QuadPart); 181 trace("UserTime1 = %I64u\n", Times1.UserTime.QuadPart); 182 trace("UserTime2 = %I64u\n", Times2.UserTime.QuadPart); 183 184 /* TODO: Test ExitTime on a terminated process */ 185 #undef SPIN_TIME 186 } 187 188 static 189 void 190 Test_ProcessPriorityClassAlignment(void) 191 { 192 NTSTATUS Status; 193 PPROCESS_PRIORITY_CLASS ProcPriority; 194 195 /* Allocate some memory for the priority class structure */ 196 ProcPriority = malloc(sizeof(PROCESS_PRIORITY_CLASS)); 197 if (ProcPriority == NULL) 198 { 199 skip("Failed to allocate memory for PROCESS_PRIORITY_CLASS!\n"); 200 return; 201 } 202 203 /* 204 * Initialize the PriorityClass member to ensure the test won't randomly succeed (if such data is uninitialized). 205 * Filling 85 to the data member makes sure that if the test fails continously then NtQueryInformationProcess() 206 * didn't initialize the structure with data. 207 */ 208 RtlFillMemory(&ProcPriority->PriorityClass, sizeof(ProcPriority->PriorityClass), 0x55); 209 210 /* Unaligned buffer -- wrong size */ 211 Status = NtQueryInformationProcess(NtCurrentProcess(), 212 ProcessPriorityClass, 213 (PVOID)1, 214 0, 215 NULL); 216 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 217 218 /* Unaligned buffer -- correct size */ 219 Status = NtQueryInformationProcess(NtCurrentProcess(), 220 ProcessPriorityClass, 221 (PVOID)1, 222 sizeof(PROCESS_PRIORITY_CLASS), 223 NULL); 224 ok_hex(Status, STATUS_DATATYPE_MISALIGNMENT); 225 226 /* Unaligned buffer -- wrong size (but this time do with an alignment of 2) */ 227 Status = NtQueryInformationProcess(NtCurrentProcess(), 228 ProcessPriorityClass, 229 (PVOID)2, 230 0, 231 NULL); 232 ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH); 233 234 /* Unaligned buffer -- correct size (but this time do with an alignment of 2) */ 235 Status = NtQueryInformationProcess(NtCurrentProcess(), 236 ProcessPriorityClass, 237 (PVOID)2, 238 sizeof(PROCESS_PRIORITY_CLASS), 239 NULL); 240 ok_hex(Status, STATUS_DATATYPE_MISALIGNMENT); 241 242 /* Do not care for the length but expect to return the priority class */ 243 Status = NtQueryInformationProcess(NtCurrentProcess(), 244 ProcessPriorityClass, 245 ProcPriority, 246 sizeof(PROCESS_PRIORITY_CLASS), 247 NULL); 248 ok_hex(Status, STATUS_SUCCESS); 249 250 /* Make sure the returned priority class is a valid number (non negative) but also it should be within the PROCESS_PRIORITY_CLASS range */ 251 ok(ProcPriority->PriorityClass > PROCESS_PRIORITY_CLASS_INVALID && ProcPriority->PriorityClass <= PROCESS_PRIORITY_CLASS_ABOVE_NORMAL, 252 "Expected a valid number from priority class range but got %d\n", ProcPriority->PriorityClass); 253 free(ProcPriority); 254 } 255 256 START_TEST(NtQueryInformationProcess) 257 { 258 NTSTATUS Status; 259 260 Status = NtQuerySystemTime(&TestStartTime); 261 ok_hex(Status, STATUS_SUCCESS); 262 263 Test_ProcessTimes(); 264 Test_ProcessPriorityClassAlignment(); 265 } 266