194 lines
6.1 KiB
C
194 lines
6.1 KiB
C
// Waitable timer smoke test.
|
|
// Verifies one-shot, cancellation, reset, invalid handle, and wait timeout behavior.
|
|
|
|
#include <stdint.h>
|
|
#include <ntlite/syscall.h>
|
|
|
|
// Prints one NUL-terminated string to the kernel console.
|
|
static void print(const char* s) {
|
|
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) };
|
|
SysWriteConsole(&req);
|
|
}
|
|
|
|
// Prints one unsigned integer to the kernel console.
|
|
static void print_u64(uint64_t v) {
|
|
char buf[32];
|
|
int i = 0;
|
|
if (v == 0) {
|
|
print("0");
|
|
return;
|
|
}
|
|
while (v && i < (int)sizeof(buf)) {
|
|
buf[i++] = (char)('0' + (v % 10));
|
|
v /= 10;
|
|
}
|
|
while (i--) {
|
|
char c = buf[i];
|
|
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts(&c, 1) };
|
|
SysWriteConsole(&req);
|
|
}
|
|
}
|
|
|
|
// Terminates the current test process.
|
|
static void exit_now(int code) {
|
|
for (;;) SysExitProcess(code);
|
|
}
|
|
|
|
// Fails the test with one status value.
|
|
static void fail_status(const char* what, uint32_t status) {
|
|
print("timer_smoke: ");
|
|
print(what);
|
|
print(" status=");
|
|
print_u64(status);
|
|
print("\n");
|
|
exit_now(1);
|
|
}
|
|
|
|
// Requires one exact status value.
|
|
static void expect_status(const char* what, uint32_t got, uint32_t expected) {
|
|
if (got == expected) return;
|
|
print("timer_smoke: ");
|
|
print(what);
|
|
print(" got=");
|
|
print_u64(got);
|
|
print(" expected=");
|
|
print_u64(expected);
|
|
print("\n");
|
|
exit_now(1);
|
|
}
|
|
|
|
// Arms a timer through the public request ABI.
|
|
static uint32_t set_timer(uint32_t timer, uint64_t dueMs, uint64_t periodMs) {
|
|
SYS_SET_TIMER_REQUEST req = {
|
|
sizeof(req),
|
|
timer,
|
|
SYS_TIMER_FLAG_NONE,
|
|
dueMs,
|
|
periodMs,
|
|
};
|
|
return SysSetTimer(&req);
|
|
}
|
|
|
|
// Verifies timer request validation paths.
|
|
static void test_validation(void) {
|
|
uint32_t timer = 0;
|
|
expect_status("create timer null", SysCreateTimer((uint32_t*)0), NTLSTATUS_INVALID_PARAMETER);
|
|
|
|
uint32_t s = SysCreateTimer(&timer);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("create validation timer", s);
|
|
|
|
expect_status("set timer null", SysSetTimer((const SYS_SET_TIMER_REQUEST*)0), NTLSTATUS_INVALID_PARAMETER);
|
|
expect_status("cancel invalid", SysCancelTimer(0xdeadbeefu), NTLSTATUS_INVALID_HANDLE);
|
|
expect_status("wait invalid", SysWaitSingle(0xdeadbeefu, SYS_WAIT_FLAG_NONE, 0), NTLSTATUS_INVALID_HANDLE);
|
|
|
|
SYS_SET_TIMER_REQUEST req = {
|
|
0,
|
|
timer,
|
|
SYS_TIMER_FLAG_NONE,
|
|
1,
|
|
0,
|
|
};
|
|
expect_status("set bad size", SysSetTimer(&req), NTLSTATUS_INVALID_PARAMETER);
|
|
|
|
req.Size = sizeof(req);
|
|
req.Flags = 1;
|
|
expect_status("set bad flags", SysSetTimer(&req), NTLSTATUS_INVALID_PARAMETER);
|
|
|
|
SysCloseHandle(timer);
|
|
}
|
|
|
|
// Verifies one-shot timers wake waiters and are consumed by the wait.
|
|
static void test_one_shot(void) {
|
|
uint32_t timer = 0;
|
|
uint32_t s = SysCreateTimer(&timer);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("create one-shot timer", s);
|
|
|
|
expect_status("unset immediate wait", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 0), NTLSTATUS_TIMEOUT);
|
|
s = set_timer(timer, 20, 0);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("set one-shot", s);
|
|
|
|
s = SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, SYS_WAIT_TIMEOUT_INFINITE);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("wait one-shot", s);
|
|
|
|
expect_status("one-shot consumed", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 0), NTLSTATUS_TIMEOUT);
|
|
SysCloseHandle(timer);
|
|
}
|
|
|
|
// Verifies cancellation clears an armed timer and its retained signal.
|
|
static void test_cancel(void) {
|
|
uint32_t timer = 0;
|
|
uint32_t s = SysCreateTimer(&timer);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("create cancel timer", s);
|
|
|
|
s = set_timer(timer, 100, 0);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("set cancel timer", s);
|
|
s = SysCancelTimer(timer);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("cancel timer", s);
|
|
|
|
expect_status("cancelled timer wait", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 30), NTLSTATUS_TIMEOUT);
|
|
|
|
s = set_timer(timer, 0, 0);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("set immediate", s);
|
|
expect_status("immediate timer wait", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 0), NTLSTATUS_SUCCESS);
|
|
|
|
s = set_timer(timer, 0, 0);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("set immediate before cancel", s);
|
|
s = SysCancelTimer(timer);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("cancel signaled", s);
|
|
expect_status("cancel clears signal", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 0), NTLSTATUS_TIMEOUT);
|
|
|
|
SysCloseHandle(timer);
|
|
}
|
|
|
|
// Verifies resetting an active timer replaces its previous deadline.
|
|
static void test_reset_changes_deadline(void) {
|
|
uint32_t timer = 0;
|
|
uint32_t s = SysCreateTimer(&timer);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("create reset timer", s);
|
|
|
|
s = set_timer(timer, 100, 0);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("set reset timer long", s);
|
|
s = set_timer(timer, 20, 0);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("set reset timer short", s);
|
|
|
|
s = SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 80);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("wait reset timer", s);
|
|
|
|
SysCloseHandle(timer);
|
|
}
|
|
|
|
// Verifies a periodic timer can wake more than once.
|
|
static void test_periodic(void) {
|
|
uint32_t timer = 0;
|
|
uint32_t s = SysCreateTimer(&timer);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("create periodic timer", s);
|
|
|
|
s = set_timer(timer, 10, 20);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("set periodic timer", s);
|
|
s = SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 80);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("wait periodic first", s);
|
|
s = SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 80);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("wait periodic second", s);
|
|
|
|
s = SysCancelTimer(timer);
|
|
if (s != NTLSTATUS_SUCCESS) fail_status("cancel periodic", s);
|
|
expect_status("periodic cancelled wait", SysWaitSingle(timer, SYS_WAIT_FLAG_NONE, 30), NTLSTATUS_TIMEOUT);
|
|
|
|
SysCloseHandle(timer);
|
|
}
|
|
|
|
// Program entry point.
|
|
int main(void) {
|
|
print("timer_smoke: start\n");
|
|
|
|
test_validation();
|
|
test_one_shot();
|
|
test_cancel();
|
|
test_reset_changes_deadline();
|
|
test_periodic();
|
|
|
|
print("timer_smoke: PASS\n");
|
|
exit_now(0);
|
|
return 0;
|
|
}
|