Some applications rely on this behavior.
-- v5: kernel32/tests: Add more tests for waits on pseudo-handles.
From: Marc-Aurel Zent mzent@codeweavers.com
--- dlls/kernelbase/sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/kernelbase/sync.c b/dlls/kernelbase/sync.c index 40aec41e5c8..31620a1aad2 100644 --- a/dlls/kernelbase/sync.c +++ b/dlls/kernelbase/sync.c @@ -438,7 +438,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH WaitForMultipleObjectsEx( DWORD count, const HAND
status = NtWaitForMultipleObjects( count, hloc, wait_all ? WaitAll : WaitAny, alertable, get_nt_timeout( &time, timeout ) ); - if (HIWORD(status)) /* is it an error code? */ + if (NT_ERROR(status)) { SetLastError( RtlNtStatusToDosError(status) ); status = WAIT_FAILED;
From: Marc-Aurel Zent mzent@codeweavers.com
--- dlls/kernelbase/sync.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/dlls/kernelbase/sync.c b/dlls/kernelbase/sync.c index 31620a1aad2..3948f7ea4bd 100644 --- a/dlls/kernelbase/sync.c +++ b/dlls/kernelbase/sync.c @@ -395,7 +395,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH UnregisterWaitEx( HANDLE handle, HANDLE event ) */ DWORD WINAPI DECLSPEC_HOTPATCH WaitForSingleObject( HANDLE handle, DWORD timeout ) { - return WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, FALSE ); + return WaitForSingleObjectEx( handle, timeout, FALSE ); }
@@ -404,7 +404,18 @@ DWORD WINAPI DECLSPEC_HOTPATCH WaitForSingleObject( HANDLE handle, DWORD timeout */ DWORD WINAPI DECLSPEC_HOTPATCH WaitForSingleObjectEx( HANDLE handle, DWORD timeout, BOOL alertable ) { - return WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, alertable ); + NTSTATUS status; + LARGE_INTEGER time; + + status = NtWaitForSingleObject( normalize_std_handle( handle ), alertable, + get_nt_timeout( &time, timeout ) ); + + if (NT_ERROR(status)) + { + SetLastError( RtlNtStatusToDosError(status) ); + status = WAIT_FAILED; + } + return status; }
From: Marc-Aurel Zent mzent@codeweavers.com
Also fixes an off-by-one error in the pseudo-handle check. --- dlls/ntdll/unix/sync.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 07ffe854104..ef6dfe1e2c1 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -556,6 +556,11 @@ static inline unsigned int inproc_sync_handle_to_index( HANDLE handle, unsigned return idx % INPROC_SYNC_CACHE_BLOCK_SIZE; }
+static inline BOOL is_pseudo_handle( HANDLE handle ) +{ + return ((ULONG)(ULONG_PTR)handle >= 0xfffffffa); +} + static struct inproc_sync *cache_inproc_sync( HANDLE handle, struct inproc_sync *sync ) { unsigned int entry, idx = inproc_sync_handle_to_index( handle, &entry ); @@ -563,7 +568,7 @@ static struct inproc_sync *cache_inproc_sync( HANDLE handle, struct inproc_sync int refcount;
/* don't cache pseudo-handles; waiting on them is pointless anyway */ - if ((ULONG)(ULONG_PTR)handle > 0xfffffffa) return sync; + if (is_pseudo_handle( handle )) return sync;
if (entry >= INPROC_SYNC_CACHE_ENTRIES) {
From: Marc-Aurel Zent mzent@codeweavers.com
--- dlls/ntdll/unix/sync.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index ef6dfe1e2c1..c07d318fd1e 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -2338,7 +2338,24 @@ NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, WA */ NTSTATUS WINAPI NtWaitForSingleObject( HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { - return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout ); + union select_op select_op; + UINT flags = SELECT_INTERRUPTIBLE; + unsigned int ret; + + TRACE( "handle %p, alertable %u, timeout %s\n", handle, alertable, debugstr_timeout(timeout) ); + + if ((ret = inproc_wait( 1, &handle, WaitAny, alertable, timeout )) != STATUS_NOT_IMPLEMENTED) + { + TRACE( "-> %#x\n", ret ); + return ret; + } + + if (alertable) flags |= SELECT_ALERTABLE; + select_op.wait.op = SELECT_WAIT; + select_op.wait.handles[0] = wine_server_obj_handle( handle ); + ret = server_wait( &select_op, offsetof( union select_op, wait.handles[1] ), flags, timeout ); + TRACE( "-> %#x\n", ret ); + return ret; }
From: Marc-Aurel Zent mzent@codeweavers.com
--- dlls/kernel32/tests/sync.c | 16 ++++++++-------- dlls/ntdll/unix/sync.c | 5 +++++ 2 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index 466bbc8908b..30ea72907ef 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -1432,26 +1432,26 @@ static void test_WaitForMultipleObjects(void) maxevents[0] = GetCurrentProcess(); SetLastError(0xdeadbeef); r = WaitForMultipleObjects(1, maxevents, FALSE, 100); - todo_wine ok(r == WAIT_FAILED, "expected WAIT_FAILED, got %lu\n", r); - todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, - "expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); + ok(r == WAIT_FAILED, "expected WAIT_FAILED, got %lu\n", r); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError());
maxevents[0] = GetCurrentThread(); SetLastError(0xdeadbeef); r = WaitForMultipleObjects(1, maxevents, FALSE, 100); - todo_wine ok(r == WAIT_FAILED, "expected WAIT_FAILED, got %lu\n", r); - todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, - "expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); + ok(r == WAIT_FAILED, "expected WAIT_FAILED, got %lu\n", r); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError());
timeout.QuadPart = -1000000; maxevents[0] = GetCurrentProcess(); status = pNtWaitForMultipleObjects(1, maxevents, WaitAny, FALSE, &timeout); - todo_wine ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status); + ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status);
timeout.QuadPart = -1000000; maxevents[0] = GetCurrentThread(); status = pNtWaitForMultipleObjects(1, maxevents, WaitAny, FALSE, &timeout); - todo_wine ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status); + ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status); }
static BOOL g_initcallback_ret, g_initcallback_called; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index c07d318fd1e..b080d61fcf5 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -2318,6 +2318,11 @@ NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, WA TRACE( "}, timeout %s\n", debugstr_timeout(timeout) ); }
+ /* Reject pseudo-handles up front. These are not valid for multi-object waits. */ + for (i = 0; i < count; i++) + if (is_pseudo_handle( handles[i] )) + return STATUS_INVALID_HANDLE; + if ((ret = inproc_wait( count, handles, type, alertable, timeout )) != STATUS_NOT_IMPLEMENTED) { TRACE( "-> %#x\n", ret );
From: Marc-Aurel Zent mzent@codeweavers.com
--- include/winbase.h | 36 +++++++++++++++++++++--------------- include/winternl.h | 8 ++++++-- 2 files changed, 27 insertions(+), 17 deletions(-)
diff --git a/include/winbase.h b/include/winbase.h index c96f58a61b3..4ae800bfc46 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -2657,6 +2657,9 @@ extern WCHAR * CDECL wine_get_dos_file_name( const char * ) __WINE_DEALLOC(HeapF
#define GetCurrentProcess() NtCurrentProcess() #define GetCurrentThread() NtCurrentThread() +#define GetCurrentProcessToken() NtCurrentProcessToken() +#define GetCurrentThreadToken() NtCurrentThreadToken() +#define GetCurrentThreadEffectiveToken() NtCurrentEffectiveToken() #define GetCurrentProcessId() HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess) #define GetCurrentThreadId() HandleToULong(NtCurrentTeb()->ClientId.UniqueThread)
@@ -2682,6 +2685,21 @@ static FORCEINLINE DWORD WINAPI GetCurrentThreadId(void) return HandleToULong( ((HANDLE *)NtCurrentTeb())[9] ); }
+static FORCEINLINE HANDLE WINAPI GetCurrentProcessToken(void) +{ + return (HANDLE)~(ULONG_PTR)3; +} + +static FORCEINLINE HANDLE WINAPI GetCurrentThreadToken(void) +{ + return (HANDLE)~(ULONG_PTR)4; +} + +static FORCEINLINE HANDLE WINAPI GetCurrentThreadEffectiveToken(void) +{ + return (HANDLE)~(ULONG_PTR)5; +} + static FORCEINLINE DWORD WINAPI GetLastError(void) { return *(DWORD *)((void **)NtCurrentTeb() + 13); @@ -2703,27 +2721,15 @@ WINBASEAPI HANDLE WINAPI GetCurrentProcess(void); WINBASEAPI DWORD WINAPI GetCurrentProcessId(void); WINBASEAPI HANDLE WINAPI GetCurrentThread(void); WINBASEAPI DWORD WINAPI GetCurrentThreadId(void); +WINBASEAPI HANDLE WINAPI GetCurrentProcessToken(void); +WINBASEAPI HANDLE WINAPI GetCurrentThreadToken(void); +WINBASEAPI HANDLE WINAPI GetCurrentThreadEffectiveToken(void); WINBASEAPI DWORD WINAPI GetLastError(void); WINBASEAPI HANDLE WINAPI GetProcessHeap(void); WINBASEAPI VOID WINAPI SetLastError(DWORD);
#endif /* __WINESRC__ */
-static FORCEINLINE HANDLE WINAPI GetCurrentProcessToken(void) -{ - return (HANDLE)~(ULONG_PTR)3; -} - -static FORCEINLINE HANDLE WINAPI GetCurrentThreadToken(void) -{ - return (HANDLE)~(ULONG_PTR)4; -} - -static FORCEINLINE HANDLE WINAPI GetCurrentThreadEffectiveToken(void) -{ - return (HANDLE)~(ULONG_PTR)5; -} - /* WinMain(entry point) must be declared in winbase.h. */ /* If this is not declared, we cannot compile many sources written with C++. */ int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int); diff --git a/include/winternl.h b/include/winternl.h index d94b9911c74..7dea51d2f93 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -5284,8 +5284,12 @@ NTSYSAPI NTSTATUS WINAPI RtlLargeIntegerToChar(const ULONGLONG *,ULONG,ULONG,PC * Inline functions */
-#define NtCurrentProcess() ((HANDLE)~(ULONG_PTR)0) -#define NtCurrentThread() ((HANDLE)~(ULONG_PTR)1) +#define NtCurrentProcess() ((HANDLE)~(ULONG_PTR)0) +#define NtCurrentThread() ((HANDLE)~(ULONG_PTR)1) +#define NtCurrentSession() ((HANDLE)~(ULONG_PTR)2) +#define NtCurrentProcessToken() ((HANDLE)~(ULONG_PTR)3) +#define NtCurrentThreadToken() ((HANDLE)~(ULONG_PTR)4) +#define NtCurrentEffectiveToken() ((HANDLE)~(ULONG_PTR)5)
#define RtlFillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length)) #define RtlMoveMemory(Destination,Source,Length) memmove((Destination),(Source),(Length))
From: Marc-Aurel Zent mzent@codeweavers.com
Also improve some formatting in surrounding for-loops. --- dlls/kernel32/tests/sync.c | 176 +++++++++++++++++++++++++++++-------- 1 file changed, 137 insertions(+), 39 deletions(-)
diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index 30ea72907ef..e7f8a316016 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -1291,6 +1291,22 @@ static void test_WaitForSingleObject(void) LARGE_INTEGER timeout; NTSTATUS status; DWORD ret; + int i; + HANDLE waitable_pseudohandles[] = { + NtCurrentProcess(), + NtCurrentThread(), + }; + HANDLE non_waitable_pseudohandles[] = { + NtCurrentSession(), + NtCurrentProcessToken(), + NtCurrentThreadToken(), + NtCurrentEffectiveToken(), + }; + HANDLE std_handles[] = { + (HANDLE)STD_INPUT_HANDLE, + (HANDLE)STD_OUTPUT_HANDLE, + (HANDLE)STD_ERROR_HANDLE, + };
signaled = CreateEventW(NULL, TRUE, TRUE, NULL); nonsignaled = CreateEventW(NULL, TRUE, FALSE, NULL); @@ -1359,20 +1375,44 @@ static void test_WaitForSingleObject(void) ok(ret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %ld\n", ret); ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %ld\n", GetLastError());
- /* pseudo handles are allowed in WaitForSingleObject and NtWaitForSingleObject */ - ret = WaitForSingleObject(GetCurrentProcess(), 100); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %lu\n", ret); + /* waitable pseudo-handles are allowed in WaitForSingleObject and NtWaitForSingleObject, + * but not in NtWaitForMultipleObjects, see test_WaitForMultipleObjects */ + for (i = 0; i < ARRAY_SIZE(waitable_pseudohandles); i++) + { + ret = WaitForSingleObject(waitable_pseudohandles[i], 0); + ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %lu\n", ret);
- ret = WaitForSingleObject(GetCurrentThread(), 100); - ok(ret == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %lu\n", ret); + timeout.QuadPart = 0; + status = pNtWaitForSingleObject(waitable_pseudohandles[i], FALSE, &timeout); + ok(status == STATUS_TIMEOUT, "expected STATUS_TIMEOUT, got %08lx\n", status); + }
- timeout.QuadPart = -1000000; - status = pNtWaitForSingleObject(GetCurrentProcess(), FALSE, &timeout); - ok(status == STATUS_TIMEOUT, "expected STATUS_TIMEOUT, got %08lx\n", status); + /* non-waitable pseudo-handles return STATUS_INVALID_HANDLE */ + for (i = 0; i < ARRAY_SIZE(non_waitable_pseudohandles); i++) + { + SetLastError(0xdeadbeef); + ret = WaitForSingleObject(non_waitable_pseudohandles[i], 0); + ok(ret == WAIT_FAILED, "expected WAIT_FAILED, got %ld\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError()); + + status = pNtWaitForSingleObject(non_waitable_pseudohandles[i], FALSE, NULL); + todo_wine_if((non_waitable_pseudohandles[i] == NtCurrentProcessToken() || + non_waitable_pseudohandles[i] == NtCurrentEffectiveToken()) && + status == STATUS_OBJECT_TYPE_MISMATCH) + ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status); + }
- timeout.QuadPart = -1000000; - status = pNtWaitForSingleObject(GetCurrentThread(), FALSE, &timeout); - ok(status == STATUS_TIMEOUT, "expected STATUS_TIMEOUT, got %08lx\n", status); + /* std handles are only allowed in WaitForSingleObject and not NtWaitForSingleObject */ + for (i = 0; i < ARRAY_SIZE(std_handles); i++) + { + ret = WaitForSingleObject(std_handles[i], 100); + ok(ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT, + "expected WAIT_OBJECT_0 or WAIT_TIMEOUT), got %lu, GetLastError()=%lu\n", + ret, GetLastError()); + + status = pNtWaitForSingleObject(std_handles[i], FALSE, NULL); + ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status); + }
CloseHandle(signaled); CloseHandle(nonsignaled); @@ -1380,15 +1420,27 @@ static void test_WaitForSingleObject(void)
static void test_WaitForMultipleObjects(void) { - LARGE_INTEGER timeout; NTSTATUS status; DWORD r; int i; HANDLE maxevents[MAXIMUM_WAIT_OBJECTS]; + HANDLE pseudohandles[] = { + NtCurrentProcess(), + NtCurrentThread(), + NtCurrentSession(), + NtCurrentProcessToken(), + NtCurrentThreadToken(), + NtCurrentEffectiveToken(), + }; + HANDLE std_handles[] = { + (HANDLE)STD_INPUT_HANDLE, + (HANDLE)STD_OUTPUT_HANDLE, + (HANDLE)STD_ERROR_HANDLE, + };
/* create the maximum number of events and make sure * we can wait on that many */ - for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++) + for (i = 0; i < MAXIMUM_WAIT_OBJECTS; i++) { maxevents[i] = CreateEventW(NULL, i==0, TRUE, NULL); ok( maxevents[i] != 0, "should create enough events\n"); @@ -1400,7 +1452,7 @@ static void test_WaitForMultipleObjects(void) r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, FALSE, 0); ok( r == WAIT_OBJECT_0, "should signal handle #0 first, got %ld\n", r); ok(ResetEvent(maxevents[0]), "ResetEvent\n"); - for (i=1; i<MAXIMUM_WAIT_OBJECTS; i++) + for (i = 1; i < MAXIMUM_WAIT_OBJECTS; i++) { /* the lowest index is checked first and remaining events are untouched */ r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, FALSE, 0); @@ -1408,7 +1460,7 @@ static void test_WaitForMultipleObjects(void) }
/* run same test with Nt* call */ - for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++) + for (i = 0; i < MAXIMUM_WAIT_OBJECTS; i++) SetEvent(maxevents[i]);
/* a manual-reset event remains signaled, an auto-reset event is cleared */ @@ -1417,41 +1469,87 @@ static void test_WaitForMultipleObjects(void) status = pNtWaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, WaitAny, FALSE, NULL); ok(status == STATUS_WAIT_0, "should signal handle #0 first, got %08lx\n", status); ok(ResetEvent(maxevents[0]), "ResetEvent\n"); - for (i=1; i<MAXIMUM_WAIT_OBJECTS; i++) + for (i = 1; i < MAXIMUM_WAIT_OBJECTS; i++) { /* the lowest index is checked first and remaining events are untouched */ status = pNtWaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, WaitAny, FALSE, NULL); ok(status == STATUS_WAIT_0 + i, "should signal handle #%d first, got %08lx\n", i, status); }
- for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++) - if (maxevents[i]) CloseHandle(maxevents[i]); + CloseHandle(maxevents[0]);
- /* in contrast to WaitForSingleObject, pseudo handles are not allowed in + /* in contrast to WaitForSingleObject, all pseudo-handles are not allowed in * WaitForMultipleObjects and NtWaitForMultipleObjects */ - maxevents[0] = GetCurrentProcess(); - SetLastError(0xdeadbeef); - r = WaitForMultipleObjects(1, maxevents, FALSE, 100); - ok(r == WAIT_FAILED, "expected WAIT_FAILED, got %lu\n", r); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); + for (i = 0; i < ARRAY_SIZE(pseudohandles); i++) + { + maxevents[0] = pseudohandles[i]; + SetLastError(0xdeadbeef); + r = WaitForMultipleObjects(1, maxevents, FALSE, 0); + ok(r == WAIT_FAILED, "expected WAIT_FAILED, got %lu\n", r); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError());
- maxevents[0] = GetCurrentThread(); - SetLastError(0xdeadbeef); - r = WaitForMultipleObjects(1, maxevents, FALSE, 100); - ok(r == WAIT_FAILED, "expected WAIT_FAILED, got %lu\n", r); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); + status = pNtWaitForMultipleObjects(1, maxevents, WaitAny, FALSE, NULL); + ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status); + + /* also not allowed with a wait count greater than 1 with both WaitAny and WaitAll */ + SetLastError(0xdeadbeef); + r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, FALSE, 0); + ok(r == WAIT_FAILED, "expected WAIT_FAILED, got %lu\n", r); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); + SetLastError(0xdeadbeef); + r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, TRUE, 0); + ok(r == WAIT_FAILED, "expected WAIT_FAILED, got %lu\n", r); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); + + status = pNtWaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, WaitAny, FALSE, NULL); + ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status); + status = pNtWaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, WaitAll, FALSE, NULL); + ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status); + + /* irrespective of the index that contains the pseudo handle for both wait types */ + maxevents[0] = maxevents[MAXIMUM_WAIT_OBJECTS - 1]; + maxevents[MAXIMUM_WAIT_OBJECTS - 1] = pseudohandles[i]; + SetLastError(0xdeadbeef); + r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, FALSE, 0); + ok(r == WAIT_FAILED, "expected WAIT_FAILED, got %lu\n", r); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); + SetLastError(0xdeadbeef); + r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, TRUE, 0); + ok(r == WAIT_FAILED, "expected WAIT_FAILED, got %lu\n", r); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "expected ERROR_INVALID_HANDLE, got %lu\n", GetLastError()); + + status = pNtWaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, WaitAny, FALSE, NULL); + ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status); + status = pNtWaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, WaitAll, FALSE, NULL); + ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status); + maxevents[MAXIMUM_WAIT_OBJECTS - 1] = maxevents[0]; + } + + /* Similar to WaitForSingleObject std handles are only allowed in WaitForMultipleObjects and + * not NtWaitForMultipleObjects (for brevity we only test single count waits here) */ + for (i = 0; i < ARRAY_SIZE(std_handles); i++) + { + maxevents[0] = std_handles[i]; + SetLastError(0xdeadbeef); + r = WaitForMultipleObjects(1, maxevents, FALSE, 0); + ok(r == WAIT_OBJECT_0 || r == WAIT_TIMEOUT, + "expected WAIT_OBJECT_0 or WAIT_TIMEOUT), got %lu, GetLastError()=%lu\n", + r, GetLastError());
- timeout.QuadPart = -1000000; - maxevents[0] = GetCurrentProcess(); - status = pNtWaitForMultipleObjects(1, maxevents, WaitAny, FALSE, &timeout); - ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status); + status = pNtWaitForMultipleObjects(1, maxevents, WaitAny, FALSE, NULL); + ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status);
- timeout.QuadPart = -1000000; - maxevents[0] = GetCurrentThread(); - status = pNtWaitForMultipleObjects(1, maxevents, WaitAny, FALSE, &timeout); - ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status); + status = pNtWaitForMultipleObjects(1, maxevents, WaitAll, FALSE, NULL); + ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got %08lx\n", status); + } + + for (i = 1; i < MAXIMUM_WAIT_OBJECTS; i++) + if (maxevents[i]) CloseHandle(maxevents[i]); }
static BOOL g_initcallback_ret, g_initcallback_called;
On Thu Oct 30 23:19:03 2025 +0000, Marc-Aurel Zent wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/9305/diffs?diff_id=219969&start_sha=58d355666a5f27d456e5a50685ed490226463603#6a31f4cf2c4d24038e67fe3417ad92c8f1f6cfdc_2351_2353)
Fixed in v4.
On Thu Oct 30 23:19:03 2025 +0000, Marc-Aurel Zent wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/9305/diffs?diff_id=219969&start_sha=58d355666a5f27d456e5a50685ed490226463603#bde7f180050ff4134043396571b3f8d20aba512e_1552_1552)
I made the formatting of loops in both of the tests there consistent now.
On Thu Oct 30 23:19:02 2025 +0000, Marc-Aurel Zent wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/9305/diffs?diff_id=219969&start_sha=58d355666a5f27d456e5a50685ed490226463603#bde7f180050ff4134043396571b3f8d20aba512e_1545_1540)
Yeah it may randomly timeout or succeed, but the test does show that more clearly now.
On Thu Oct 30 23:38:37 2025 +0000, Paul Gofman wrote:
For completeness, I'd also add the same test with WaitAll after that (I checked locally that it works the same way at least on Win11).
Done.
On Thu Oct 30 23:39:23 2025 +0000, Paul Gofman wrote:
It is best to add '&& status == <wine_error_code>' to todo_wine_if, to test and illustrate clearly that Wine wait doesn't succeed in this special case but returns a different error code.
Added in v4 now.
On Thu Oct 30 23:19:02 2025 +0000, Marc-Aurel Zent wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/9305/diffs?diff_id=219969&start_sha=58d355666a5f27d456e5a50685ed490226463603#bde7f180050ff4134043396571b3f8d20aba512e_1399_1398)
For the multiple wait case we actually never need a timeout now with that.
On Thu Oct 30 23:43:33 2025 +0000, Paul Gofman wrote:
Here and throughout the rest of the test, whenever we expect timeout to happen, and when in this case it is not subject to interaction with any other place, we can just wait with 0 timeout (both for kerbelbase and Nt functions). Currently the added test increases the test run time greatly without good reason.
Fixed.
On Thu Oct 30 23:19:02 2025 +0000, Marc-Aurel Zent wrote:
changed this line in [version 4 of the diff](/wine/wine/-/merge_requests/9305/diffs?diff_id=219969&start_sha=58d355666a5f27d456e5a50685ed490226463603#bde7f180050ff4134043396571b3f8d20aba512e_1297_1297)
Fixed in v4.
On Thu Oct 30 19:27:31 2025 +0000, Paul Gofman wrote:
Do we need changes in this patch for anything? I am not finding, e. g., NtCurrentProcessToken() definition in Windows SDK. Can't we just use existing GetCurrentProcessToken() in the added tests?
We could use `GetCurrentProcessToken()`, but `NtCurrentProcessToken()` is a fixed compile time constant instead of a function and is a bit more pleasant to use (especially to initialize lists).
I also think it would be nice to have both the NT versions and Win32 ones for all of the pseudo-handles for consistencies sake.