[PATCH v2 1/3] ntdll: Add NtQueryMutant
Daniel Lehman
dlehman25 at gmail.com
Sun May 1 14:14:45 CDT 2016
Signed-off-by: Daniel Lehman <dlehman25 at gmail.com>
---
changes v1 -> v2:
- converted FIXME->TRACE instead of removing
- fixed return for WaitForSingleObject
- removed duplicate "NtQueryMutant failed" in tests
- marked 32-bit test failures as broken
- removed sizeof from ok trace
- fixed copy & paste mistake ('event' -> 'mutex')
- added ()s around comparison in server code
- memset info before calling query mutant
dlls/ntdll/sync.c | 40 +++++++++++++----
dlls/ntdll/tests/om.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++
server/mutex.c | 16 +++++++
server/protocol.def | 10 +++++
4 files changed, 177 insertions(+), 9 deletions(-)
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 822ec6e..4440bef 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -520,15 +520,37 @@ NTSTATUS WINAPI NtReleaseMutant( IN HANDLE handle, OUT PLONG prev_count OPTIONAL
* NtQueryMutant [NTDLL.@]
* ZwQueryMutant [NTDLL.@]
*/
-NTSTATUS WINAPI NtQueryMutant(IN HANDLE handle,
- IN MUTANT_INFORMATION_CLASS MutantInformationClass,
- OUT PVOID MutantInformation,
- IN ULONG MutantInformationLength,
- OUT PULONG ResultLength OPTIONAL )
-{
- FIXME("(%p %u %p %u %p): stub!\n",
- handle, MutantInformationClass, MutantInformation, MutantInformationLength, ResultLength);
- return STATUS_NOT_IMPLEMENTED;
+NTSTATUS WINAPI NtQueryMutant( HANDLE handle, MUTANT_INFORMATION_CLASS class,
+ void *info, ULONG len, ULONG *ret_len )
+{
+ NTSTATUS ret;
+ MUTANT_BASIC_INFORMATION *out = info;
+
+ TRACE("(%p %u %p %u %p):\n", handle, class, info, len, ret_len);
+
+ if (class != MutantBasicInformation)
+ {
+ FIXME("(%p, %d, %d) Unknown class\n",
+ handle, class, len);
+ return STATUS_INVALID_INFO_CLASS;
+ }
+
+ if (len != sizeof(MUTANT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
+
+ SERVER_START_REQ( query_mutex )
+ {
+ req->handle = wine_server_obj_handle( handle );
+ if (!(ret = wine_server_call( req )))
+ {
+ out->CurrentCount = 1 - reply->count;
+ out->OwnedByCaller = reply->owned;
+ out->AbandonedState = reply->abandoned;
+ if (ret_len) *ret_len = sizeof(MUTANT_BASIC_INFORMATION);
+ }
+ }
+ SERVER_END_REQ;
+
+ return ret;
}
/*
diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c
index c05f31d..7596e32 100644
--- a/dlls/ntdll/tests/om.c
+++ b/dlls/ntdll/tests/om.c
@@ -43,6 +43,8 @@ static NTSTATUS (WINAPI *pNtCreateMailslotFile)( PHANDLE, ACCESS_MASK, POBJECT_A
ULONG, ULONG, ULONG, PLARGE_INTEGER );
static NTSTATUS (WINAPI *pNtCreateMutant)( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES, BOOLEAN );
static NTSTATUS (WINAPI *pNtOpenMutant) ( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES );
+static NTSTATUS (WINAPI *pNtQueryMutant) ( HANDLE, MUTANT_INFORMATION_CLASS, PVOID, ULONG, PULONG );
+static NTSTATUS (WINAPI *pNtReleaseMutant)( HANDLE, PLONG );
static NTSTATUS (WINAPI *pNtCreateSemaphore)( PHANDLE, ACCESS_MASK,const POBJECT_ATTRIBUTES,LONG,LONG );
static NTSTATUS (WINAPI *pNtOpenSemaphore)( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES );
static NTSTATUS (WINAPI *pNtCreateTimer) ( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES, TIMER_TYPE );
@@ -1865,6 +1867,121 @@ static void test_null_device(void)
CloseHandle(ov.hEvent);
}
+static DWORD WINAPI mutant_thread( void *arg )
+{
+ MUTANT_BASIC_INFORMATION info;
+ NTSTATUS status;
+ HANDLE mutant;
+ DWORD ret;
+
+ mutant = arg;
+ ret = WaitForSingleObject( mutant, 1000 );
+ ok( ret == WAIT_OBJECT_0, "WaitForSingleObject failed %08x\n", ret );
+
+ memset(&info, 0xcc, sizeof(info));
+ status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), NULL);
+ ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status );
+ ok( info.CurrentCount == 0, "expected 0, got %d\n", info.CurrentCount );
+ ok( info.OwnedByCaller == TRUE, "expected TRUE, got %d\n", info.OwnedByCaller );
+ ok( info.AbandonedState == FALSE, "expected FALSE, got %d\n", info.AbandonedState );
+ /* abandon mutant */
+
+ return 0;
+}
+
+static void test_mutant(void)
+{
+ static const WCHAR name[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',
+ '\\','t','e','s','t','_','m','u','t','a','n','t',0};
+ MUTANT_BASIC_INFORMATION info;
+ OBJECT_ATTRIBUTES attr;
+ UNICODE_STRING str;
+ NTSTATUS status;
+ HANDLE mutant;
+ HANDLE thread;
+ DWORD ret;
+ ULONG len;
+ LONG prev;
+
+ pRtlInitUnicodeString(&str, name);
+ InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
+ status = pNtCreateMutant(&mutant, GENERIC_ALL, &attr, TRUE);
+ ok( status == STATUS_SUCCESS, "Failed to create Mutant(%08x)\n", status );
+
+ /* bogus */
+ status = pNtQueryMutant(mutant, MutantBasicInformation, &info, 0, NULL);
+ ok( status == STATUS_INFO_LENGTH_MISMATCH,
+ "Failed to NtQueryMutant, expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status );
+ status = pNtQueryMutant(mutant, 0x42, &info, sizeof(info), NULL);
+ ok( status == STATUS_INVALID_INFO_CLASS || broken(status == STATUS_NOT_IMPLEMENTED), /* 32-bit on Vista/2k8 */
+ "Failed to NtQueryMutant, expected STATUS_INVALID_INFO_CLASS, got %08x\n", status );
+ status = pNtQueryMutant((HANDLE)0xdeadbeef, MutantBasicInformation, &info, sizeof(info), NULL);
+ ok( status == STATUS_INVALID_HANDLE,
+ "Failed to NtQueryMutant, expected STATUS_INVALID_HANDLE, got %08x\n", status );
+
+ /* new */
+ len = -1;
+ memset(&info, 0xcc, sizeof(info));
+ status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), &len);
+ ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status );
+ ok( info.CurrentCount == 0, "expected 0, got %d\n", info.CurrentCount );
+ ok( info.OwnedByCaller == TRUE, "expected TRUE, got %d\n", info.OwnedByCaller );
+ ok( info.AbandonedState == FALSE, "expected FALSE, got %d\n", info.AbandonedState );
+ ok( len == sizeof(info), "got %u\n", len );
+
+ ret = WaitForSingleObject( mutant, 1000 );
+ ok( ret == WAIT_OBJECT_0, "WaitForSingleObject failed %08x\n", ret );
+
+ memset(&info, 0xcc, sizeof(info));
+ status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), NULL);
+ ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status );
+ ok( info.CurrentCount == -1, "expected -1, got %d\n", info.CurrentCount );
+ ok( info.OwnedByCaller == TRUE, "expected TRUE, got %d\n", info.OwnedByCaller );
+ ok( info.AbandonedState == FALSE, "expected FALSE, got %d\n", info.AbandonedState );
+
+ prev = 0xdeadbeef;
+ status = pNtReleaseMutant(mutant, &prev);
+ ok( status == STATUS_SUCCESS, "NtQueryRelease failed %08x\n", status );
+ todo_wine ok( prev == -1, "NtQueryRelease failed, expected -1, got %d\n", prev );
+
+ prev = 0xdeadbeef;
+ status = pNtReleaseMutant(mutant, &prev);
+ ok( status == STATUS_SUCCESS, "NtQueryRelease failed %08x\n", status );
+ todo_wine ok( prev == 0, "NtQueryRelease failed, expected 0, got %d\n", prev );
+
+ memset(&info, 0xcc, sizeof(info));
+ status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), NULL);
+ ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status );
+ ok( info.CurrentCount == 1, "expected 1, got %d\n", info.CurrentCount );
+ ok( info.OwnedByCaller == FALSE, "expected FALSE, got %d\n", info.OwnedByCaller );
+ ok( info.AbandonedState == FALSE, "expected FALSE, got %d\n", info.AbandonedState );
+
+ /* abandoned */
+ thread = CreateThread( NULL, 0, mutant_thread, mutant, 0, NULL );
+ ret = WaitForSingleObject( thread, 1000 );
+ ok( ret == WAIT_OBJECT_0, "WaitForSingleObject failed %08x\n", ret );
+ NtClose( thread );
+
+ memset(&info, 0xcc, sizeof(info));
+ status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), NULL);
+ ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status );
+ ok( info.CurrentCount == 1, "expected 0, got %d\n", info.CurrentCount );
+ ok( info.OwnedByCaller == FALSE, "expected FALSE, got %d\n", info.OwnedByCaller );
+ ok( info.AbandonedState == TRUE, "expected TRUE, got %d\n", info.AbandonedState );
+
+ ret = WaitForSingleObject( mutant, 1000 );
+ ok( ret == WAIT_ABANDONED_0, "WaitForSingleObject failed %08x\n", ret );
+
+ memset(&info, 0xcc, sizeof(info));
+ status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), NULL);
+ ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status );
+ ok( info.CurrentCount == 0, "expected 0, got %d\n", info.CurrentCount );
+ ok( info.OwnedByCaller == TRUE, "expected TRUE, got %d\n", info.OwnedByCaller );
+ ok( info.AbandonedState == FALSE, "expected FALSE, got %d\n", info.AbandonedState );
+
+ NtClose( mutant );
+}
+
START_TEST(om)
{
HMODULE hntdll = GetModuleHandleA("ntdll.dll");
@@ -1892,6 +2009,8 @@ START_TEST(om)
pNtQueryEvent = (void *)GetProcAddress(hntdll, "NtQueryEvent");
pNtPulseEvent = (void *)GetProcAddress(hntdll, "NtPulseEvent");
pNtOpenMutant = (void *)GetProcAddress(hntdll, "NtOpenMutant");
+ pNtQueryMutant = (void *)GetProcAddress(hntdll, "NtQueryMutant");
+ pNtReleaseMutant = (void *)GetProcAddress(hntdll, "NtReleaseMutant");
pNtOpenFile = (void *)GetProcAddress(hntdll, "NtOpenFile");
pNtClose = (void *)GetProcAddress(hntdll, "NtClose");
pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString");
@@ -1925,6 +2044,7 @@ START_TEST(om)
test_query_object();
test_type_mismatch();
test_event();
+ test_mutant();
test_keyed_events();
test_null_device();
}
diff --git a/server/mutex.c b/server/mutex.c
index 3693095..d1887e4 100644
--- a/server/mutex.c
+++ b/server/mutex.c
@@ -251,3 +251,19 @@ DECL_HANDLER(release_mutex)
release_object( mutex );
}
}
+
+/* return details about the mutex */
+DECL_HANDLER(query_mutex)
+{
+ struct mutex *mutex;
+
+ if ((mutex = (struct mutex *)get_handle_obj( current->process, req->handle,
+ MUTANT_QUERY_STATE, &mutex_ops )))
+ {
+ reply->count = mutex->count;
+ reply->owned = (mutex->owner == current);
+ reply->abandoned = mutex->abandoned;
+
+ release_object( mutex );
+ }
+}
diff --git a/server/protocol.def b/server/protocol.def
index a5a45eb..3359b77 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1093,6 +1093,16 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
@END
+/* Query a mutex */
+ at REQ(query_mutex)
+ obj_handle_t handle; /* handle to event */
+ at REPLY
+ unsigned int count; /* current count of mutex */
+ int owned; /* true if owned by current thread */
+ int abandoned; /* true if abandoned */
+ at END
+
+
/* Create a semaphore */
@REQ(create_semaphore)
unsigned int access; /* wanted access rights */
--
2.5.0
More information about the wine-patches
mailing list