ntoskrnl.exe: Support creating event objects from server handle.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2019-03-25 14:38:44 +01:00 committed by Alexandre Julliard
parent a5c2f043e6
commit 0decadd62a
4 changed files with 101 additions and 16 deletions

View File

@ -27,6 +27,8 @@ struct _OBJECT_TYPE {
void (*release)(void*); /* called when the last reference is released */ void (*release)(void*); /* called when the last reference is released */
}; };
void *alloc_kernel_object( POBJECT_TYPE type, HANDLE handle, SIZE_T size, LONG ref ) DECLSPEC_HIDDEN;
extern POBJECT_TYPE ExEventObjectType; extern POBJECT_TYPE ExEventObjectType;
extern POBJECT_TYPE ExSemaphoreObjectType; extern POBJECT_TYPE ExSemaphoreObjectType;
extern POBJECT_TYPE IoDeviceObjectType; extern POBJECT_TYPE IoDeviceObjectType;

View File

@ -76,6 +76,13 @@ NTSTATUS WINAPI KeWaitForMultipleObjects(ULONG count, void *pobjs[],
EnterCriticalSection( &sync_cs ); EnterCriticalSection( &sync_cs );
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
if (objs[i]->WaitListHead.Blink == INVALID_HANDLE_VALUE)
{
FIXME("unsupported on kernel objects\n");
handles[i] = INVALID_HANDLE_VALUE;
continue;
}
++*((ULONG_PTR *)&objs[i]->WaitListHead.Flink); ++*((ULONG_PTR *)&objs[i]->WaitListHead.Flink);
if (!objs[i]->WaitListHead.Blink) if (!objs[i]->WaitListHead.Blink)
{ {
@ -127,6 +134,8 @@ NTSTATUS WINAPI KeWaitForMultipleObjects(ULONG count, void *pobjs[],
} }
} }
if (objs[i]->WaitListHead.Blink == INVALID_HANDLE_VALUE) continue;
if (!--*((ULONG_PTR *)&objs[i]->WaitListHead.Flink)) if (!--*((ULONG_PTR *)&objs[i]->WaitListHead.Flink))
{ {
switch (objs[i]->Type) switch (objs[i]->Type)
@ -186,10 +195,24 @@ void WINAPI KeInitializeEvent( PRKEVENT event, EVENT_TYPE type, BOOLEAN state )
event->Header.WaitListHead.Flink = NULL; event->Header.WaitListHead.Flink = NULL;
} }
static void *create_event_object( HANDLE handle )
{
EVENT_BASIC_INFORMATION info;
KEVENT *event;
if (!(event = alloc_kernel_object( ExEventObjectType, handle, sizeof(*event), 0 ))) return NULL;
if (!NtQueryEvent( handle, EventBasicInformation, &info, sizeof(info), NULL ))
KeInitializeEvent( event, info.EventType, info.EventState );
event->Header.WaitListHead.Blink = INVALID_HANDLE_VALUE; /* mark as kernel object */
return event;
}
static const WCHAR event_type_name[] = {'E','v','e','n','t',0}; static const WCHAR event_type_name[] = {'E','v','e','n','t',0};
static struct _OBJECT_TYPE event_type = { static struct _OBJECT_TYPE event_type = {
event_type_name, event_type_name,
create_event_object
}; };
POBJECT_TYPE ExEventObjectType = &event_type; POBJECT_TYPE ExEventObjectType = &event_type;
@ -200,15 +223,23 @@ POBJECT_TYPE ExEventObjectType = &event_type;
LONG WINAPI KeSetEvent( PRKEVENT event, KPRIORITY increment, BOOLEAN wait ) LONG WINAPI KeSetEvent( PRKEVENT event, KPRIORITY increment, BOOLEAN wait )
{ {
HANDLE handle; HANDLE handle;
LONG ret; ULONG ret = 0;
TRACE("event %p, increment %d, wait %u.\n", event, increment, wait); TRACE("event %p, increment %d, wait %u.\n", event, increment, wait);
if (event->Header.WaitListHead.Blink != INVALID_HANDLE_VALUE)
{
EnterCriticalSection( &sync_cs ); EnterCriticalSection( &sync_cs );
ret = InterlockedExchange( &event->Header.SignalState, TRUE ); ret = InterlockedExchange( &event->Header.SignalState, TRUE );
if ((handle = event->Header.WaitListHead.Blink)) if ((handle = event->Header.WaitListHead.Blink))
SetEvent( handle ); SetEvent( handle );
LeaveCriticalSection( &sync_cs ); LeaveCriticalSection( &sync_cs );
}
else
{
FIXME("unsupported on kernel objects\n");
event->Header.SignalState = TRUE;
}
return ret; return ret;
} }
@ -219,15 +250,23 @@ LONG WINAPI KeSetEvent( PRKEVENT event, KPRIORITY increment, BOOLEAN wait )
LONG WINAPI KeResetEvent( PRKEVENT event ) LONG WINAPI KeResetEvent( PRKEVENT event )
{ {
HANDLE handle; HANDLE handle;
LONG ret; ULONG ret = 0;
TRACE("event %p.\n", event); TRACE("event %p.\n", event);
if (event->Header.WaitListHead.Blink != INVALID_HANDLE_VALUE)
{
EnterCriticalSection( &sync_cs ); EnterCriticalSection( &sync_cs );
ret = InterlockedExchange( &event->Header.SignalState, FALSE ); ret = InterlockedExchange( &event->Header.SignalState, FALSE );
if ((handle = event->Header.WaitListHead.Blink)) if ((handle = event->Header.WaitListHead.Blink))
ResetEvent( handle ); ResetEvent( handle );
LeaveCriticalSection( &sync_cs ); LeaveCriticalSection( &sync_cs );
}
else
{
FIXME("unsupported on kernel objects\n");
event->Header.SignalState = FALSE;
}
return ret; return ret;
} }

