From 7505150045f3ce4cd805e863913289156322b41d Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 19 Aug 2018 21:43:37 -0500 Subject: [PATCH 11/17] ntoskrnl.exe: Implement KeReleaseMutex() and waiting on mutexes. We can get away with storing the mutex object in the KMUTEX for as long as it's held, since on Windows it's illegal to destroy a mutex until it's released. Setting the flag OBJ_KERNEL_HANDLE on okfile is necessary to allow it to be written to by system threads. Signed-off-by: Zebediah Figura --- dlls/ntoskrnl.exe/ntoskrnl.c | 10 ------- dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 2 +- dlls/ntoskrnl.exe/sync.c | 44 ++++++++++++++++++++++++++-- dlls/ntoskrnl.exe/tests/driver.c | 58 +++++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 13 deletions(-) diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 920fb74..cc88100 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -2096,16 +2096,6 @@ NTSTATUS WINAPI KeWaitForMutexObject(PRKMUTEX Mutex, KWAIT_REASON WaitReason, KP } - /*********************************************************************** - * KeReleaseMutex (NTOSKRNL.EXE.@) - */ -LONG WINAPI KeReleaseMutex(PRKMUTEX Mutex, BOOLEAN Wait) -{ - FIXME( "stub: %p, %d\n", Mutex, Wait ); - return STATUS_NOT_IMPLEMENTED; -} - - /*********************************************************************** * KeInitializeSpinLock (NTOSKRNL.EXE.@) */ diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index 422d575..f089f41 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -1402,7 +1402,7 @@ @ stdcall -private ZwUnloadKey(ptr) NtUnloadKey @ stdcall -private ZwUnmapViewOfSection(long ptr) NtUnmapViewOfSection @ stdcall -private ZwWaitForMultipleObjects(long ptr long long ptr) NtWaitForMultipleObjects -@ stdcall -private ZwWaitForSingleObject(long long ptr) NtWaitForSingleObject +@ stdcall ZwWaitForSingleObject(long long ptr) NtWaitForSingleObject @ stdcall ZwWriteFile(long long ptr ptr ptr ptr long ptr ptr) NtWriteFile @ stdcall -private ZwYieldExecution() NtYieldExecution @ stdcall -private -arch=arm,x86_64 -norelay __chkstk() diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c index 7535ae8..a038a07 100644 --- a/dlls/ntoskrnl.exe/sync.c +++ b/dlls/ntoskrnl.exe/sync.c @@ -84,6 +84,9 @@ NTSTATUS WINAPI KeWaitForMultipleObjects(ULONG count, void *pobjs[], case TYPE_AUTO_EVENT: objs[i]->WaitListHead.Blink = CreateEventW( NULL, FALSE, objs[i]->SignalState, NULL ); break; + case TYPE_MUTEX: + objs[i]->WaitListHead.Blink = CreateMutexW( NULL, FALSE, NULL ); + break; case TYPE_SEMAPHORE: { KSEMAPHORE *semaphore = CONTAINING_RECORD(objs[i], KSEMAPHORE, Header); @@ -110,6 +113,7 @@ NTSTATUS WINAPI KeWaitForMultipleObjects(ULONG count, void *pobjs[], case TYPE_AUTO_EVENT: objs[i]->SignalState = FALSE; break; + case TYPE_MUTEX: case TYPE_SEMAPHORE: --objs[i]->SignalState; break; @@ -118,8 +122,22 @@ NTSTATUS WINAPI KeWaitForMultipleObjects(ULONG count, void *pobjs[], if (!--*((ULONG_PTR *)&objs[i]->WaitListHead.Flink)) { - CloseHandle(objs[i]->WaitListHead.Blink); - objs[i]->WaitListHead.Blink = NULL; + switch (objs[i]->Type) + { + case TYPE_MANUAL_EVENT: + case TYPE_AUTO_EVENT: + case TYPE_SEMAPHORE: + CloseHandle(objs[i]->WaitListHead.Blink); + objs[i]->WaitListHead.Blink = NULL; + break; + case TYPE_MUTEX: + if (objs[i]->SignalState == 1) + { + CloseHandle(objs[i]->WaitListHead.Blink); + objs[i]->WaitListHead.Blink = NULL; + } + break; + } } } LeaveCriticalSection( &sync_cs ); @@ -242,3 +260,25 @@ void WINAPI KeInitializeMutex( PRKMUTEX mutex, ULONG level ) mutex->Header.WaitListHead.Blink = NULL; mutex->Header.WaitListHead.Flink = NULL; } + +/*********************************************************************** + * KeReleaseMutex (NTOSKRNL.EXE.@) + */ +LONG WINAPI KeReleaseMutex( PRKMUTEX mutex, BOOLEAN wait ) +{ + HANDLE handle = mutex->Header.WaitListHead.Blink; + LONG ret; + + TRACE("mutex %p, wait %u.\n", mutex, wait); + + EnterCriticalSection( &sync_cs ); + ret = mutex->Header.SignalState++; + if (!ret && !mutex->Header.WaitListHead.Flink) + { + CloseHandle( handle ); + mutex->Header.WaitListHead.Blink = NULL; + } + LeaveCriticalSection( &sync_cs ); + + return ret; +} diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c index 852a726..e758e3f 100644 --- a/dlls/ntoskrnl.exe/tests/driver.c +++ b/dlls/ntoskrnl.exe/tests/driver.c @@ -226,6 +226,36 @@ static NTSTATUS wait_multiple(ULONG count, void *objs[], WAIT_TYPE wait_type, UL return KeWaitForMultipleObjects(count, objs, wait_type, Executive, KernelMode, FALSE, &integer, NULL); } +static void run_thread(PKSTART_ROUTINE proc, void *arg) +{ + OBJECT_ATTRIBUTES attr = {0}; + HANDLE thread; + NTSTATUS ret; + + attr.Length = sizeof(attr); + attr.Attributes = OBJ_KERNEL_HANDLE; + ret = PsCreateSystemThread(&thread, THREAD_ALL_ACCESS, &attr, NULL, NULL, proc, arg); + ok(!ret, "got %#x\n", ret); + + ret = ZwWaitForSingleObject(thread, FALSE, NULL); + ok(!ret, "got %#x\n", ret); + ret = ZwClose(thread); + ok(!ret, "got %#x\n", ret); +} + +static KMUTEX test_mutex; + +static void WINAPI mutex_thread(void *arg) +{ + NTSTATUS ret, expect = (NTSTATUS)(DWORD_PTR)arg; + + ret = wait_single(&test_mutex, 0); + ok(ret == expect, "expected %#x, got %#x\n", expect, ret); + + if (!ret) KeReleaseMutex(&test_mutex, FALSE); + PsTerminateSystemThread(STATUS_SUCCESS); +} + static void test_sync(void) { KSEMAPHORE semaphore, semaphore2; @@ -387,6 +417,33 @@ static void test_sync(void) ret = wait_multiple(2, objs, WaitAny, 0); ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + /* test mutexes */ + KeInitializeMutex(&test_mutex, 0); + + for (i = 0; i < 10; i++) + { + ret = wait_single(&test_mutex, 0); + ok(ret == 0, "got %#x\n", ret); + } + + for (i = 0; i < 10; i++) + { + ret = KeReleaseMutex(&test_mutex, FALSE); + ok(ret == i - 9, "expected %d, got %d\n", i - 9, ret); + } + + run_thread(mutex_thread, (void *)0); + + ret = wait_single(&test_mutex, 0); + ok(ret == 0, "got %#x\n", ret); + + run_thread(mutex_thread, (void *)STATUS_TIMEOUT); + + ret = KeReleaseMutex(&test_mutex, 0); + ok(ret == 0, "got %#x\n", ret); + + run_thread(mutex_thread, (void *)0); } static NTSTATUS main_test(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info) @@ -410,6 +467,7 @@ static NTSTATUS main_test(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info) winetest_debug = test_input->winetest_debug; winetest_report_success = test_input->winetest_report_success; attr.ObjectName = &pathU; + attr.Attributes = OBJ_KERNEL_HANDLE; ZwOpenFile(&okfile, FILE_APPEND_DATA, &attr, &io, 0, 0); test_currentprocess(); -- 2.7.4