Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntoskrnl.exe/ntoskrnl.c | 10 ------- dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 2 +- dlls/ntoskrnl.exe/sync.c | 46 +++++++++++++++++++++++++++-- dlls/ntoskrnl.exe/tests/driver.c | 58 +++++++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 13 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 1d1033e793..7838bd9545 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -2288,16 +2288,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 d127a25270..f56bde130d 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -1404,7 +1404,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 6f356f6355..0947b671f5 100644 --- a/dlls/ntoskrnl.exe/sync.c +++ b/dlls/ntoskrnl.exe/sync.c @@ -82,6 +82,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); @@ -108,6 +111,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; @@ -116,8 +120,24 @@ 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: + /* Native will panic if a mutex is destroyed while held, so we + * don't have to worry about leaking the handle here. */ + if (objs[i]->SignalState == 1) + { + CloseHandle(objs[i]->WaitListHead.Blink); + objs[i]->WaitListHead.Blink = NULL; + } + break; + } } } LeaveCriticalSection( &sync_cs ); @@ -232,3 +252,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 852a726413..82948823c5 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; /* needed to be accessible from system threads */ ZwOpenFile(&okfile, FILE_APPEND_DATA, &attr, &io, 0, 0);
test_currentprocess();