View File

@ -308,6 +308,14 @@ static NTSTATUS wait_multiple(ULONG count, void *objs[], WAIT_TYPE wait_type, UL
return KeWaitForMultipleObjects(count, objs, wait_type, Executive, KernelMode, FALSE, &integer, NULL); return KeWaitForMultipleObjects(count, objs, wait_type, Executive, KernelMode, FALSE, &integer, NULL);
} }
static NTSTATUS wait_single_handle(HANDLE handle, ULONGLONG timeout)
{
LARGE_INTEGER integer;
integer.QuadPart = timeout;
return ZwWaitForSingleObject(handle, FALSE, &integer);
}
static void run_thread(PKSTART_ROUTINE proc, void *arg) static void run_thread(PKSTART_ROUTINE proc, void *arg)
{ {
OBJECT_ATTRIBUTES attr = {0}; OBJECT_ATTRIBUTES attr = {0};
@ -341,11 +349,13 @@ static void WINAPI mutex_thread(void *arg)
static void test_sync(void) static void test_sync(void)
{ {
KSEMAPHORE semaphore, semaphore2; KSEMAPHORE semaphore, semaphore2;
KEVENT manual_event, auto_event; KEVENT manual_event, auto_event, *event;
KTIMER timer; KTIMER timer;
LARGE_INTEGER timeout; LARGE_INTEGER timeout;
OBJECT_ATTRIBUTES attr;
void *objs[2]; void *objs[2];
NTSTATUS ret; NTSTATUS ret;
HANDLE handle;
int i; int i;
KeInitializeEvent(&manual_event, NotificationEvent, FALSE); KeInitializeEvent(&manual_event, NotificationEvent, FALSE);
@ -440,6 +450,33 @@ static void test_sync(void)
ret = wait_multiple(2, objs, WaitAny, 0); ret = wait_multiple(2, objs, WaitAny, 0);
ok(ret == 1, "got %#x\n", ret); ok(ret == 1, "got %#x\n", ret);
InitializeObjectAttributes(&attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
ret = ZwCreateEvent(&handle, SYNCHRONIZE, &attr, NotificationEvent, TRUE);
ok(!ret, "ZwCreateEvent failed: %#x\n", ret);
ret = ObReferenceObjectByHandle(handle, SYNCHRONIZE, *pExEventObjectType, KernelMode, (void **)&event, NULL);
ok(!ret, "ObReferenceObjectByHandle failed: %#x\n", ret);
ret = wait_single(event, 0);
todo_wine
ok(ret == 0, "got %#x\n", ret);
KeResetEvent(event);
ret = wait_single(event, 0);
ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
ret = wait_single_handle(handle, 0);
todo_wine
ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
KeSetEvent(event, 0, FALSE);
ret = wait_single(event, 0);
todo_wine
ok(ret == 0, "got %#x\n", ret);
ret = wait_single_handle(handle, 0);
ok(!ret, "got %#x\n", ret);
ZwClose(handle);
ObDereferenceObject(event);
/* test semaphores */ /* test semaphores */
KeInitializeSemaphore(&semaphore, 0, 5); KeInitializeSemaphore(&semaphore, 0, 5);
@ -731,14 +768,12 @@ static void test_ob_reference(const WCHAR *test_path)
status = ObReferenceObjectByHandle(event_handle, SYNCHRONIZE, *pExEventObjectType, KernelMode, &obj2, NULL); status = ObReferenceObjectByHandle(event_handle, SYNCHRONIZE, *pExEventObjectType, KernelMode, &obj2, NULL);
ok(!status, "ObReferenceObjectByHandle failed: %#x\n", status); ok(!status, "ObReferenceObjectByHandle failed: %#x\n", status);
todo_wine
ok(obj1 == obj2, "obj1 != obj2\n"); ok(obj1 == obj2, "obj1 != obj2\n");
ObDereferenceObject(obj2); ObDereferenceObject(obj2);
status = ObReferenceObjectByHandle(event_handle, SYNCHRONIZE, NULL, KernelMode, &obj2, NULL); status = ObReferenceObjectByHandle(event_handle, SYNCHRONIZE, NULL, KernelMode, &obj2, NULL);
ok(!status, "ObReferenceObjectByHandle failed: %#x\n", status); ok(!status, "ObReferenceObjectByHandle failed: %#x\n", status);
todo_wine
ok(obj1 == obj2, "obj1 != obj2\n"); ok(obj1 == obj2, "obj1 != obj2\n");
ObDereferenceObject(obj2); ObDereferenceObject(obj2);

View File

@ -39,6 +39,7 @@
struct event struct event
{ {
struct object obj; /* object header */ struct object obj; /* object header */
struct list kernel_object; /* list of kernel object pointers */
int manual_reset; /* is it a manual reset event? */ int manual_reset; /* is it a manual reset event? */
int signaled; /* event has been signaled */ int signaled; /* event has been signaled */
}; };
@ -49,6 +50,7 @@ static int event_signaled( struct object *obj, struct wait_queue_entry *entry );
static void event_satisfied( struct object *obj, struct wait_queue_entry *entry ); static void event_satisfied( struct object *obj, struct wait_queue_entry *entry );
static unsigned int event_map_access( struct object *obj, unsigned int access ); static unsigned int event_map_access( struct object *obj, unsigned int access );
static int event_signal( struct object *obj, unsigned int access); static int event_signal( struct object *obj, unsigned int access);
static struct list *event_get_kernel_obj_list( struct object *obj );
static const struct object_ops event_ops = static const struct object_ops event_ops =
{ {
@ -68,7 +70,7 @@ static const struct object_ops event_ops =
directory_link_name, /* link_name */ directory_link_name, /* link_name */
default_unlink_name, /* unlink_name */ default_unlink_name, /* unlink_name */
no_open_file, /* open_file */ no_open_file, /* open_file */
no_kernel_obj_list, /* get_kernel_obj_list */ event_get_kernel_obj_list, /* get_kernel_obj_list */
no_close_handle, /* close_handle */ no_close_handle, /* close_handle */
no_destroy /* destroy */ no_destroy /* destroy */
}; };
@ -119,6 +121,7 @@ struct event *create_event( struct object *root, const struct unicode_str *name,
if (get_error() != STATUS_OBJECT_NAME_EXISTS) if (get_error() != STATUS_OBJECT_NAME_EXISTS)
{ {
/* initialize it if it didn't already exist */ /* initialize it if it didn't already exist */
list_init( &event->kernel_object );
event->manual_reset = manual_reset; event->manual_reset = manual_reset;
event->signaled = initial_state; event->signaled = initial_state;
} }
@ -204,6 +207,12 @@ static int event_signal( struct object *obj, unsigned int access )
return 1; return 1;
} }
static struct list *event_get_kernel_obj_list( struct object *obj )
{
struct event *event = (struct event *)obj;
return &event->kernel_object;
}
struct keyed_event *create_keyed_event( struct object *root, const struct unicode_str *name, struct keyed_event *create_keyed_event( struct object *root, const struct unicode_str *name,
unsigned int attr, const struct security_descriptor *sd ) unsigned int attr, const struct security_descriptor *sd )
{ {