Files
nt-lite/code/user/tests/syscall_contract_smoke/syscall_contract_smoke.c
T

126 lines
3.5 KiB
C

// Native syscall contract smoke test.
// Verifies public tick units and process exit-code round trips.
#include <stdint.h>
#include <stddef.h>
#include <ntlite/syscall.h>
#define CHILD_EXIT_CODE ((int32_t)-1234567)
// 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(int32_t code) {
for (;;) SysExitProcess(code);
}
// Checks whether a string view equals a NUL-terminated string.
static int view_equals_cstr(SYS_STRING_VIEW view, const char* text) {
size_t n = 0;
while (text[n]) n++;
if (view.Length != n || (!view.Data && n != 0)) return 0;
for (size_t i = 0; i < n; i++) {
if (view.Data[i] != text[i]) return 0;
}
return 1;
}
// Fails the test with one plain message.
static void fail(const char* msg) {
print("syscall_contract_smoke: ");
print(msg);
print("\n");
exit_now(1);
}
// Fails the test with one status value.
static void fail_status(const char* what, uint32_t status) {
print("syscall_contract_smoke: ");
print(what);
print(" status=");
print_u64(status);
print("\n");
exit_now(1);
}
// Verifies the documented tick unit without relying on wall-clock precision.
static void check_tick_contract(void) {
uint64_t frequency = 0;
uint32_t s = SysGetTickFrequency(&frequency);
if (s != NTLSTATUS_SUCCESS) fail_status("query tick frequency", s);
if (!frequency) fail("tick frequency was zero");
uint64_t t0 = SysGetTick();
s = SysSleep(1);
if (s != NTLSTATUS_SUCCESS) fail_status("sleep", s);
uint64_t t1 = SysGetTick();
if (t1 < t0) fail("tick moved backwards across sleep");
if (SysTicksToMicroseconds(t1 - t0, frequency) < 1000ULL)
fail("tick delta was smaller than one millisecond");
}
// Verifies process exit-code storage, wait, and query agree on int32_t.
static void check_exit_code_contract(void) {
SYS_PEB* peb = SysGetPeb();
if (!peb || !peb->ImagePath.Data || peb->ImagePath.Length == 0) fail("missing image path");
uint32_t child = 0;
SYS_CREATE_PROCESS_REQUEST req = {
peb->ImagePath,
SysSvFromCstr("child"),
&child,
};
uint32_t s = SysCreateProcess(&req);
if (s != NTLSTATUS_SUCCESS) fail_status("create child", s);
s = SysWait(child, SYS_WAIT_FLAG_NONE);
if (s != NTLSTATUS_SUCCESS) fail_status("wait child", s);
int32_t exitCode = 0;
s = SysGetProcessExitCode(child, &exitCode);
if (s != NTLSTATUS_SUCCESS) fail_status("query child exit code", s);
if (exitCode != CHILD_EXIT_CODE) fail("child exit code mismatch");
SysCloseHandle(child);
}
// Runs the syscall ABI contract smoke test.
int main(void) {
SYS_PEB* peb = SysGetPeb();
if (peb && view_equals_cstr(peb->CommandLine, "child")) {
exit_now(CHILD_EXIT_CODE);
}
print("syscall_contract_smoke: start\n");
check_tick_contract();
check_exit_code_contract();
print("syscall_contract_smoke: PASS\n");
exit_now(0);
return 0;
}