From 142730ea6677cea638aef34d687dd0a30140b5f7 Mon Sep 17 00:00:00 2001 From: Daniel Lehman Date: Tue, 3 May 2016 02:55:34 +0200 Subject: [PATCH] ntdll: Add NtQueryMutant. Signed-off-by: Daniel Lehman Signed-off-by: Sebastian Lackner Signed-off-by: Alexandre Julliard --- dlls/ntdll/sync.c | 40 ++++++++++---- dlls/ntdll/tests/om.c | 120 +++++++++++++++++++++++++++++++++++++++++ include/wine/server_protocol.h | 21 +++++++- server/mutex.c | 16 ++++++ server/protocol.def | 10 ++++ server/request.h | 8 +++ server/trace.c | 15 ++++++ 7 files changed, 220 insertions(+), 10 deletions(-) diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index e87e672483e..46cbca78679 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 c05f31d59d1..2bc4ccdcafd 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 ); + CloseHandle( 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/include/wine/server_protocol.h b/include/wine/server_protocol.h index 3b4d3372a24..0cbd8250088 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1292,6 +1292,22 @@ struct open_mutex_reply +struct query_mutex_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct query_mutex_reply +{ + struct reply_header __header; + unsigned int count; + int owned; + int abandoned; + char __pad_20[4]; +}; + + + struct create_semaphore_request { struct request_header __header; @@ -5407,6 +5423,7 @@ enum request REQ_create_mutex, REQ_release_mutex, REQ_open_mutex, + REQ_query_mutex, REQ_create_semaphore, REQ_release_semaphore, REQ_query_semaphore, @@ -5686,6 +5703,7 @@ union generic_request struct create_mutex_request create_mutex_request; struct release_mutex_request release_mutex_request; struct open_mutex_request open_mutex_request; + struct query_mutex_request query_mutex_request; struct create_semaphore_request create_semaphore_request; struct release_semaphore_request release_semaphore_request; struct query_semaphore_request query_semaphore_request; @@ -5963,6 +5981,7 @@ union generic_reply struct create_mutex_reply create_mutex_reply; struct release_mutex_reply release_mutex_reply; struct open_mutex_reply open_mutex_reply; + struct query_mutex_reply query_mutex_reply; struct create_semaphore_reply create_semaphore_reply; struct release_semaphore_reply release_semaphore_reply; struct query_semaphore_reply query_semaphore_reply; @@ -6202,6 +6221,6 @@ union generic_reply struct terminate_job_reply terminate_job_reply; }; -#define SERVER_PROTOCOL_VERSION 503 +#define SERVER_PROTOCOL_VERSION 504 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/mutex.c b/server/mutex.c index 3693095cefd..d1887e4bc45 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 35b14f2c06e..e67632ceee3 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 */ +@REQ(query_mutex) + obj_handle_t handle; /* handle to mutex */ +@REPLY + unsigned int count; /* current count of mutex */ + int owned; /* true if owned by current thread */ + int abandoned; /* true if abandoned */ +@END + + /* Create a semaphore */ @REQ(create_semaphore) unsigned int access; /* wanted access rights */ diff --git a/server/request.h b/server/request.h index 4f2979ba3a2..3dea3a3740b 100644 --- a/server/request.h +++ b/server/request.h @@ -147,6 +147,7 @@ DECL_HANDLER(open_keyed_event); DECL_HANDLER(create_mutex); DECL_HANDLER(release_mutex); DECL_HANDLER(open_mutex); +DECL_HANDLER(query_mutex); DECL_HANDLER(create_semaphore); DECL_HANDLER(release_semaphore); DECL_HANDLER(query_semaphore); @@ -425,6 +426,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_create_mutex, (req_handler)req_release_mutex, (req_handler)req_open_mutex, + (req_handler)req_query_mutex, (req_handler)req_create_semaphore, (req_handler)req_release_semaphore, (req_handler)req_query_semaphore, @@ -922,6 +924,12 @@ C_ASSERT( FIELD_OFFSET(struct open_mutex_request, rootdir) == 20 ); C_ASSERT( sizeof(struct open_mutex_request) == 24 ); C_ASSERT( FIELD_OFFSET(struct open_mutex_reply, handle) == 8 ); C_ASSERT( sizeof(struct open_mutex_reply) == 16 ); +C_ASSERT( FIELD_OFFSET(struct query_mutex_request, handle) == 12 ); +C_ASSERT( sizeof(struct query_mutex_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct query_mutex_reply, count) == 8 ); +C_ASSERT( FIELD_OFFSET(struct query_mutex_reply, owned) == 12 ); +C_ASSERT( FIELD_OFFSET(struct query_mutex_reply, abandoned) == 16 ); +C_ASSERT( sizeof(struct query_mutex_reply) == 24 ); C_ASSERT( FIELD_OFFSET(struct create_semaphore_request, access) == 12 ); C_ASSERT( FIELD_OFFSET(struct create_semaphore_request, initial) == 16 ); C_ASSERT( FIELD_OFFSET(struct create_semaphore_request, max) == 20 ); diff --git a/server/trace.c b/server/trace.c index 9cd884eda58..d48c2050689 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1602,6 +1602,18 @@ static void dump_open_mutex_reply( const struct open_mutex_reply *req ) fprintf( stderr, " handle=%04x", req->handle ); } +static void dump_query_mutex_request( const struct query_mutex_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); +} + +static void dump_query_mutex_reply( const struct query_mutex_reply *req ) +{ + fprintf( stderr, " count=%08x", req->count ); + fprintf( stderr, ", owned=%d", req->owned ); + fprintf( stderr, ", abandoned=%d", req->abandoned ); +} + static void dump_create_semaphore_request( const struct create_semaphore_request *req ) { fprintf( stderr, " access=%08x", req->access ); @@ -4346,6 +4358,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_create_mutex_request, (dump_func)dump_release_mutex_request, (dump_func)dump_open_mutex_request, + (dump_func)dump_query_mutex_request, (dump_func)dump_create_semaphore_request, (dump_func)dump_release_semaphore_request, (dump_func)dump_query_semaphore_request, @@ -4621,6 +4634,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_create_mutex_reply, (dump_func)dump_release_mutex_reply, (dump_func)dump_open_mutex_reply, + (dump_func)dump_query_mutex_reply, (dump_func)dump_create_semaphore_reply, (dump_func)dump_release_semaphore_reply, (dump_func)dump_query_semaphore_reply, @@ -4896,6 +4910,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "create_mutex", "release_mutex", "open_mutex", + "query_mutex", "create_semaphore", "release_semaphore", "query_semaphore", -- 2.11.4.GIT