Commit 6267c4b8 authored by Zebediah Figura's avatar Zebediah Figura Committed by Vitaly Lipatov

server, ntdll: Implement message waits.

parent 3153d8d1
......@@ -475,12 +475,13 @@ static void update_grabbed_object( struct esync *obj )
/* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we
* need to delegate to server_select(). */
NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
BOOLEAN alertable, const LARGE_INTEGER *timeout )
{
struct esync *objs[MAXIMUM_WAIT_OBJECTS];
struct pollfd fds[MAXIMUM_WAIT_OBJECTS];
int has_esync = 0, has_server = 0;
BOOL msgwait = FALSE;
LONGLONG timeleft;
LARGE_INTEGER now;
ULONGLONG end;
......@@ -508,6 +509,9 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an
return ret;
}
if (objs[count - 1] && objs[count - 1]->type == ESYNC_QUEUE)
msgwait = TRUE;
if (has_esync && has_server)
FIXME("Can't wait on esync and server objects at the same time!\n");
else if (has_server)
......@@ -519,6 +523,9 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an
for (i = 0; i < count; i++)
TRACE(" %p", handles[i]);
if (msgwait)
TRACE(" or driver events");
if (!timeout)
TRACE(", timeout = INFINITE.\n");
else
......@@ -558,7 +565,9 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an
int64_t value;
ssize_t size;
if (obj->type == ESYNC_MANUAL_EVENT || obj->type == ESYNC_MANUAL_SERVER)
if (obj->type == ESYNC_MANUAL_EVENT
|| obj->type == ESYNC_MANUAL_SERVER
|| obj->type == ESYNC_QUEUE)
{
/* Don't grab the object, just check if it's signaled. */
if (fds[i].revents & POLLIN)
......@@ -603,6 +612,44 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an
}
}
/* We need to let the server know when we are doing a message wait, and when we
* are done with one, so that all of the code surrounding hung queues works.
* We also need this for WaitForInputIdle(). */
static void server_set_msgwait( int in_msgwait )
{
SERVER_START_REQ( esync_msgwait )
{
req->in_msgwait = in_msgwait;
wine_server_call( req );
}
SERVER_END_REQ;
}
/* This is a very thin wrapper around the proper implementation above. The
* purpose is to make sure the server knows when we are doing a message wait.
* This is separated into a wrapper function since there are at least a dozen
* exit paths from esync_wait_objects(). */
NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
BOOLEAN alertable, const LARGE_INTEGER *timeout )
{
BOOL msgwait = FALSE;
struct esync *obj;
NTSTATUS ret;
if (count && !get_object( handles[count - 1], &obj ) && obj->type == ESYNC_QUEUE)
{
msgwait = TRUE;
server_set_msgwait( 1 );
}
ret = __esync_wait_objects( count, handles, wait_any, alertable, timeout );
if (msgwait)
server_set_msgwait( 0 );
return ret;
}
void esync_init(void)
{
struct stat st;
......
......@@ -5521,6 +5521,17 @@ struct get_esync_fd_reply
};
struct esync_msgwait_request
{
struct request_header __header;
int in_msgwait;
};
struct esync_msgwait_reply
{
struct reply_header __header;
};
enum request
{
REQ_new_process,
......@@ -5802,6 +5813,7 @@ enum request
REQ_get_next_thread,
REQ_create_esync,
REQ_get_esync_fd,
REQ_esync_msgwait,
REQ_NB_REQUESTS
};
......@@ -6088,6 +6100,7 @@ union generic_request
struct get_next_thread_request get_next_thread_request;
struct create_esync_request create_esync_request;
struct get_esync_fd_request get_esync_fd_request;
struct esync_msgwait_request esync_msgwait_request;
};
union generic_reply
{
......@@ -6372,11 +6385,12 @@ union generic_reply
struct get_next_thread_reply get_next_thread_reply;
struct create_esync_reply create_esync_reply;
struct get_esync_fd_reply get_esync_fd_reply;
struct esync_msgwait_reply esync_msgwait_reply;
};
/* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 759
#define SERVER_PROTOCOL_VERSION 760
/* ### protocol_version end ### */
......
......@@ -3797,3 +3797,8 @@ enum esync_type
int type;
unsigned int shm_idx;
@END
/* Notify the server that we are doing a message wait or done with one. */
@REQ(esync_msgwait)
int in_msgwait; /* are we in a message wait? */
@END
......@@ -144,6 +144,7 @@ struct msg_queue
int keystate_lock; /* owns an input keystate lock */
unsigned int ignore_post_msg; /* ignore post messages newer than this unique id */
int esync_fd; /* esync file descriptor (signalled on message) */
int esync_in_msgwait; /* our thread is currently waiting on us */
};
struct hotkey
......@@ -317,6 +318,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_
queue->keystate_lock = 0;
queue->ignore_post_msg = 0;
queue->esync_fd = -1;
queue->esync_in_msgwait = 0;
list_init( &queue->send_result );
list_init( &queue->callback_result );
list_init( &queue->pending_timers );
......@@ -1001,6 +1003,10 @@ static int is_queue_hung( struct msg_queue *queue )
if (get_wait_queue_thread(entry)->queue == queue)
return 0; /* thread is waiting on queue -> not hung */
}
if (do_esync() && queue->esync_in_msgwait)
return 0; /* thread is waiting on queue in absentia -> not hung */
return 1;
}
......@@ -3456,3 +3462,18 @@ DECL_HANDLER(update_rawinput_devices)
process->rawinput_mouse = find_rawinput_device( process, 1, 2 );
process->rawinput_kbd = find_rawinput_device( process, 1, 6 );
}
DECL_HANDLER(esync_msgwait)
{
struct msg_queue *queue = get_current_queue();
if (!queue) return;
queue->esync_in_msgwait = req->in_msgwait;
if (current->process->idle_event && !(queue->wake_mask & QS_SMRESULT))
set_event( current->process->idle_event );
/* and start/stop waiting on the driver */
if (queue->fd)
set_fd_events( queue->fd, req->in_msgwait ? POLLIN : 0 );
}
......@@ -398,6 +398,7 @@ DECL_HANDLER(resume_process);
DECL_HANDLER(get_next_thread);
DECL_HANDLER(create_esync);
DECL_HANDLER(get_esync_fd);
DECL_HANDLER(esync_msgwait);
#ifdef WANT_REQUEST_HANDLERS
......@@ -683,6 +684,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_get_next_thread,
(req_handler)req_create_esync,
(req_handler)req_get_esync_fd,
(req_handler)req_esync_msgwait,
};
C_ASSERT( sizeof(abstime_t) == 8 );
......@@ -2286,6 +2288,8 @@ C_ASSERT( sizeof(struct get_esync_fd_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_esync_fd_reply, type) == 8 );
C_ASSERT( FIELD_OFFSET(struct get_esync_fd_reply, shm_idx) == 12 );
C_ASSERT( sizeof(struct get_esync_fd_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct esync_msgwait_request, in_msgwait) == 12 );
C_ASSERT( sizeof(struct esync_msgwait_request) == 16 );
#endif /* WANT_REQUEST_HANDLERS */
......
......@@ -4527,6 +4527,11 @@ static void dump_get_esync_fd_reply( const struct get_esync_fd_reply *req )
fprintf( stderr, ", shm_idx=%08x", req->shm_idx );
}
static void dump_esync_msgwait_request( const struct esync_msgwait_request *req )
{
fprintf( stderr, " in_msgwait=%d", req->in_msgwait );
}
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_new_process_request,
(dump_func)dump_get_new_process_info_request,
......@@ -4807,6 +4812,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_get_next_thread_request,
(dump_func)dump_create_esync_request,
(dump_func)dump_get_esync_fd_request,
(dump_func)dump_esync_msgwait_request,
};
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
......@@ -5089,6 +5095,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_get_next_thread_reply,
(dump_func)dump_create_esync_reply,
(dump_func)dump_get_esync_fd_reply,
NULL,
};
static const char * const req_names[REQ_NB_REQUESTS] = {
......@@ -5371,6 +5378,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"get_next_thread",
"create_esync",
"get_esync_fd",
"esync_msgwait",
};
static const struct
......
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