Commit 93fbb12e authored by Alexandre Julliard's avatar Alexandre Julliard

server: Implement waiting on keyed events.

parent d4cd051c
...@@ -985,8 +985,15 @@ NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJE ...@@ -985,8 +985,15 @@ NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJE
NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key, NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key,
BOOLEAN alertable, const LARGE_INTEGER *timeout ) BOOLEAN alertable, const LARGE_INTEGER *timeout )
{ {
FIXME( "stub\n" ); select_op_t select_op;
return STATUS_NOT_IMPLEMENTED; UINT flags = SELECT_INTERRUPTIBLE;
if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
if (alertable) flags |= SELECT_ALERTABLE;
select_op.keyed_event.op = SELECT_KEYED_EVENT_WAIT;
select_op.keyed_event.handle = wine_server_obj_handle( handle );
select_op.keyed_event.key = wine_server_client_ptr( key );
return server_select( &select_op, sizeof(select_op.keyed_event), flags, timeout );
} }
/****************************************************************************** /******************************************************************************
...@@ -995,8 +1002,15 @@ NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key, ...@@ -995,8 +1002,15 @@ NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key,
NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key, NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key,
BOOLEAN alertable, const LARGE_INTEGER *timeout ) BOOLEAN alertable, const LARGE_INTEGER *timeout )
{ {
FIXME( "stub\n" ); select_op_t select_op;
return STATUS_NOT_IMPLEMENTED; UINT flags = SELECT_INTERRUPTIBLE;
if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
if (alertable) flags |= SELECT_ALERTABLE;
select_op.keyed_event.op = SELECT_KEYED_EVENT_RELEASE;
select_op.keyed_event.handle = wine_server_obj_handle( handle );
select_op.keyed_event.key = wine_server_client_ptr( key );
return server_select( &select_op, sizeof(select_op.keyed_event), flags, timeout );
} }
/****************************************************************** /******************************************************************
......
...@@ -409,7 +409,9 @@ enum select_op ...@@ -409,7 +409,9 @@ enum select_op
SELECT_NONE, SELECT_NONE,
SELECT_WAIT, SELECT_WAIT,
SELECT_WAIT_ALL, SELECT_WAIT_ALL,
SELECT_SIGNAL_AND_WAIT SELECT_SIGNAL_AND_WAIT,
SELECT_KEYED_EVENT_WAIT,
SELECT_KEYED_EVENT_RELEASE
}; };
typedef union typedef union
...@@ -426,6 +428,12 @@ typedef union ...@@ -426,6 +428,12 @@ typedef union
obj_handle_t wait; obj_handle_t wait;
obj_handle_t signal; obj_handle_t signal;
} signal_and_wait; } signal_and_wait;
struct
{
enum select_op op;
obj_handle_t handle;
client_ptr_t key;
} keyed_event;
} select_op_t; } select_op_t;
enum apc_type enum apc_type
...@@ -5794,6 +5802,6 @@ union generic_reply ...@@ -5794,6 +5802,6 @@ union generic_reply
struct set_suspend_context_reply set_suspend_context_reply; struct set_suspend_context_reply set_suspend_context_reply;
}; };
#define SERVER_PROTOCOL_VERSION 446 #define SERVER_PROTOCOL_VERSION 447
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
...@@ -101,10 +101,6 @@ static const struct object_ops keyed_event_ops = ...@@ -101,10 +101,6 @@ static const struct object_ops keyed_event_ops =
no_destroy /* destroy */ no_destroy /* destroy */
}; };
#define KEYEDEVENT_WAIT 0x0001
#define KEYEDEVENT_WAKE 0x0002
#define KEYEDEVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x0003)
struct event *create_event( struct directory *root, const struct unicode_str *name, struct event *create_event( struct directory *root, const struct unicode_str *name,
unsigned int attr, int manual_reset, int initial_state, unsigned int attr, int manual_reset, int initial_state,
...@@ -227,6 +223,11 @@ struct keyed_event *create_keyed_event( struct directory *root, const struct uni ...@@ -227,6 +223,11 @@ struct keyed_event *create_keyed_event( struct directory *root, const struct uni
return event; return event;
} }
struct keyed_event *get_keyed_event_obj( struct process *process, obj_handle_t handle, unsigned int access )
{
return (struct keyed_event *)get_handle_obj( process, handle, access, &keyed_event_ops );
}
static void keyed_event_dump( struct object *obj, int verbose ) static void keyed_event_dump( struct object *obj, int verbose )
{ {
struct keyed_event *event = (struct keyed_event *)obj; struct keyed_event *event = (struct keyed_event *)obj;
...@@ -243,10 +244,32 @@ static struct object_type *keyed_event_get_type( struct object *obj ) ...@@ -243,10 +244,32 @@ static struct object_type *keyed_event_get_type( struct object *obj )
return get_object_type( &str ); return get_object_type( &str );
} }
static enum select_op matching_op( enum select_op op )
{
return op ^ (SELECT_KEYED_EVENT_WAIT ^ SELECT_KEYED_EVENT_RELEASE);
}
static int keyed_event_signaled( struct object *obj, struct wait_queue_entry *entry ) static int keyed_event_signaled( struct object *obj, struct wait_queue_entry *entry )
{ {
struct wait_queue_entry *ptr;
struct process *process;
enum select_op select_op;
assert( obj->ops == &keyed_event_ops ); assert( obj->ops == &keyed_event_ops );
return 1;
process = get_wait_queue_thread( entry )->process;
select_op = get_wait_queue_select_op( entry );
if (select_op != SELECT_KEYED_EVENT_WAIT && select_op != SELECT_KEYED_EVENT_RELEASE) return 1;
LIST_FOR_EACH_ENTRY( ptr, &obj->wait_queue, struct wait_queue_entry, entry )
{
if (ptr == entry) continue;
if (get_wait_queue_thread( ptr )->process != process) continue;
if (get_wait_queue_select_op( ptr ) != matching_op( select_op )) continue;
if (get_wait_queue_key( ptr ) != get_wait_queue_key( entry )) continue;
if (wake_thread_queue_entry( ptr )) return 1;
}
return 0;
} }
static unsigned int keyed_event_map_access( struct object *obj, unsigned int access ) static unsigned int keyed_event_map_access( struct object *obj, unsigned int access )
......
...@@ -160,6 +160,7 @@ extern struct event *create_event( struct directory *root, const struct unicode_ ...@@ -160,6 +160,7 @@ extern struct event *create_event( struct directory *root, const struct unicode_
extern struct keyed_event *create_keyed_event( struct directory *root, const struct unicode_str *name, extern struct keyed_event *create_keyed_event( struct directory *root, const struct unicode_str *name,
unsigned int attr, const struct security_descriptor *sd ); unsigned int attr, const struct security_descriptor *sd );
extern struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access ); extern struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access );
extern struct keyed_event *get_keyed_event_obj( struct process *process, obj_handle_t handle, unsigned int access );
extern void pulse_event( struct event *event ); extern void pulse_event( struct event *event );
extern void set_event( struct event *event ); extern void set_event( struct event *event );
extern void reset_event( struct event *event ); extern void reset_event( struct event *event );
...@@ -235,4 +236,8 @@ extern const char *server_argv0; ...@@ -235,4 +236,8 @@ extern const char *server_argv0;
/* server start time used for GetTickCount() */ /* server start time used for GetTickCount() */
extern timeout_t server_start_time; extern timeout_t server_start_time;
#define KEYEDEVENT_WAIT 0x0001
#define KEYEDEVENT_WAKE 0x0002
#define KEYEDEVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x0003)
#endif /* __WINE_SERVER_OBJECT_H */ #endif /* __WINE_SERVER_OBJECT_H */
...@@ -425,7 +425,9 @@ enum select_op ...@@ -425,7 +425,9 @@ enum select_op
SELECT_NONE, SELECT_NONE,
SELECT_WAIT, SELECT_WAIT,
SELECT_WAIT_ALL, SELECT_WAIT_ALL,
SELECT_SIGNAL_AND_WAIT SELECT_SIGNAL_AND_WAIT,
SELECT_KEYED_EVENT_WAIT,
SELECT_KEYED_EVENT_RELEASE
}; };
typedef union typedef union
...@@ -442,6 +444,12 @@ typedef union ...@@ -442,6 +444,12 @@ typedef union
obj_handle_t wait; obj_handle_t wait;
obj_handle_t signal; /* must be last in the structure so we can remove it on retries */ obj_handle_t signal; /* must be last in the structure so we can remove it on retries */
} signal_and_wait; } signal_and_wait;
struct
{
enum select_op op; /* SELECT_KEYED_EVENT_WAIT or SELECT_KEYED_EVENT_RELEASE */
obj_handle_t handle;
client_ptr_t key;
} keyed_event;
} select_op_t; } select_op_t;
enum apc_type enum apc_type
......
...@@ -77,6 +77,7 @@ struct thread_wait ...@@ -77,6 +77,7 @@ struct thread_wait
int flags; int flags;
int abandoned; int abandoned;
enum select_op select; enum select_op select;
client_ptr_t key; /* wait key for keyed events */
client_ptr_t cookie; /* magic cookie to return to client */ client_ptr_t cookie; /* magic cookie to return to client */
timeout_t timeout; timeout_t timeout;
struct timeout_user *user; struct timeout_user *user;
...@@ -549,6 +550,16 @@ struct thread *get_wait_queue_thread( struct wait_queue_entry *entry ) ...@@ -549,6 +550,16 @@ struct thread *get_wait_queue_thread( struct wait_queue_entry *entry )
return entry->wait->thread; return entry->wait->thread;
} }
enum select_op get_wait_queue_select_op( struct wait_queue_entry *entry )
{
return entry->wait->select;
}
client_ptr_t get_wait_queue_key( struct wait_queue_entry *entry )
{
return entry->wait->key;
}
void make_wait_abandoned( struct wait_queue_entry *entry ) void make_wait_abandoned( struct wait_queue_entry *entry )
{ {
entry->wait->abandoned = 1; entry->wait->abandoned = 1;
...@@ -707,6 +718,33 @@ int wake_thread( struct thread *thread ) ...@@ -707,6 +718,33 @@ int wake_thread( struct thread *thread )
return count; return count;
} }
/* attempt to wake up a thread from a wait queue entry, assuming that it is signaled */
int wake_thread_queue_entry( struct wait_queue_entry *entry )
{
struct thread_wait *wait = entry->wait;
struct thread *thread = wait->thread;
int signaled;
client_ptr_t cookie;
if (thread->wait != wait) return 0; /* not the current wait */
if (thread->process->suspend + thread->suspend > 0) return 0; /* cannot acquire locks */
assert( wait->select != SELECT_WAIT_ALL );
signaled = entry - wait->queues;
entry->obj->ops->satisfied( entry->obj, entry );
if (wait->abandoned) signaled += STATUS_ABANDONED_WAIT_0;
cookie = wait->cookie;
if (debug_level) fprintf( stderr, "%04x: *wakeup* signaled=%d\n", thread->id, signaled );
end_wait( thread );
if (send_thread_wakeup( thread, cookie, signaled ) != -1)
wake_thread( thread ); /* check other waits too */
return 1;
}
/* thread wait timeout */ /* thread wait timeout */
static void thread_timeout( void *ptr ) static void thread_timeout( void *ptr )
{ {
...@@ -746,6 +784,7 @@ static timeout_t select_on( const select_op_t *select_op, data_size_t op_size, c ...@@ -746,6 +784,7 @@ static timeout_t select_on( const select_op_t *select_op, data_size_t op_size, c
{ {
int ret; int ret;
unsigned int count; unsigned int count;
struct object *object;
if (timeout <= 0) timeout = current_time - timeout; if (timeout <= 0) timeout = current_time - timeout;
...@@ -782,6 +821,17 @@ static timeout_t select_on( const select_op_t *select_op, data_size_t op_size, c ...@@ -782,6 +821,17 @@ static timeout_t select_on( const select_op_t *select_op, data_size_t op_size, c
} }
break; break;
case SELECT_KEYED_EVENT_WAIT:
case SELECT_KEYED_EVENT_RELEASE:
object = (struct object *)get_keyed_event_obj( current->process, select_op->keyed_event.handle,
select_op->op == SELECT_KEYED_EVENT_WAIT ? KEYEDEVENT_WAIT : KEYEDEVENT_WAKE );
if (!object) return timeout;
ret = wait_on( select_op, 1, &object, flags, timeout );
release_object( object );
if (!ret) return timeout;
current->wait->key = select_op->keyed_event.key;
break;
default: default:
set_error( STATUS_INVALID_PARAMETER ); set_error( STATUS_INVALID_PARAMETER );
return 0; return 0;
......
...@@ -106,10 +106,13 @@ extern struct thread *get_thread_from_handle( obj_handle_t handle, unsigned int ...@@ -106,10 +106,13 @@ extern struct thread *get_thread_from_handle( obj_handle_t handle, unsigned int
extern struct thread *get_thread_from_tid( int tid ); extern struct thread *get_thread_from_tid( int tid );
extern struct thread *get_thread_from_pid( int pid ); extern struct thread *get_thread_from_pid( int pid );
extern struct thread *get_wait_queue_thread( struct wait_queue_entry *entry ); extern struct thread *get_wait_queue_thread( struct wait_queue_entry *entry );
extern enum select_op get_wait_queue_select_op( struct wait_queue_entry *entry );
extern client_ptr_t get_wait_queue_key( struct wait_queue_entry *entry );
extern void make_wait_abandoned( struct wait_queue_entry *entry ); extern void make_wait_abandoned( struct wait_queue_entry *entry );
extern void stop_thread( struct thread *thread ); extern void stop_thread( struct thread *thread );
extern void stop_thread_if_suspended( struct thread *thread ); extern void stop_thread_if_suspended( struct thread *thread );
extern int wake_thread( struct thread *thread ); extern int wake_thread( struct thread *thread );
extern int wake_thread_queue_entry( struct wait_queue_entry *entry );
extern int add_queue( struct object *obj, struct wait_queue_entry *entry ); extern int add_queue( struct object *obj, struct wait_queue_entry *entry );
extern void remove_queue( struct object *obj, struct wait_queue_entry *entry ); extern void remove_queue( struct object *obj, struct wait_queue_entry *entry );
extern void kill_thread( struct thread *thread, int violent_death ); extern void kill_thread( struct thread *thread, int violent_death );
......
...@@ -409,6 +409,13 @@ static void dump_varargs_select_op( const char *prefix, data_size_t size ) ...@@ -409,6 +409,13 @@ static void dump_varargs_select_op( const char *prefix, data_size_t size )
fprintf( stderr, "SIGNAL_AND_WAIT,signal=%04x,wait=%04x", fprintf( stderr, "SIGNAL_AND_WAIT,signal=%04x,wait=%04x",
data.signal_and_wait.signal, data.signal_and_wait.wait ); data.signal_and_wait.signal, data.signal_and_wait.wait );
break; break;
case SELECT_KEYED_EVENT_WAIT:
case SELECT_KEYED_EVENT_RELEASE:
fprintf( stderr, "KEYED_EVENT_%s,handle=%04x",
data.op == SELECT_KEYED_EVENT_WAIT ? "WAIT" : "RELEASE",
data.keyed_event.handle );
dump_uint64( ",key=", &data.keyed_event.key );
break;
default: default:
fprintf( stderr, "op=%u", data.op ); fprintf( stderr, "op=%u", data.op );
break; break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment