From 8be256f9b12b42f5a5fef0b82d34aaacfa7c6115 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Thu, 9 Jan 2020 13:44:01 -0600 Subject: [PATCH] ntdll/tests: Move some tests to a new sync.c file. Signed-off-by: Zebediah Figura --- dlls/ntdll/tests/Makefile.in | 1 + dlls/ntdll/tests/om.c | 478 ------------------------------- dlls/ntdll/tests/sync.c | 527 +++++++++++++++++++++++++++++++++++ 3 files changed, 528 insertions(+), 478 deletions(-) create mode 100644 dlls/ntdll/tests/sync.c diff --git a/dlls/ntdll/tests/Makefile.in b/dlls/ntdll/tests/Makefile.in index ed15c51339f..9a99c01bd7c 100644 --- a/dlls/ntdll/tests/Makefile.in +++ b/dlls/ntdll/tests/Makefile.in @@ -21,6 +21,7 @@ C_SRCS = \ rtlbitmap.c \ rtlstr.c \ string.c \ + sync.c \ threadpool.c \ time.c \ virtual.c diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c index 120b093fa56..f366a661a16 100644 --- a/dlls/ntdll/tests/om.c +++ b/dlls/ntdll/tests/om.c @@ -28,10 +28,6 @@ static VOID (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR ); static NTSTATUS (WINAPI *pNtCreateEvent) ( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES, BOOLEAN, BOOLEAN); static NTSTATUS (WINAPI *pNtOpenEvent) ( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES); -static NTSTATUS (WINAPI *pNtPulseEvent) ( HANDLE, PLONG ); -static NTSTATUS (WINAPI *pNtQueryEvent) ( HANDLE, EVENT_INFORMATION_CLASS, PVOID, ULONG, PULONG ); -static NTSTATUS (WINAPI *pNtResetEvent) ( HANDLE, LONG* ); -static NTSTATUS (WINAPI *pNtSetEvent) ( HANDLE, LONG* ); static NTSTATUS (WINAPI *pNtCreateJobObject)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES ); static NTSTATUS (WINAPI *pNtOpenJobObject)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES ); static NTSTATUS (WINAPI *pNtCreateKey)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG, @@ -42,8 +38,6 @@ 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 *pNtQuerySemaphore)( PHANDLE, SEMAPHORE_INFORMATION_CLASS, PVOID, ULONG, PULONG ); @@ -65,22 +59,12 @@ static NTSTATUS (WINAPI *pNtQueryObject)(HANDLE,OBJECT_INFORMATION_CLASS,PVOID,U static NTSTATUS (WINAPI *pNtReleaseSemaphore)(HANDLE, ULONG, PULONG); static NTSTATUS (WINAPI *pNtCreateKeyedEvent)( HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *, ULONG ); static NTSTATUS (WINAPI *pNtOpenKeyedEvent)( HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES * ); -static NTSTATUS (WINAPI *pNtWaitForKeyedEvent)( HANDLE, const void *, BOOLEAN, const LARGE_INTEGER * ); -static NTSTATUS (WINAPI *pNtReleaseKeyedEvent)( HANDLE, const void *, BOOLEAN, const LARGE_INTEGER * ); static NTSTATUS (WINAPI *pNtCreateIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG); static NTSTATUS (WINAPI *pNtOpenIoCompletion)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES ); static NTSTATUS (WINAPI *pNtQueryInformationFile)(HANDLE, PIO_STATUS_BLOCK, void *, ULONG, FILE_INFORMATION_CLASS); -static NTSTATUS (WINAPI *pNtQuerySystemTime)( LARGE_INTEGER * ); -static NTSTATUS (WINAPI *pRtlWaitOnAddress)( const void *, const void *, SIZE_T, const LARGE_INTEGER * ); -static void (WINAPI *pRtlWakeAddressAll)( const void * ); -static void (WINAPI *pRtlWakeAddressSingle)( const void * ); static NTSTATUS (WINAPI *pNtOpenProcess)( HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *, const CLIENT_ID * ); static NTSTATUS (WINAPI *pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); -#define KEYEDEVENT_WAIT 0x0001 -#define KEYEDEVENT_WAKE 0x0002 -#define KEYEDEVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x0003) - #define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1)) static LPCSTR wine_dbgstr_us( const UNICODE_STRING *us ) @@ -1697,266 +1681,6 @@ static void test_type_mismatch(void) pNtClose( h ); } -static void test_event(void) -{ - HANDLE Event; - HANDLE Event2; - LONG prev_state = 0xdeadbeef; - NTSTATUS status; - UNICODE_STRING str; - OBJECT_ATTRIBUTES attr; - EVENT_BASIC_INFORMATION info; - - pRtlInitUnicodeString( &str, L"\\BaseNamedObjects\\testEvent" ); - InitializeObjectAttributes(&attr, &str, 0, 0, NULL); - - status = pNtCreateEvent(&Event, GENERIC_ALL, &attr, 1, 0); - ok( status == STATUS_SUCCESS, "NtCreateEvent failed %08x\n", status ); - - status = pNtPulseEvent(Event, &prev_state); - ok( status == STATUS_SUCCESS, "NtPulseEvent failed %08x\n", status ); - ok( !prev_state, "prev_state = %x\n", prev_state ); - - status = pNtQueryEvent(Event, EventBasicInformation, &info, sizeof(info), NULL); - ok( status == STATUS_SUCCESS, "NtQueryEvent failed %08x\n", status ); - ok( info.EventType == 1 && info.EventState == 0, - "NtQueryEvent failed, expected 1 0, got %d %d\n", info.EventType, info.EventState ); - - status = pNtOpenEvent(&Event2, GENERIC_ALL, &attr); - ok( status == STATUS_SUCCESS, "NtOpenEvent failed %08x\n", status ); - - pNtClose(Event); - Event = Event2; - - status = pNtQueryEvent(Event, EventBasicInformation, &info, sizeof(info), NULL); - ok( status == STATUS_SUCCESS, "NtQueryEvent failed %08x\n", status ); - ok( info.EventType == 1 && info.EventState == 0, - "NtQueryEvent failed, expected 1 0, got %d %d\n", info.EventType, info.EventState ); - - status = pNtSetEvent( Event, &prev_state ); - ok( status == STATUS_SUCCESS, "NtSetEvent failed: %08x\n", status ); - ok( !prev_state, "prev_state = %x\n", prev_state ); - - status = pNtSetEvent( Event, &prev_state ); - ok( status == STATUS_SUCCESS, "NtSetEvent failed: %08x\n", status ); - ok( prev_state == 1, "prev_state = %x\n", prev_state ); - - status = pNtResetEvent( Event, &prev_state ); - ok( status == STATUS_SUCCESS, "NtSetEvent failed: %08x\n", status ); - ok( prev_state == 1, "prev_state = %x\n", prev_state ); - - status = pNtResetEvent( Event, &prev_state ); - ok( status == STATUS_SUCCESS, "NtSetEvent failed: %08x\n", status ); - ok( !prev_state, "prev_state = %x\n", prev_state ); - - status = pNtPulseEvent( Event, &prev_state ); - ok( status == STATUS_SUCCESS, "NtPulseEvent failed %08x\n", status ); - ok( !prev_state, "prev_state = %x\n", prev_state ); - - status = pNtSetEvent( Event, &prev_state ); - ok( status == STATUS_SUCCESS, "NtSetEvent failed: %08x\n", status ); - ok( !prev_state, "prev_state = %x\n", prev_state ); - - status = pNtPulseEvent( Event, &prev_state ); - ok( status == STATUS_SUCCESS, "NtPulseEvent failed %08x\n", status ); - ok( prev_state == 1, "prev_state = %x\n", prev_state ); - - pNtClose(Event); -} - -static const WCHAR keyed_nameW[] = L"\\BaseNamedObjects\\WineTestEvent"; - -static DWORD WINAPI keyed_event_thread( void *arg ) -{ - HANDLE handle; - NTSTATUS status; - LARGE_INTEGER timeout; - OBJECT_ATTRIBUTES attr; - UNICODE_STRING str; - ULONG_PTR i; - - attr.Length = sizeof(attr); - attr.RootDirectory = 0; - attr.ObjectName = &str; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - RtlInitUnicodeString( &str, keyed_nameW ); - - status = pNtOpenKeyedEvent( &handle, KEYEDEVENT_ALL_ACCESS, &attr ); - ok( !status, "NtOpenKeyedEvent failed %x\n", status ); - - for (i = 0; i < 20; i++) - { - if (i & 1) - status = pNtWaitForKeyedEvent( handle, (void *)(i * 2), 0, NULL ); - else - status = pNtReleaseKeyedEvent( handle, (void *)(i * 2), 0, NULL ); - ok( status == STATUS_SUCCESS, "%li: failed %x\n", i, status ); - Sleep( 20 - i ); - } - - status = pNtReleaseKeyedEvent( handle, (void *)0x1234, 0, NULL ); - ok( status == STATUS_SUCCESS, "NtReleaseKeyedEvent %x\n", status ); - - timeout.QuadPart = -10000; - status = pNtWaitForKeyedEvent( handle, (void *)0x5678, 0, &timeout ); - ok( status == STATUS_TIMEOUT, "NtWaitForKeyedEvent %x\n", status ); - status = pNtReleaseKeyedEvent( handle, (void *)0x9abc, 0, &timeout ); - ok( status == STATUS_TIMEOUT, "NtReleaseKeyedEvent %x\n", status ); - - NtClose( handle ); - return 0; -} - -static void test_keyed_events(void) -{ - OBJECT_ATTRIBUTES attr; - UNICODE_STRING str; - HANDLE handle, event, thread; - NTSTATUS status; - LARGE_INTEGER timeout; - ULONG_PTR i; - - if (!pNtCreateKeyedEvent) - { - win_skip( "Keyed events not supported\n" ); - return; - } - - attr.Length = sizeof(attr); - attr.RootDirectory = 0; - attr.ObjectName = &str; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - RtlInitUnicodeString( &str, keyed_nameW ); - - status = pNtCreateKeyedEvent( &handle, KEYEDEVENT_ALL_ACCESS | SYNCHRONIZE, &attr, 0 ); - ok( !status, "NtCreateKeyedEvent failed %x\n", status ); - - status = WaitForSingleObject( handle, 1000 ); - ok( status == 0, "WaitForSingleObject %x\n", status ); - - timeout.QuadPart = -100000; - status = pNtWaitForKeyedEvent( handle, (void *)255, 0, &timeout ); - ok( status == STATUS_INVALID_PARAMETER_1, "NtWaitForKeyedEvent %x\n", status ); - status = pNtReleaseKeyedEvent( handle, (void *)255, 0, &timeout ); - ok( status == STATUS_INVALID_PARAMETER_1, "NtReleaseKeyedEvent %x\n", status ); - - status = pNtWaitForKeyedEvent( handle, (void *)254, 0, &timeout ); - ok( status == STATUS_TIMEOUT, "NtWaitForKeyedEvent %x\n", status ); - status = pNtReleaseKeyedEvent( handle, (void *)254, 0, &timeout ); - ok( status == STATUS_TIMEOUT, "NtReleaseKeyedEvent %x\n", status ); - - status = pNtWaitForKeyedEvent( handle, NULL, 0, &timeout ); - ok( status == STATUS_TIMEOUT, "NtWaitForKeyedEvent %x\n", status ); - status = pNtReleaseKeyedEvent( handle, NULL, 0, &timeout ); - ok( status == STATUS_TIMEOUT, "NtReleaseKeyedEvent %x\n", status ); - - status = pNtWaitForKeyedEvent( NULL, (void *)8, 0, &timeout ); - ok( status == STATUS_TIMEOUT || broken(status == STATUS_INVALID_HANDLE), /* XP/2003 */ - "NtWaitForKeyedEvent %x\n", status ); - status = pNtReleaseKeyedEvent( NULL, (void *)8, 0, &timeout ); - ok( status == STATUS_TIMEOUT || broken(status == STATUS_INVALID_HANDLE), /* XP/2003 */ - "NtReleaseKeyedEvent %x\n", status ); - - status = pNtWaitForKeyedEvent( (HANDLE)0xdeadbeef, (void *)9, 0, &timeout ); - ok( status == STATUS_INVALID_PARAMETER_1, "NtWaitForKeyedEvent %x\n", status ); - status = pNtReleaseKeyedEvent( (HANDLE)0xdeadbeef, (void *)9, 0, &timeout ); - ok( status == STATUS_INVALID_PARAMETER_1, "NtReleaseKeyedEvent %x\n", status ); - - status = pNtWaitForKeyedEvent( (HANDLE)0xdeadbeef, (void *)8, 0, &timeout ); - ok( status == STATUS_INVALID_HANDLE, "NtWaitForKeyedEvent %x\n", status ); - status = pNtReleaseKeyedEvent( (HANDLE)0xdeadbeef, (void *)8, 0, &timeout ); - ok( status == STATUS_INVALID_HANDLE, "NtReleaseKeyedEvent %x\n", status ); - - thread = CreateThread( NULL, 0, keyed_event_thread, 0, 0, NULL ); - for (i = 0; i < 20; i++) - { - if (i & 1) - status = pNtReleaseKeyedEvent( handle, (void *)(i * 2), 0, NULL ); - else - status = pNtWaitForKeyedEvent( handle, (void *)(i * 2), 0, NULL ); - ok( status == STATUS_SUCCESS, "%li: failed %x\n", i, status ); - Sleep( i ); - } - status = pNtWaitForKeyedEvent( handle, (void *)0x1234, 0, &timeout ); - ok( status == STATUS_SUCCESS, "NtWaitForKeyedEvent %x\n", status ); - status = pNtWaitForKeyedEvent( handle, (void *)0x5678, 0, &timeout ); - ok( status == STATUS_TIMEOUT, "NtWaitForKeyedEvent %x\n", status ); - status = pNtReleaseKeyedEvent( handle, (void *)0x9abc, 0, &timeout ); - ok( status == STATUS_TIMEOUT, "NtReleaseKeyedEvent %x\n", status ); - - ok( WaitForSingleObject( thread, 30000 ) == 0, "wait failed\n" ); - - NtClose( handle ); - - /* test access rights */ - - status = pNtCreateKeyedEvent( &handle, KEYEDEVENT_WAIT, &attr, 0 ); - ok( !status, "NtCreateKeyedEvent failed %x\n", status ); - status = pNtWaitForKeyedEvent( handle, (void *)8, 0, &timeout ); - ok( status == STATUS_TIMEOUT, "NtWaitForKeyedEvent %x\n", status ); - status = pNtReleaseKeyedEvent( handle, (void *)8, 0, &timeout ); - ok( status == STATUS_ACCESS_DENIED, "NtReleaseKeyedEvent %x\n", status ); - NtClose( handle ); - - status = pNtCreateKeyedEvent( &handle, KEYEDEVENT_WAKE, &attr, 0 ); - ok( !status, "NtCreateKeyedEvent failed %x\n", status ); - status = pNtWaitForKeyedEvent( handle, (void *)8, 0, &timeout ); - ok( status == STATUS_ACCESS_DENIED, "NtWaitForKeyedEvent %x\n", status ); - status = pNtReleaseKeyedEvent( handle, (void *)8, 0, &timeout ); - ok( status == STATUS_TIMEOUT, "NtReleaseKeyedEvent %x\n", status ); - NtClose( handle ); - - status = pNtCreateKeyedEvent( &handle, KEYEDEVENT_ALL_ACCESS, &attr, 0 ); - ok( !status, "NtCreateKeyedEvent failed %x\n", status ); - status = WaitForSingleObject( handle, 1000 ); - ok( status == WAIT_FAILED && GetLastError() == ERROR_ACCESS_DENIED, - "WaitForSingleObject %x err %u\n", status, GetLastError() ); - status = pNtWaitForKeyedEvent( handle, (void *)8, 0, &timeout ); - ok( status == STATUS_TIMEOUT, "NtWaitForKeyedEvent %x\n", status ); - status = pNtReleaseKeyedEvent( handle, (void *)8, 0, &timeout ); - ok( status == STATUS_TIMEOUT, "NtReleaseKeyedEvent %x\n", status ); - NtClose( handle ); - - /* GENERIC_READ gives wait access */ - status = pNtCreateKeyedEvent( &handle, GENERIC_READ, &attr, 0 ); - ok( !status, "NtCreateKeyedEvent failed %x\n", status ); - status = pNtWaitForKeyedEvent( handle, (void *)8, 0, &timeout ); - ok( status == STATUS_TIMEOUT, "NtWaitForKeyedEvent %x\n", status ); - status = pNtReleaseKeyedEvent( handle, (void *)8, 0, &timeout ); - ok( status == STATUS_ACCESS_DENIED, "NtReleaseKeyedEvent %x\n", status ); - NtClose( handle ); - - /* GENERIC_WRITE gives wake access */ - status = pNtCreateKeyedEvent( &handle, GENERIC_WRITE, &attr, 0 ); - ok( !status, "NtCreateKeyedEvent failed %x\n", status ); - status = pNtWaitForKeyedEvent( handle, (void *)8, 0, &timeout ); - ok( status == STATUS_ACCESS_DENIED, "NtWaitForKeyedEvent %x\n", status ); - status = pNtReleaseKeyedEvent( handle, (void *)8, 0, &timeout ); - ok( status == STATUS_TIMEOUT, "NtReleaseKeyedEvent %x\n", status ); - - /* it's not an event */ - status = pNtPulseEvent( handle, NULL ); - ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtPulseEvent %x\n", status ); - - status = pNtCreateEvent( &event, GENERIC_ALL, &attr, FALSE, FALSE ); - ok( status == STATUS_OBJECT_NAME_COLLISION || status == STATUS_OBJECT_TYPE_MISMATCH /* 7+ */, - "CreateEvent %x\n", status ); - - NtClose( handle ); - - status = pNtCreateEvent( &event, GENERIC_ALL, &attr, FALSE, FALSE ); - ok( status == 0, "CreateEvent %x\n", status ); - status = pNtWaitForKeyedEvent( event, (void *)8, 0, &timeout ); - ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtWaitForKeyedEvent %x\n", status ); - status = pNtReleaseKeyedEvent( event, (void *)8, 0, &timeout ); - ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtReleaseKeyedEvent %x\n", status ); - NtClose( event ); -} - static void test_null_device(void) { OBJECT_ATTRIBUTES attr; @@ -2030,119 +1754,6 @@ 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) -{ - MUTANT_BASIC_INFORMATION info; - OBJECT_ATTRIBUTES attr; - UNICODE_STRING str; - NTSTATUS status; - HANDLE mutant; - HANDLE thread; - DWORD ret; - ULONG len; - LONG prev; - - pRtlInitUnicodeString(&str, L"\\BaseNamedObjects\\test_mutant"); - 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, "NtReleaseMutant failed %08x\n", status ); - ok( prev == -1, "NtReleaseMutant failed, expected -1, got %d\n", prev ); - - prev = 0xdeadbeef; - status = pNtReleaseMutant(mutant, &prev); - ok( status == STATUS_SUCCESS, "NtReleaseMutant failed %08x\n", status ); - ok( prev == 0, "NtReleaseMutant 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 ); -} - static void test_semaphore(void) { SEMAPHORE_BASIC_INFORMATION info; @@ -2219,79 +1830,6 @@ static void test_semaphore(void) NtClose( semaphore ); } -static void test_wait_on_address(void) -{ - DWORD ticks; - SIZE_T size; - NTSTATUS status; - LARGE_INTEGER timeout; - LONG64 address, compare; - - if (!pRtlWaitOnAddress) - { - win_skip("RtlWaitOnAddress not supported, skipping test\n"); - return; - } - - if (0) /* crash on Windows */ - { - pRtlWaitOnAddress(&address, NULL, 8, NULL); - pRtlWaitOnAddress(NULL, &compare, 8, NULL); - pRtlWaitOnAddress(NULL, NULL, 8, NULL); - } - - /* don't crash */ - pRtlWakeAddressSingle(NULL); - pRtlWakeAddressAll(NULL); - - /* invalid values */ - address = 0; - compare = 0; - status = pRtlWaitOnAddress(&address, &compare, 5, NULL); - ok(status == STATUS_INVALID_PARAMETER, "got %x\n", status); - - /* values match */ - address = 0; - compare = 0; - pNtQuerySystemTime(&timeout); - timeout.QuadPart += 100*10000; - ticks = GetTickCount(); - status = pRtlWaitOnAddress(&address, &compare, 8, &timeout); - ticks = GetTickCount() - ticks; - ok(status == STATUS_TIMEOUT, "got 0x%08x\n", status); - ok(ticks >= 90 && ticks <= 1000, "got %u\n", ticks); - ok(address == 0, "got %s\n", wine_dbgstr_longlong(address)); - ok(compare == 0, "got %s\n", wine_dbgstr_longlong(compare)); - - /* different address size */ - for (size = 1; size <= 4; size <<= 1) - { - compare = ~0; - compare <<= size * 8; - - timeout.QuadPart = -100 * 10000; - ticks = GetTickCount(); - status = pRtlWaitOnAddress(&address, &compare, size, &timeout); - ticks = GetTickCount() - ticks; - ok(status == STATUS_TIMEOUT, "got 0x%08x\n", status); - ok(ticks >= 90 && ticks <= 1000, "got %u\n", ticks); - - status = pRtlWaitOnAddress(&address, &compare, size << 1, &timeout); - ok(!status, "got 0x%08x\n", status); - } - address = 0; - compare = 1; - status = pRtlWaitOnAddress(&address, &compare, 8, NULL); - ok(!status, "got 0x%08x\n", status); - - /* no waiters */ - address = 0; - pRtlWakeAddressSingle(&address); - ok(address == 0, "got %s\n", wine_dbgstr_longlong(address)); - pRtlWakeAddressAll(&address); - ok(address == 0, "got %s\n", wine_dbgstr_longlong(address)); -} - static void test_process(void) { OBJECT_ATTRIBUTES attr; @@ -2355,13 +1893,7 @@ START_TEST(om) pNtCreateMailslotFile = (void *)GetProcAddress(hntdll, "NtCreateMailslotFile"); pNtCreateMutant = (void *)GetProcAddress(hntdll, "NtCreateMutant"); pNtOpenEvent = (void *)GetProcAddress(hntdll, "NtOpenEvent"); - pNtQueryEvent = (void *)GetProcAddress(hntdll, "NtQueryEvent"); - pNtPulseEvent = (void *)GetProcAddress(hntdll, "NtPulseEvent"); - pNtResetEvent = (void *)GetProcAddress(hntdll, "NtResetEvent"); - pNtSetEvent = (void *)GetProcAddress(hntdll, "NtSetEvent"); 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"); @@ -2382,15 +1914,9 @@ START_TEST(om) pNtReleaseSemaphore = (void *)GetProcAddress(hntdll, "NtReleaseSemaphore"); pNtCreateKeyedEvent = (void *)GetProcAddress(hntdll, "NtCreateKeyedEvent"); pNtOpenKeyedEvent = (void *)GetProcAddress(hntdll, "NtOpenKeyedEvent"); - pNtWaitForKeyedEvent = (void *)GetProcAddress(hntdll, "NtWaitForKeyedEvent"); - pNtReleaseKeyedEvent = (void *)GetProcAddress(hntdll, "NtReleaseKeyedEvent"); pNtCreateIoCompletion = (void *)GetProcAddress(hntdll, "NtCreateIoCompletion"); pNtOpenIoCompletion = (void *)GetProcAddress(hntdll, "NtOpenIoCompletion"); pNtQueryInformationFile = (void *)GetProcAddress(hntdll, "NtQueryInformationFile"); - pNtQuerySystemTime = (void *)GetProcAddress(hntdll, "NtQuerySystemTime"); - pRtlWaitOnAddress = (void *)GetProcAddress(hntdll, "RtlWaitOnAddress"); - pRtlWakeAddressAll = (void *)GetProcAddress(hntdll, "RtlWakeAddressAll"); - pRtlWakeAddressSingle = (void *)GetProcAddress(hntdll, "RtlWakeAddressSingle"); pNtOpenProcess = (void *)GetProcAddress(hntdll, "NtOpenProcess"); pNtQuerySystemInformation = (void *)GetProcAddress(hntdll, "NtQuerySystemInformation"); @@ -2403,11 +1929,7 @@ START_TEST(om) test_query_object(); test_query_object_types(); test_type_mismatch(); - test_event(); - test_mutant(); test_semaphore(); - test_keyed_events(); test_null_device(); - test_wait_on_address(); test_process(); } diff --git a/dlls/ntdll/tests/sync.c b/dlls/ntdll/tests/sync.c new file mode 100644 index 00000000000..9967a2be257 --- /dev/null +++ b/dlls/ntdll/tests/sync.c @@ -0,0 +1,527 @@ +/* + * Unit tests for NT synchronization objects + * + * Copyright 2020 Zebediah Figura + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" +#include "wine/test.h" + +static NTSTATUS (WINAPI *pNtClose)( HANDLE ); +static NTSTATUS (WINAPI *pNtCreateEvent)( HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *, BOOLEAN, BOOLEAN ); +static NTSTATUS (WINAPI *pNtCreateKeyedEvent)( HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *, ULONG ); +static NTSTATUS (WINAPI *pNtCreateMutant)( HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *, BOOLEAN ); +static NTSTATUS (WINAPI *pNtOpenEvent)( HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES * ); +static NTSTATUS (WINAPI *pNtOpenKeyedEvent)( HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES * ); +static NTSTATUS (WINAPI *pNtPulseEvent)( HANDLE, LONG * ); +static NTSTATUS (WINAPI *pNtQueryEvent)( HANDLE, EVENT_INFORMATION_CLASS, void *, ULONG, ULONG * ); +static NTSTATUS (WINAPI *pNtQueryMutant)( HANDLE, MUTANT_INFORMATION_CLASS, void *, ULONG, ULONG * ); +static NTSTATUS (WINAPI *pNtQuerySystemTime)( LARGE_INTEGER * ); +static NTSTATUS (WINAPI *pNtReleaseKeyedEvent)( HANDLE, const void *, BOOLEAN, const LARGE_INTEGER * ); +static NTSTATUS (WINAPI *pNtReleaseMutant)( HANDLE, LONG * ); +static NTSTATUS (WINAPI *pNtResetEvent)( HANDLE, LONG * ); +static NTSTATUS (WINAPI *pNtSetEvent)( HANDLE, LONG * ); +static NTSTATUS (WINAPI *pNtWaitForKeyedEvent)( HANDLE, const void *, BOOLEAN, const LARGE_INTEGER * ); +static void (WINAPI *pRtlInitUnicodeString)( UNICODE_STRING *, const WCHAR * ); +static NTSTATUS (WINAPI *pRtlWaitOnAddress)( const void *, const void *, SIZE_T, const LARGE_INTEGER * ); +static void (WINAPI *pRtlWakeAddressAll)( const void * ); +static void (WINAPI *pRtlWakeAddressSingle)( const void * ); + +#define KEYEDEVENT_WAIT 0x0001 +#define KEYEDEVENT_WAKE 0x0002 +#define KEYEDEVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x0003) + +static void test_event(void) +{ + HANDLE Event; + HANDLE Event2; + LONG prev_state = 0xdeadbeef; + NTSTATUS status; + UNICODE_STRING str; + OBJECT_ATTRIBUTES attr; + EVENT_BASIC_INFORMATION info; + + pRtlInitUnicodeString(&str, L"\\BaseNamedObjects\\testEvent"); + InitializeObjectAttributes(&attr, &str, 0, 0, NULL); + + status = pNtCreateEvent(&Event, GENERIC_ALL, &attr, 1, 0); + ok( status == STATUS_SUCCESS, "NtCreateEvent failed %08x\n", status ); + + status = pNtPulseEvent(Event, &prev_state); + ok( status == STATUS_SUCCESS, "NtPulseEvent failed %08x\n", status ); + ok( !prev_state, "prev_state = %x\n", prev_state ); + + status = pNtQueryEvent(Event, EventBasicInformation, &info, sizeof(info), NULL); + ok( status == STATUS_SUCCESS, "NtQueryEvent failed %08x\n", status ); + ok( info.EventType == 1 && info.EventState == 0, + "NtQueryEvent failed, expected 1 0, got %d %d\n", info.EventType, info.EventState ); + + status = pNtOpenEvent(&Event2, GENERIC_ALL, &attr); + ok( status == STATUS_SUCCESS, "NtOpenEvent failed %08x\n", status ); + + pNtClose(Event); + Event = Event2; + + status = pNtQueryEvent(Event, EventBasicInformation, &info, sizeof(info), NULL); + ok( status == STATUS_SUCCESS, "NtQueryEvent failed %08x\n", status ); + ok( info.EventType == 1 && info.EventState == 0, + "NtQueryEvent failed, expected 1 0, got %d %d\n", info.EventType, info.EventState ); + + status = pNtSetEvent( Event, &prev_state ); + ok( status == STATUS_SUCCESS, "NtSetEvent failed: %08x\n", status ); + ok( !prev_state, "prev_state = %x\n", prev_state ); + + status = pNtSetEvent( Event, &prev_state ); + ok( status == STATUS_SUCCESS, "NtSetEvent failed: %08x\n", status ); + ok( prev_state == 1, "prev_state = %x\n", prev_state ); + + status = pNtResetEvent( Event, &prev_state ); + ok( status == STATUS_SUCCESS, "NtSetEvent failed: %08x\n", status ); + ok( prev_state == 1, "prev_state = %x\n", prev_state ); + + status = pNtResetEvent( Event, &prev_state ); + ok( status == STATUS_SUCCESS, "NtSetEvent failed: %08x\n", status ); + ok( !prev_state, "prev_state = %x\n", prev_state ); + + status = pNtPulseEvent( Event, &prev_state ); + ok( status == STATUS_SUCCESS, "NtPulseEvent failed %08x\n", status ); + ok( !prev_state, "prev_state = %x\n", prev_state ); + + status = pNtSetEvent( Event, &prev_state ); + ok( status == STATUS_SUCCESS, "NtSetEvent failed: %08x\n", status ); + ok( !prev_state, "prev_state = %x\n", prev_state ); + + status = pNtPulseEvent( Event, &prev_state ); + ok( status == STATUS_SUCCESS, "NtPulseEvent failed %08x\n", status ); + ok( prev_state == 1, "prev_state = %x\n", prev_state ); + + pNtClose(Event); +} + +static const WCHAR keyed_nameW[] = L"\\BaseNamedObjects\\WineTestEvent"; + +static DWORD WINAPI keyed_event_thread( void *arg ) +{ + HANDLE handle; + NTSTATUS status; + LARGE_INTEGER timeout; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING str; + ULONG_PTR i; + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &str; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + RtlInitUnicodeString( &str, keyed_nameW ); + + status = pNtOpenKeyedEvent( &handle, KEYEDEVENT_ALL_ACCESS, &attr ); + ok( !status, "NtOpenKeyedEvent failed %x\n", status ); + + for (i = 0; i < 20; i++) + { + if (i & 1) + status = pNtWaitForKeyedEvent( handle, (void *)(i * 2), 0, NULL ); + else + status = pNtReleaseKeyedEvent( handle, (void *)(i * 2), 0, NULL ); + ok( status == STATUS_SUCCESS, "%li: failed %x\n", i, status ); + Sleep( 20 - i ); + } + + status = pNtReleaseKeyedEvent( handle, (void *)0x1234, 0, NULL ); + ok( status == STATUS_SUCCESS, "NtReleaseKeyedEvent %x\n", status ); + + timeout.QuadPart = -10000; + status = pNtWaitForKeyedEvent( handle, (void *)0x5678, 0, &timeout ); + ok( status == STATUS_TIMEOUT, "NtWaitForKeyedEvent %x\n", status ); + status = pNtReleaseKeyedEvent( handle, (void *)0x9abc, 0, &timeout ); + ok( status == STATUS_TIMEOUT, "NtReleaseKeyedEvent %x\n", status ); + + NtClose( handle ); + return 0; +} + +static void test_keyed_events(void) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING str; + HANDLE handle, event, thread; + NTSTATUS status; + LARGE_INTEGER timeout; + ULONG_PTR i; + + if (!pNtCreateKeyedEvent) + { + win_skip( "Keyed events not supported\n" ); + return; + } + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &str; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + RtlInitUnicodeString( &str, keyed_nameW ); + + status = pNtCreateKeyedEvent( &handle, KEYEDEVENT_ALL_ACCESS | SYNCHRONIZE, &attr, 0 ); + ok( !status, "NtCreateKeyedEvent failed %x\n", status ); + + status = WaitForSingleObject( handle, 1000 ); + ok( status == 0, "WaitForSingleObject %x\n", status ); + + timeout.QuadPart = -100000; + status = pNtWaitForKeyedEvent( handle, (void *)255, 0, &timeout ); + ok( status == STATUS_INVALID_PARAMETER_1, "NtWaitForKeyedEvent %x\n", status ); + status = pNtReleaseKeyedEvent( handle, (void *)255, 0, &timeout ); + ok( status == STATUS_INVALID_PARAMETER_1, "NtReleaseKeyedEvent %x\n", status ); + + status = pNtWaitForKeyedEvent( handle, (void *)254, 0, &timeout ); + ok( status == STATUS_TIMEOUT, "NtWaitForKeyedEvent %x\n", status ); + status = pNtReleaseKeyedEvent( handle, (void *)254, 0, &timeout ); + ok( status == STATUS_TIMEOUT, "NtReleaseKeyedEvent %x\n", status ); + + status = pNtWaitForKeyedEvent( handle, NULL, 0, &timeout ); + ok( status == STATUS_TIMEOUT, "NtWaitForKeyedEvent %x\n", status ); + status = pNtReleaseKeyedEvent( handle, NULL, 0, &timeout ); + ok( status == STATUS_TIMEOUT, "NtReleaseKeyedEvent %x\n", status ); + + status = pNtWaitForKeyedEvent( NULL, (void *)8, 0, &timeout ); + ok( status == STATUS_TIMEOUT || broken(status == STATUS_INVALID_HANDLE), /* XP/2003 */ + "NtWaitForKeyedEvent %x\n", status ); + status = pNtReleaseKeyedEvent( NULL, (void *)8, 0, &timeout ); + ok( status == STATUS_TIMEOUT || broken(status == STATUS_INVALID_HANDLE), /* XP/2003 */ + "NtReleaseKeyedEvent %x\n", status ); + + status = pNtWaitForKeyedEvent( (HANDLE)0xdeadbeef, (void *)9, 0, &timeout ); + ok( status == STATUS_INVALID_PARAMETER_1, "NtWaitForKeyedEvent %x\n", status ); + status = pNtReleaseKeyedEvent( (HANDLE)0xdeadbeef, (void *)9, 0, &timeout ); + ok( status == STATUS_INVALID_PARAMETER_1, "NtReleaseKeyedEvent %x\n", status ); + + status = pNtWaitForKeyedEvent( (HANDLE)0xdeadbeef, (void *)8, 0, &timeout ); + ok( status == STATUS_INVALID_HANDLE, "NtWaitForKeyedEvent %x\n", status ); + status = pNtReleaseKeyedEvent( (HANDLE)0xdeadbeef, (void *)8, 0, &timeout ); + ok( status == STATUS_INVALID_HANDLE, "NtReleaseKeyedEvent %x\n", status ); + + thread = CreateThread( NULL, 0, keyed_event_thread, 0, 0, NULL ); + for (i = 0; i < 20; i++) + { + if (i & 1) + status = pNtReleaseKeyedEvent( handle, (void *)(i * 2), 0, NULL ); + else + status = pNtWaitForKeyedEvent( handle, (void *)(i * 2), 0, NULL ); + ok( status == STATUS_SUCCESS, "%li: failed %x\n", i, status ); + Sleep( i ); + } + status = pNtWaitForKeyedEvent( handle, (void *)0x1234, 0, &timeout ); + ok( status == STATUS_SUCCESS, "NtWaitForKeyedEvent %x\n", status ); + status = pNtWaitForKeyedEvent( handle, (void *)0x5678, 0, &timeout ); + ok( status == STATUS_TIMEOUT, "NtWaitForKeyedEvent %x\n", status ); + status = pNtReleaseKeyedEvent( handle, (void *)0x9abc, 0, &timeout ); + ok( status == STATUS_TIMEOUT, "NtReleaseKeyedEvent %x\n", status ); + + ok( WaitForSingleObject( thread, 30000 ) == 0, "wait failed\n" ); + + NtClose( handle ); + + /* test access rights */ + + status = pNtCreateKeyedEvent( &handle, KEYEDEVENT_WAIT, &attr, 0 ); + ok( !status, "NtCreateKeyedEvent failed %x\n", status ); + status = pNtWaitForKeyedEvent( handle, (void *)8, 0, &timeout ); + ok( status == STATUS_TIMEOUT, "NtWaitForKeyedEvent %x\n", status ); + status = pNtReleaseKeyedEvent( handle, (void *)8, 0, &timeout ); + ok( status == STATUS_ACCESS_DENIED, "NtReleaseKeyedEvent %x\n", status ); + NtClose( handle ); + + status = pNtCreateKeyedEvent( &handle, KEYEDEVENT_WAKE, &attr, 0 ); + ok( !status, "NtCreateKeyedEvent failed %x\n", status ); + status = pNtWaitForKeyedEvent( handle, (void *)8, 0, &timeout ); + ok( status == STATUS_ACCESS_DENIED, "NtWaitForKeyedEvent %x\n", status ); + status = pNtReleaseKeyedEvent( handle, (void *)8, 0, &timeout ); + ok( status == STATUS_TIMEOUT, "NtReleaseKeyedEvent %x\n", status ); + NtClose( handle ); + + status = pNtCreateKeyedEvent( &handle, KEYEDEVENT_ALL_ACCESS, &attr, 0 ); + ok( !status, "NtCreateKeyedEvent failed %x\n", status ); + status = WaitForSingleObject( handle, 1000 ); + ok( status == WAIT_FAILED && GetLastError() == ERROR_ACCESS_DENIED, + "WaitForSingleObject %x err %u\n", status, GetLastError() ); + status = pNtWaitForKeyedEvent( handle, (void *)8, 0, &timeout ); + ok( status == STATUS_TIMEOUT, "NtWaitForKeyedEvent %x\n", status ); + status = pNtReleaseKeyedEvent( handle, (void *)8, 0, &timeout ); + ok( status == STATUS_TIMEOUT, "NtReleaseKeyedEvent %x\n", status ); + NtClose( handle ); + + /* GENERIC_READ gives wait access */ + status = pNtCreateKeyedEvent( &handle, GENERIC_READ, &attr, 0 ); + ok( !status, "NtCreateKeyedEvent failed %x\n", status ); + status = pNtWaitForKeyedEvent( handle, (void *)8, 0, &timeout ); + ok( status == STATUS_TIMEOUT, "NtWaitForKeyedEvent %x\n", status ); + status = pNtReleaseKeyedEvent( handle, (void *)8, 0, &timeout ); + ok( status == STATUS_ACCESS_DENIED, "NtReleaseKeyedEvent %x\n", status ); + NtClose( handle ); + + /* GENERIC_WRITE gives wake access */ + status = pNtCreateKeyedEvent( &handle, GENERIC_WRITE, &attr, 0 ); + ok( !status, "NtCreateKeyedEvent failed %x\n", status ); + status = pNtWaitForKeyedEvent( handle, (void *)8, 0, &timeout ); + ok( status == STATUS_ACCESS_DENIED, "NtWaitForKeyedEvent %x\n", status ); + status = pNtReleaseKeyedEvent( handle, (void *)8, 0, &timeout ); + ok( status == STATUS_TIMEOUT, "NtReleaseKeyedEvent %x\n", status ); + + /* it's not an event */ + status = pNtPulseEvent( handle, NULL ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtPulseEvent %x\n", status ); + + status = pNtCreateEvent( &event, GENERIC_ALL, &attr, FALSE, FALSE ); + ok( status == STATUS_OBJECT_NAME_COLLISION || status == STATUS_OBJECT_TYPE_MISMATCH, + "CreateEvent %x\n", status ); + + NtClose( handle ); + + status = pNtCreateEvent( &event, GENERIC_ALL, &attr, FALSE, FALSE ); + ok( status == 0, "CreateEvent %x\n", status ); + status = pNtWaitForKeyedEvent( event, (void *)8, 0, &timeout ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtWaitForKeyedEvent %x\n", status ); + status = pNtReleaseKeyedEvent( event, (void *)8, 0, &timeout ); + ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtReleaseKeyedEvent %x\n", status ); + NtClose( event ); +} + +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) +{ + MUTANT_BASIC_INFORMATION info; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING str; + NTSTATUS status; + HANDLE mutant; + HANDLE thread; + DWORD ret; + ULONG len; + LONG prev; + + pRtlInitUnicodeString(&str, L"\\BaseNamedObjects\\test_mutant"); + 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 ); + 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 ); + 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 ); +} + +static void test_wait_on_address(void) +{ + DWORD ticks; + SIZE_T size; + NTSTATUS status; + LARGE_INTEGER timeout; + LONG64 address, compare; + + if (!pRtlWaitOnAddress) + { + win_skip("RtlWaitOnAddress not supported, skipping test\n"); + return; + } + + if (0) /* crash on Windows */ + { + pRtlWaitOnAddress(&address, NULL, 8, NULL); + pRtlWaitOnAddress(NULL, &compare, 8, NULL); + pRtlWaitOnAddress(NULL, NULL, 8, NULL); + } + + /* don't crash */ + pRtlWakeAddressSingle(NULL); + pRtlWakeAddressAll(NULL); + + /* invalid values */ + address = 0; + compare = 0; + status = pRtlWaitOnAddress(&address, &compare, 5, NULL); + ok(status == STATUS_INVALID_PARAMETER, "got %x\n", status); + + /* values match */ + address = 0; + compare = 0; + pNtQuerySystemTime(&timeout); + timeout.QuadPart += 100*10000; + ticks = GetTickCount(); + status = pRtlWaitOnAddress(&address, &compare, 8, &timeout); + ticks = GetTickCount() - ticks; + ok(status == STATUS_TIMEOUT, "got 0x%08x\n", status); + ok(ticks >= 90 && ticks <= 1000, "got %u\n", ticks); + ok(address == 0, "got %s\n", wine_dbgstr_longlong(address)); + ok(compare == 0, "got %s\n", wine_dbgstr_longlong(compare)); + + /* different address size */ + for (size = 1; size <= 4; size <<= 1) + { + compare = ~0; + compare <<= size * 8; + + timeout.QuadPart = -100 * 10000; + ticks = GetTickCount(); + status = pRtlWaitOnAddress(&address, &compare, size, &timeout); + ticks = GetTickCount() - ticks; + ok(status == STATUS_TIMEOUT, "got 0x%08x\n", status); + ok(ticks >= 90 && ticks <= 1000, "got %u\n", ticks); + + status = pRtlWaitOnAddress(&address, &compare, size << 1, &timeout); + ok(!status, "got 0x%08x\n", status); + } + address = 0; + compare = 1; + status = pRtlWaitOnAddress(&address, &compare, 8, NULL); + ok(!status, "got 0x%08x\n", status); + + /* no waiters */ + address = 0; + pRtlWakeAddressSingle(&address); + ok(address == 0, "got %s\n", wine_dbgstr_longlong(address)); + pRtlWakeAddressAll(&address); + ok(address == 0, "got %s\n", wine_dbgstr_longlong(address)); +} + +START_TEST(sync) +{ + HMODULE module = GetModuleHandleA("ntdll.dll"); + + pNtClose = (void *)GetProcAddress(module, "NtClose"); + pNtCreateEvent = (void *)GetProcAddress(module, "NtCreateEvent"); + pNtCreateKeyedEvent = (void *)GetProcAddress(module, "NtCreateKeyedEvent"); + pNtCreateMutant = (void *)GetProcAddress(module, "NtCreateMutant"); + pNtOpenEvent = (void *)GetProcAddress(module, "NtOpenEvent"); + pNtOpenKeyedEvent = (void *)GetProcAddress(module, "NtOpenKeyedEvent"); + pNtPulseEvent = (void *)GetProcAddress(module, "NtPulseEvent"); + pNtQueryEvent = (void *)GetProcAddress(module, "NtQueryEvent"); + pNtQueryMutant = (void *)GetProcAddress(module, "NtQueryMutant"); + pNtQuerySystemTime = (void *)GetProcAddress(module, "NtQuerySystemTime"); + pNtReleaseKeyedEvent = (void *)GetProcAddress(module, "NtReleaseKeyedEvent"); + pNtReleaseMutant = (void *)GetProcAddress(module, "NtReleaseMutant"); + pNtResetEvent = (void *)GetProcAddress(module, "NtResetEvent"); + pNtSetEvent = (void *)GetProcAddress(module, "NtSetEvent"); + pNtWaitForKeyedEvent = (void *)GetProcAddress(module, "NtWaitForKeyedEvent"); + pRtlInitUnicodeString = (void *)GetProcAddress(module, "RtlInitUnicodeString"); + pRtlWaitOnAddress = (void *)GetProcAddress(module, "RtlWaitOnAddress"); + pRtlWakeAddressAll = (void *)GetProcAddress(module, "RtlWakeAddressAll"); + pRtlWakeAddressSingle = (void *)GetProcAddress(module, "RtlWakeAddressSingle"); + + test_wait_on_address(); + test_event(); + test_mutant(); + test_keyed_events(); +} -- 2.29.2