server: Implement waiting on keyed events.
This commit is contained in:
parent
d4cd051cef
commit
93fbb12e65
|
@ -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 );
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue