// Native anonymous queue lifetime smoke test. // Verifies queue message delivery and survival through a derived handle. #include #include #include #define TEST_MESSAGE_TYPE 0x71756575u #define TEST_MESSAGE_VALUE 0x123456789abcdef0ull typedef struct TEST_QUEUE_MESSAGE { uint32_t Type; uint32_t Flags; uint64_t Param[6]; } TEST_QUEUE_MESSAGE; typedef char TEST_QUEUE_MESSAGE_SIZE_CHECK[ (sizeof(TEST_QUEUE_MESSAGE) == SYS_QUEUE_MESSAGE_SIZE) ? 1 : -1 ]; // Prints one NUL-terminated string to the kernel console. static void print(const char* s) { SYS_WRITE_CONSOLE_REQUEST req = { sizeof(SYS_WRITE_CONSOLE_REQUEST), 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 = { sizeof(SYS_WRITE_CONSOLE_REQUEST), SysSvFromParts(&c, 1) }; SysWriteConsole(&req); } } // Terminates the current test process. static void exit_now(int code) { while (true) SysExitProcess(code); } // Fails the test with one plain message. static void fail(const char* msg) { print("anonymous_queue_smoke: "); print(msg); print("\n"); exit_now(1); } // Fails the test with one status value. static void fail_status(const char* what, KSTATUS status) { print("anonymous_queue_smoke: "); print(what); print(" status="); print_u64(status); print("\n"); exit_now(1); } // Sends one fixed-size queue message. static KSTATUS send_message(uint32_t queue, const TEST_QUEUE_MESSAGE* message) { SYS_QUEUE_SEND_REQUEST req; memset(&req, 0, sizeof(req)); req.Size = sizeof(req); req.QueueHandle = queue; req.Flags = SYS_QUEUE_FLAG_NONE; req.TimeoutMilliseconds = 0; req.Message = message; return SysSendQueue(&req); } // Receives one fixed-size queue message. static uint32_t recv_message(uint32_t queue, TEST_QUEUE_MESSAGE* message) { SYS_QUEUE_RECV_REQUEST req; memset(&req, 0, sizeof(req)); req.Size = sizeof(req); req.QueueHandle = queue; req.Flags = SYS_QUEUE_FLAG_NONE; req.TimeoutMilliseconds = 0; req.MessageOut = message; return SysRecvQueue(&req); } // Verifies aliases keep an anonymous queue alive after the original handle closes. static void check_alias_lifetime(void) { SYS_HANDLE queue = SYS_HANDLE_INVALID; SYS_HANDLE alias = SYS_HANDLE_INVALID; KSTATUS status = SysCreateQueue(&queue); if (!KSUCCESS(status)) fail_status("create queue", status); SYS_HANDLE self = SYS_HANDLE_INVALID; status = SysOpenProcess(SysGetCurrentPid(), SYS_RIGHT_QUERY | SYS_PROCESS_RIGHT_INSERT_HANDLE, &self); if (!KSUCCESS(status)) fail_status("open self", status); SYS_DUPLICATE_HANDLE_REQUEST duplicate = {0}; duplicate.Size = sizeof(duplicate); duplicate.SourceHandle = queue; duplicate.TargetProcessHandle = self; duplicate.DesiredRights = SYS_QUEUE_RIGHT_SEND | SYS_QUEUE_RIGHT_RECEIVE; duplicate.TargetHandleOut = &alias; status = SysDuplicateHandle(&duplicate); if (!KSUCCESS(status)) fail_status("duplicate queue", status); (void)SysCloseHandle(self); TEST_QUEUE_MESSAGE out = {0}; TEST_QUEUE_MESSAGE in = {0}; out.Type = TEST_MESSAGE_TYPE; out.Param[0] = TEST_MESSAGE_VALUE; status = send_message(queue, &out); if (!KSUCCESS(status)) fail_status("send queue", status); status = SysCloseHandle(queue); if (!KSUCCESS(status)) fail_status("close original", status); status = recv_message(alias, &in); if (!KSUCCESS(status)) fail_status("recv via surviving alias", status); if (in.Type != TEST_MESSAGE_TYPE || in.Param[0] != TEST_MESSAGE_VALUE) fail("message corrupted"); status = recv_message(alias, &in); if (status != NTLSTATUS_WOULD_BLOCK) fail_status("empty queue", status); (void)SysCloseHandle(alias); } // Runs the anonymous queue lifetime smoke test. int main(void) { print("anonymous_queue_smoke: start\n"); check_alias_lifetime(); print("anonymous_queue_smoke: PASS\n"); exit_now(0); return 0; }