forked from Mirrors/wine-wine
server: Implement waiting on keyed events.
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,
|
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,
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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 =
|
||||||
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
|
||||||
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 )
|
||||||
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_
|
||||||
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;
|
||||||
/* 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
|
||||||
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
|
||||||
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
|
||||||
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 )
|
||||||
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 )
|
||||||
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
|
||||||
{
|
{
|
||||||
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
|
||||||
}
|
}
|
||||||
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
|
||||||
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 )
|
||||||
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;
|
||||||
|
|
Loading…
Reference in New Issue