ntdll: Add NtQueryMutant.
Signed-off-by: Daniel Lehman <dlehman25@gmail.com> Signed-off-by: Sebastian Lackner <sebastian@fds-team.de> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
d18c14c311
commit
142730ea66
|
@ -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 )
|
||||
NTSTATUS WINAPI NtQueryMutant( HANDLE handle, MUTANT_INFORMATION_CLASS class,
|
||||
void *info, ULONG len, ULONG *ret_len )
|
||||
{
|
||||
FIXME("(%p %u %p %u %p): stub!\n",
|
||||
handle, MutantInformationClass, MutantInformation, MutantInformationLength, ResultLength);
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue