server: Implement waiting on keyed events.

This commit is contained in:
Alexandre Julliard 2013-08-22 17:53:15 +02:00
parent d4cd051cef
commit 93fbb12e65
8 changed files with 130 additions and 12 deletions

View File

@ -985,8 +985,15 @@ NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJE
NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key,
BOOLEAN alertable, const LARGE_INTEGER *timeout )
{
FIXME( "stub\n" );
return STATUS_NOT_IMPLEMENTED;
select_op_t select_op;
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,
NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key,
BOOLEAN alertable, const LARGE_INTEGER *timeout )
{
FIXME( "stub\n" );
return STATUS_NOT_IMPLEMENTED;
select_op_t select_op;
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 );
}
/******************************************************************

View File

@ -409,7 +409,9 @@ enum select_op
SELECT_NONE,
SELECT_WAIT,
SELECT_WAIT_ALL,
SELECT_SIGNAL_AND_WAIT
SELECT_SIGNAL_AND_WAIT,
SELECT_KEYED_EVENT_WAIT,
SELECT_KEYED_EVENT_RELEASE
};
typedef union
@ -426,6 +428,12 @@ typedef union
obj_handle_t wait;
obj_handle_t signal;
} signal_and_wait;
struct
{
enum select_op op;
obj_handle_t handle;
client_ptr_t key;
} keyed_event;
} select_op_t;
enum apc_type
@ -5794,6 +5802,6 @@ union generic_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 */

View File

@ -101,10 +101,6 @@ static const struct object_ops keyed_event_ops =
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,
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
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 )
{
struct keyed_event *event = (struct keyed_event *)obj;
@ -243,10 +244,32 @@ static struct object_type *keyed_event_get_type( struct object *obj )
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 )
{
struct wait_queue_entry *ptr;
struct process *process;
enum select_op select_op;
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 )

View File

@ -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,
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 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 set_event( struct event *event );
extern void reset_event( struct event *event );
@ -235,4 +236,8 @@ extern const char *server_argv0;
/* server start time used for GetTickCount() */
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 */

View File

@ -425,7 +425,9 @@ enum select_op
SELECT_NONE,
SELECT_WAIT,
SELECT_WAIT_ALL,
SELECT_SIGNAL_AND_WAIT
SELECT_SIGNAL_AND_WAIT,
SELECT_KEYED_EVENT_WAIT,
SELECT_KEYED_EVENT_RELEASE
};
typedef union
@ -442,6 +444,12 @@ typedef union
obj_handle_t wait;
obj_handle_t signal; /* must be last in the structure so we can remove it on retries */
} 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;
enum apc_type

View File

@ -77,6 +77,7 @@ struct thread_wait
int flags;
int abandoned;
enum select_op select;
client_ptr_t key; /* wait key for keyed events */
client_ptr_t cookie; /* magic cookie to return to client */
timeout_t timeout;
struct timeout_user *user;
@ -549,6 +550,16 @@ struct thread *get_wait_queue_thread( struct wait_queue_entry *entry )
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 )
{
entry->wait->abandoned = 1;
@ -707,6 +718,33 @@ int wake_thread( struct thread *thread )
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 */
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
{
int ret;
unsigned int count;
struct object *object;
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
}
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:
set_error( STATUS_INVALID_PARAMETER );
return 0;

View File

@ -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_pid( int pid );
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 stop_thread( struct thread *thread );
extern void stop_thread_if_suspended( 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 void remove_queue( struct object *obj, struct wait_queue_entry *entry );
extern void kill_thread( struct thread *thread, int violent_death );

View File

@ -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",
data.signal_and_wait.signal, data.signal_and_wait.wait );
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:
fprintf( stderr, "op=%u", data.op );
break;