Signed-off-by: Zebediah Figura z.figura12@gmail.com --- We have plenty of space in which to store a kernel handle inside a DISPATCHER_HEADER. However, the storage is volatile, and there is no way to know when to close it. Therefore, we create the handle when KeWaitForMultipleObjects() is called, and keep it open as long as at least one thread is waiting on the object.
dlls/ntoskrnl.exe/Makefile.in | 3 +- dlls/ntoskrnl.exe/ntoskrnl.c | 13 ----- dlls/ntoskrnl.exe/sync.c | 114 ++++++++++++++++++++++++++++++++++++++++++ include/ddk/ntddk.h | 9 ---- include/ddk/wdm.h | 10 ++++ 5 files changed, 126 insertions(+), 23 deletions(-) create mode 100644 dlls/ntoskrnl.exe/sync.c
diff --git a/dlls/ntoskrnl.exe/Makefile.in b/dlls/ntoskrnl.exe/Makefile.in index afb22fe3e0..8cafaada85 100644 --- a/dlls/ntoskrnl.exe/Makefile.in +++ b/dlls/ntoskrnl.exe/Makefile.in @@ -5,6 +5,7 @@ DELAYIMPORTS = setupapi user32
C_SRCS = \ instr.c \ - ntoskrnl.c + ntoskrnl.c \ + sync.c
RC_SRCS = ntoskrnl.rc diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 3b42e29b27..4c84a789d6 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -2488,19 +2488,6 @@ NTSTATUS WINAPI KeWaitForSingleObject(PVOID Object, return STATUS_NOT_IMPLEMENTED; }
-/*********************************************************************** - * KeWaitForMultipleObjects (NTOSKRNL.EXE.@) - */ -NTSTATUS WINAPI KeWaitForMultipleObjects(ULONG Count, PVOID Object[], WAIT_TYPE WaitType, - KWAIT_REASON WaitReason, KPROCESSOR_MODE WaitMode, - BOOLEAN Alertable, PLARGE_INTEGER Timeout, - PKWAIT_BLOCK WaitBlockArray) -{ - FIXME( "stub: %u, %p, %d, %d, %d, %d, %p, %p\n", Count, Object, WaitType, WaitReason, WaitMode, - Alertable, Timeout, WaitBlockArray ); - return STATUS_NOT_IMPLEMENTED; -} - /*********************************************************************** * IoRegisterFileSystem (NTOSKRNL.EXE.@) */ diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c new file mode 100644 index 0000000000..19af4f677a --- /dev/null +++ b/dlls/ntoskrnl.exe/sync.c @@ -0,0 +1,114 @@ +/* + * Kernel synchronization + * + * Copyright (C) 2018 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 <stdarg.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "ddk/ntddk.h" +#include "ddk/wdm.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl); + +enum object_type +{ + TYPE_MANUAL_EVENT = 0, + TYPE_AUTO_EVENT = 1, +}; + +static CRITICAL_SECTION sync_cs; +static CRITICAL_SECTION_DEBUG sync_cs_debug = +{ + 0, 0, &sync_cs, + { &sync_cs_debug.ProcessLocksList, &sync_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": sync_cs") } +}; +static CRITICAL_SECTION sync_cs = { &sync_cs_debug, -1, 0, 0, 0, 0 }; + +/*********************************************************************** + * KeWaitForMultipleObjects (NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI KeWaitForMultipleObjects(ULONG count, void *pobjs[], + WAIT_TYPE wait_type, KWAIT_REASON reason, KPROCESSOR_MODE mode, + BOOLEAN alertable, LARGE_INTEGER *timeout, KWAIT_BLOCK *wait_blocks) +{ + DISPATCHER_HEADER **objs = (DISPATCHER_HEADER **)pobjs; + HANDLE handles[MAXIMUM_WAIT_OBJECTS]; + NTSTATUS ret; + ULONG i; + + TRACE("count %u, objs %p, wait_type %u, reason %u, mode %d, alertable %u, timeout %p, wait_blocks %p.\n", + count, objs, wait_type, reason, mode, alertable, timeout, wait_blocks); + + /* We co-opt DISPATCHER_HEADER.WaitListHead: + * Blink stores a handle to the synchronization object, + * Flink stores the number of threads currently waiting on this object. */ + + EnterCriticalSection( &sync_cs ); + for (i = 0; i < count; i++) + { + ++*((ULONG_PTR *)&objs[i]->WaitListHead.Flink); + if (!objs[i]->WaitListHead.Blink) + { + switch (objs[i]->Type) + { + case TYPE_MANUAL_EVENT: + objs[i]->WaitListHead.Blink = CreateEventW( NULL, TRUE, objs[i]->SignalState, NULL ); + break; + case TYPE_AUTO_EVENT: + objs[i]->WaitListHead.Blink = CreateEventW( NULL, FALSE, objs[i]->SignalState, NULL ); + break; + } + } + + handles[i] = objs[i]->WaitListHead.Blink; + } + LeaveCriticalSection( &sync_cs ); + + ret = NtWaitForMultipleObjects( count, handles, (wait_type == WaitAny), alertable, timeout ); + + EnterCriticalSection( &sync_cs ); + for (i = 0; i < count; i++) + { + if (ret == i || (!ret && wait_type == WaitAll)) + { + switch (objs[i]->Type) + { + case TYPE_AUTO_EVENT: + objs[i]->SignalState = FALSE; + break; + } + } + + if (!--*((ULONG_PTR *)&objs[i]->WaitListHead.Flink)) + { + CloseHandle(objs[i]->WaitListHead.Blink); + objs[i]->WaitListHead.Blink = NULL; + } + } + LeaveCriticalSection( &sync_cs ); + + return ret; +} diff --git a/include/ddk/ntddk.h b/include/ddk/ntddk.h index fdf035d148..dc051e1e18 100644 --- a/include/ddk/ntddk.h +++ b/include/ddk/ntddk.h @@ -140,15 +140,6 @@ typedef struct _FILE_VALID_DATA_LENGTH_INFORMATION LARGE_INTEGER ValidDataLength; } FILE_VALID_DATA_LENGTH_INFORMATION, *PFILE_VALID_DATA_LENGTH_INFORMATION;
-typedef struct _KWAIT_BLOCK { - LIST_ENTRY WaitListEntry; - struct _KTHREAD *RESTRICTED_POINTER Thread; - PVOID Object; - struct _KWAIT_BLOCK *RESTRICTED_POINTER NextWaitBlock; - USHORT WaitKey; - USHORT WaitType; -} KWAIT_BLOCK, *PKWAIT_BLOCK, *RESTRICTED_POINTER PRKWAIT_BLOCK; - typedef struct _RTL_BALANCED_LINKS { struct _RTL_BALANCED_LINKS *Parent; struct _RTL_BALANCED_LINKS *LeftChild; diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index cd057d5a9f..ec2fc151ec 100644 --- a/include/ddk/wdm.h +++ b/include/ddk/wdm.h @@ -144,6 +144,15 @@ typedef enum _KWAIT_REASON MaximumWaitReason, } KWAIT_REASON;
+typedef struct _KWAIT_BLOCK { + LIST_ENTRY WaitListEntry; + struct _KTHREAD *RESTRICTED_POINTER Thread; + PVOID Object; + struct _KWAIT_BLOCK *RESTRICTED_POINTER NextWaitBlock; + USHORT WaitKey; + USHORT WaitType; +} KWAIT_BLOCK, *PKWAIT_BLOCK, *RESTRICTED_POINTER PRKWAIT_BLOCK; + typedef struct _ALLOCATE_FUNCTION *PALLOCATE_FUNCTION; typedef struct _IO_TIMER *PIO_TIMER; typedef struct _IO_TIMER_ROUTINE *PIO_TIMER_ROUTINE; @@ -1422,6 +1431,7 @@ LONG WINAPI KeResetEvent(PRKEVENT); LONG WINAPI KeSetEvent(PRKEVENT,KPRIORITY,BOOLEAN); KPRIORITY WINAPI KeSetPriorityThread(PKTHREAD,KPRIORITY); void WINAPI KeSetSystemAffinityThread(KAFFINITY); +NTSTATUS WINAPI KeWaitForMultipleObjects(ULONG,void*[],WAIT_TYPE,KWAIT_REASON,KPROCESSOR_MODE,BOOLEAN,LARGE_INTEGER*,KWAIT_BLOCK*);
PVOID WINAPI MmAllocateContiguousMemory(SIZE_T,PHYSICAL_ADDRESS); PVOID WINAPI MmAllocateNonCachedMemory(SIZE_T);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntoskrnl.exe/ntoskrnl.c | 9 --------- dlls/ntoskrnl.exe/sync.c | 13 +++++++++++++ include/ddk/wdm.h | 1 + 3 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 4c84a789d6..eb984bd838 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -2277,15 +2277,6 @@ PRKTHREAD WINAPI KeGetCurrentThread(void) return NULL; }
-/*********************************************************************** - * KeInitializeEvent (NTOSKRNL.EXE.@) - */ -void WINAPI KeInitializeEvent( PRKEVENT Event, EVENT_TYPE Type, BOOLEAN State ) -{ - FIXME( "stub: %p %d %d\n", Event, Type, State ); -} - - /*********************************************************************** * KeInitializeMutex (NTOSKRNL.EXE.@) */ diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c index 19af4f677a..e7ff7ec6f9 100644 --- a/dlls/ntoskrnl.exe/sync.c +++ b/dlls/ntoskrnl.exe/sync.c @@ -112,3 +112,16 @@ NTSTATUS WINAPI KeWaitForMultipleObjects(ULONG count, void *pobjs[],
return ret; } + +/*********************************************************************** + * KeInitializeEvent (NTOSKRNL.EXE.@) + */ +void WINAPI KeInitializeEvent( PRKEVENT event, EVENT_TYPE type, BOOLEAN state ) +{ + TRACE("event %p, type %u, state %u.\n", event, type, state); + + event->Header.Type = type; + event->Header.SignalState = state; + event->Header.WaitListHead.Blink = NULL; + event->Header.WaitListHead.Flink = NULL; +} diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index ec2fc151ec..dbbc5a11cf 100644 --- a/include/ddk/wdm.h +++ b/include/ddk/wdm.h @@ -1420,6 +1420,7 @@ NTSTATUS WINAPI IoSetDeviceInterfaceState(UNICODE_STRING*,BOOLEAN); NTSTATUS WINAPI IoWMIRegistrationControl(PDEVICE_OBJECT,ULONG);
PKTHREAD WINAPI KeGetCurrentThread(void); +void WINAPI KeInitializeEvent(PRKEVENT,EVENT_TYPE,BOOLEAN); void WINAPI KeInitializeSemaphore(PRKSEMAPHORE,LONG,LONG); void WINAPI KeInitializeTimerEx(PKTIMER,TIMER_TYPE); void WINAPI KeQuerySystemTime(LARGE_INTEGER*);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntoskrnl.exe/ntoskrnl.c | 10 ---------- dlls/ntoskrnl.exe/sync.c | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 10 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index eb984bd838..189f303d6a 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -2439,16 +2439,6 @@ LONG WINAPI KeResetEvent( PRKEVENT Event ) }
-/*********************************************************************** - * KeSetEvent (NTOSKRNL.EXE.@) - */ -LONG WINAPI KeSetEvent( PRKEVENT Event, KPRIORITY Increment, BOOLEAN Wait ) -{ - FIXME("(%p, %d, %d): stub\n", Event, Increment, Wait); - return 0; -} - - /*********************************************************************** * KeSetPriorityThread (NTOSKRNL.EXE.@) */ diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c index e7ff7ec6f9..05d50ef648 100644 --- a/dlls/ntoskrnl.exe/sync.c +++ b/dlls/ntoskrnl.exe/sync.c @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include "config.h" +#include "wine/port.h" #include <stdarg.h>
#include "ntstatus.h" @@ -125,3 +127,22 @@ void WINAPI KeInitializeEvent( PRKEVENT event, EVENT_TYPE type, BOOLEAN state ) event->Header.WaitListHead.Blink = NULL; event->Header.WaitListHead.Flink = NULL; } + +/*********************************************************************** + * KeSetEvent (NTOSKRNL.EXE.@) + */ +LONG WINAPI KeSetEvent( PRKEVENT event, KPRIORITY increment, BOOLEAN wait ) +{ + HANDLE handle = event->Header.WaitListHead.Blink; + LONG ret; + + TRACE("event %p, increment %d, wait %u.\n", event, increment, wait); + + EnterCriticalSection( &sync_cs ); + ret = interlocked_xchg( &event->Header.SignalState, TRUE ); + if (handle) + SetEvent( handle ); + LeaveCriticalSection( &sync_cs ); + + return ret; +}
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntoskrnl.exe/ntoskrnl.c | 10 ---------- dlls/ntoskrnl.exe/sync.c | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 189f303d6a..e6ca5e9ace 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -2429,16 +2429,6 @@ ULONG WINAPI KeQueryTimeIncrement(void) }
-/*********************************************************************** - * KeResetEvent (NTOSKRNL.EXE.@) - */ -LONG WINAPI KeResetEvent( PRKEVENT Event ) -{ - FIXME("(%p): stub\n", Event); - return 0; -} - - /*********************************************************************** * KeSetPriorityThread (NTOSKRNL.EXE.@) */ diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c index 05d50ef648..f011a6009a 100644 --- a/dlls/ntoskrnl.exe/sync.c +++ b/dlls/ntoskrnl.exe/sync.c @@ -146,3 +146,22 @@ LONG WINAPI KeSetEvent( PRKEVENT event, KPRIORITY increment, BOOLEAN wait )
return ret; } + +/*********************************************************************** + * KeResetEvent (NTOSKRNL.EXE.@) + */ +LONG WINAPI KeResetEvent( PRKEVENT event ) +{ + HANDLE handle = event->Header.WaitListHead.Blink; + LONG ret; + + TRACE("event %p.\n", event); + + EnterCriticalSection( &sync_cs ); + ret = interlocked_xchg( &event->Header.SignalState, FALSE ); + if (handle) + ResetEvent( handle ); + LeaveCriticalSection( &sync_cs ); + + return ret; +}
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntoskrnl.exe/ntoskrnl.c | 13 ------------- dlls/ntoskrnl.exe/sync.c | 9 +++++++++ include/ddk/wdm.h | 1 + 3 files changed, 10 insertions(+), 13 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index e6ca5e9ace..c1cfb032dd 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -2446,19 +2446,6 @@ VOID WINAPI KeSetSystemAffinityThread(KAFFINITY Affinity) FIXME("(%lx) stub\n", Affinity); }
-/*********************************************************************** - * KeWaitForSingleObject (NTOSKRNL.EXE.@) - */ -NTSTATUS WINAPI KeWaitForSingleObject(PVOID Object, - KWAIT_REASON WaitReason, - KPROCESSOR_MODE WaitMode, - BOOLEAN Alertable, - PLARGE_INTEGER Timeout) -{ - FIXME( "stub: %p, %d, %d, %d, %p\n", Object, WaitReason, WaitMode, Alertable, Timeout ); - return STATUS_NOT_IMPLEMENTED; -} - /*********************************************************************** * IoRegisterFileSystem (NTOSKRNL.EXE.@) */ diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c index f011a6009a..a67bd88130 100644 --- a/dlls/ntoskrnl.exe/sync.c +++ b/dlls/ntoskrnl.exe/sync.c @@ -115,6 +115,15 @@ NTSTATUS WINAPI KeWaitForMultipleObjects(ULONG count, void *pobjs[], return ret; }
+/*********************************************************************** + * KeWaitForSingleObject (NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI KeWaitForSingleObject( void *obj, KWAIT_REASON reason, + KPROCESSOR_MODE mode, BOOLEAN alertable, LARGE_INTEGER *timeout ) +{ + return KeWaitForMultipleObjects( 1, &obj, WaitAny, reason, mode, alertable, timeout, NULL ); +} + /*********************************************************************** * KeInitializeEvent (NTOSKRNL.EXE.@) */ diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index dbbc5a11cf..522bb3f9c8 100644 --- a/include/ddk/wdm.h +++ b/include/ddk/wdm.h @@ -1433,6 +1433,7 @@ LONG WINAPI KeSetEvent(PRKEVENT,KPRIORITY,BOOLEAN); KPRIORITY WINAPI KeSetPriorityThread(PKTHREAD,KPRIORITY); void WINAPI KeSetSystemAffinityThread(KAFFINITY); NTSTATUS WINAPI KeWaitForMultipleObjects(ULONG,void*[],WAIT_TYPE,KWAIT_REASON,KPROCESSOR_MODE,BOOLEAN,LARGE_INTEGER*,KWAIT_BLOCK*); +NTSTATUS WINAPI KeWaitForSingleObject(void*,KWAIT_REASON,KPROCESSOR_MODE,BOOLEAN,LARGE_INTEGER*);
PVOID WINAPI MmAllocateContiguousMemory(SIZE_T,PHYSICAL_ADDRESS); PVOID WINAPI MmAllocateNonCachedMemory(SIZE_T);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntoskrnl.exe/tests/driver.c | 116 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+)
diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c index 68b6730c9b..07a0adba60 100644 --- a/dlls/ntoskrnl.exe/tests/driver.c +++ b/dlls/ntoskrnl.exe/tests/driver.c @@ -210,6 +210,121 @@ static void test_load_driver(void) ok(!ret, "got %#x\n", ret); }
+static NTSTATUS wait_single(void *obj, ULONGLONG timeout) +{ + LARGE_INTEGER integer; + + integer.QuadPart = timeout; + return KeWaitForSingleObject(obj, Executive, KernelMode, FALSE, &integer); +} + +static NTSTATUS wait_multiple(ULONG count, void *objs[], WAIT_TYPE wait_type, ULONGLONG timeout) +{ + LARGE_INTEGER integer; + + integer.QuadPart = timeout; + return KeWaitForMultipleObjects(count, objs, wait_type, Executive, KernelMode, FALSE, &integer, NULL); +} + +static void test_sync(void) +{ + KEVENT manual_event, auto_event; + void *objs[2]; + NTSTATUS ret; + + KeInitializeEvent(&manual_event, NotificationEvent, FALSE); + + ret = wait_single(&manual_event, 0); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + KeSetEvent(&manual_event, 0, FALSE); + + ret = wait_single(&manual_event, 0); + ok(ret == 0, "got %#x\n", ret); + + ret = wait_single(&manual_event, 0); + ok(ret == 0, "got %#x\n", ret); + + KeResetEvent(&manual_event); + + ret = wait_single(&manual_event, 0); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + KeInitializeEvent(&auto_event, SynchronizationEvent, FALSE); + + ret = wait_single(&auto_event, 0); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + KeSetEvent(&auto_event, 0, FALSE); + + ret = wait_single(&auto_event, 0); + ok(ret == 0, "got %#x\n", ret); + + ret = wait_single(&auto_event, 0); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + KeInitializeEvent(&auto_event, SynchronizationEvent, TRUE); + + ret = wait_single(&auto_event, 0); + ok(ret == 0, "got %#x\n", ret); + + objs[0] = &manual_event; + objs[1] = &auto_event; + + ret = wait_multiple(2, objs, WaitAny, 0); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + KeSetEvent(&manual_event, 0, FALSE); + KeSetEvent(&auto_event, 0, FALSE); + + ret = wait_multiple(2, objs, WaitAny, 0); + ok(ret == 0, "got %#x\n", ret); + + ret = wait_single(&auto_event, 0); + ok(ret == 0, "got %#x\n", ret); + + KeResetEvent(&manual_event); + KeSetEvent(&auto_event, 0, FALSE); + + ret = wait_multiple(2, objs, WaitAny, 0); + ok(ret == 1, "got %#x\n", ret); + + ret = wait_multiple(2, objs, WaitAny, 0); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + KeSetEvent(&manual_event, 0, FALSE); + KeSetEvent(&auto_event, 0, FALSE); + + ret = wait_multiple(2, objs, WaitAll, 0); + ok(ret == 0, "got %#x\n", ret); + + ret = wait_multiple(2, objs, WaitAll, 0); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + KeSetEvent(&auto_event, 0, FALSE); + KeResetEvent(&manual_event); + + ret = wait_multiple(2, objs, WaitAll, 0); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + ret = wait_single(&auto_event, 0); + ok(ret == 0, "got %#x\n", ret); + + objs[0] = &auto_event; + objs[1] = &manual_event; + KeSetEvent(&manual_event, 0, FALSE); + KeSetEvent(&auto_event, 0, FALSE); + + ret = wait_multiple(2, objs, WaitAny, 0); + ok(ret == 0, "got %#x\n", ret); + + ret = wait_multiple(2, objs, WaitAny, 0); + ok(ret == 1, "got %#x\n", ret); + + ret = wait_multiple(2, objs, WaitAny, 0); + ok(ret == 1, "got %#x\n", ret); +} + static NTSTATUS main_test(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info) { ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength; @@ -237,6 +352,7 @@ static NTSTATUS main_test(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info) test_mdl_map(); test_init_funcs(); test_load_driver(); + test_sync();
/* print process report */ if (test_input->winetest_debug)