// Win32 recursive mutex smoke test for Bink worker teardown. #include #include #include typedef void* HANDLE; typedef unsigned long DWORD; typedef int BOOL; typedef DWORD (__stdcall *THREAD_START_ROUTINE)(void* parameter); #define FALSE 0 #define TRUE 1 #define INFINITE 0xFFFFFFFFu #define WAIT_OBJECT_0 0u #define WAIT_TIMEOUT 0x00000102u #define WAIT_FAILED 0xFFFFFFFFu #define INVALID_HANDLE_VALUE ((HANDLE)(intptr_t)-1) __declspec(dllimport) HANDLE CreateMutexA(void* attributes, BOOL initialOwner, const char* name); __declspec(dllimport) BOOL ReleaseMutex(HANDLE mutex); __declspec(dllimport) HANDLE CreateThread(void* attributes, size_t stackSize, THREAD_START_ROUTINE startRoutine, void* parameter, DWORD creationFlags, DWORD* threadId); __declspec(dllimport) DWORD WaitForSingleObject(HANDLE handle, DWORD milliseconds); __declspec(dllimport) BOOL CloseHandle(HANDLE handle); __declspec(dllimport) DWORD GetLastError(void); static HANDLE gMutex; static DWORD gWorkerWait; static DWORD gWorkerError; static BOOL gWorkerRelease; // Writes one test message to the native console. static void print(const char* text) { SYS_WRITE_CONSOLE_REQUEST request = { SysSvFromCstr(text) }; (void)SysWriteConsole(&request); } // Terminates the test after one contract failure. static void fail(const char* message) { print("win32_mutex_smoke: "); print(message); print("\n"); while (true) (void)SysExitProcess(1); } // Writes one fixed-width hexadecimal value to the native console. static void print_hex32(DWORD value) { static const char digits[] = "0123456789ABCDEF"; char text[] = "0x00000000"; for (unsigned i = 0; i < 8; i++) { text[9 - i] = digits[value & 0xFu]; value >>= 4; } print(text); } // Reports a failed worker wait with both Win32 result channels. static void fail_worker_wait(const char* message) { print("win32_mutex_smoke: "); print(message); print(" result="); print_hex32(gWorkerWait); print(" error="); print_hex32(gWorkerError); print("\n"); while (true) (void)SysExitProcess(1); } // Attempts one wait and releases the mutex only after successful acquisition. static DWORD __stdcall mutex_worker(void* parameter) { DWORD timeout = (DWORD)(uintptr_t)parameter; gWorkerWait = WaitForSingleObject(gMutex, timeout); gWorkerError = gWorkerWait == WAIT_FAILED ? GetLastError() : 0; if (gWorkerWait == WAIT_OBJECT_0) gWorkerRelease = ReleaseMutex(gMutex); return 0; } // Runs one worker and waits for its normal return. static void run_worker(DWORD timeout) { gWorkerWait = 0xFFFFFFFFu; gWorkerError = 0; gWorkerRelease = FALSE; HANDLE worker = CreateThread(NULL, 0, mutex_worker, (void*)(uintptr_t)timeout, 0, NULL); if (!worker || worker == INVALID_HANDLE_VALUE) fail("CreateThread failed"); if (WaitForSingleObject(worker, 5000u) != WAIT_OBJECT_0) fail("worker did not return"); if (!CloseHandle(worker)) fail("worker CloseHandle failed"); } // Verifies recursive ownership, non-owner safety, and final release transfer. int main(void) { print("win32_mutex_smoke: begin\n"); gMutex = CreateMutexA(NULL, FALSE, NULL); if (!gMutex || gMutex == INVALID_HANDLE_VALUE) fail("CreateMutexA failed"); if (WaitForSingleObject(gMutex, INFINITE) != WAIT_OBJECT_0 || WaitForSingleObject(gMutex, INFINITE) != WAIT_OBJECT_0) fail("recursive acquisition failed"); run_worker(25u); if (gWorkerWait == WAIT_FAILED) fail_worker_wait("doubly-owned finite wait failed"); if (gWorkerWait != WAIT_TIMEOUT || gWorkerRelease) fail("worker acquired doubly-owned mutex"); if (!ReleaseMutex(gMutex)) fail("first recursive release failed"); run_worker(25u); if (gWorkerWait == WAIT_FAILED) fail_worker_wait("singly-owned finite wait failed"); if (gWorkerWait != WAIT_TIMEOUT || gWorkerRelease) fail("worker acquired singly-owned mutex"); if (!ReleaseMutex(gMutex)) fail("final recursive release failed"); run_worker(1000u); if (gWorkerWait == WAIT_FAILED) fail_worker_wait("released finite wait failed"); if (gWorkerWait != WAIT_OBJECT_0 || !gWorkerRelease) fail("worker did not acquire released mutex"); if (!CloseHandle(gMutex)) fail("mutex CloseHandle failed"); gMutex = CreateMutexA(NULL, TRUE, NULL); if (!gMutex || gMutex == INVALID_HANDLE_VALUE) fail("initial-owner mutex failed"); if (WaitForSingleObject(gMutex, INFINITE) != WAIT_OBJECT_0) fail("initial-owner recursion failed"); if (!ReleaseMutex(gMutex) || !ReleaseMutex(gMutex)) fail("initial-owner release failed"); if (!CloseHandle(gMutex)) fail("initial-owner close failed"); print("win32_mutex_smoke: PASS\n"); while (true) (void)SysExitProcess(0); }