Commit bedd92ca authored by Zebediah Figura's avatar Zebediah Figura Committed by Alexandre Julliard

server: Explicitly return whether a select request was immediately signaled.

This fixes a regression introduced by 97afac46. If we make a request on an asynchronous device handle, and the IRP handler returns STATUS_PENDING, wait_async() will return STATUS_PENDING, as intended. However, if the async object is signaled before the user has a chance to call wait_async() [e.g. if get_next_device_request is called quickly enough], select will return STATUS_PENDING immediately, which causes server_select() to think the object is not signaled, and wait for a select reply forever. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51277 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51295Signed-off-by: 's avatarZebediah Figura <zfigura@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent a17469b1
...@@ -603,6 +603,7 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT ...@@ -603,6 +603,7 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT
apc_call_t call; apc_call_t call;
apc_result_t result; apc_result_t result;
sigset_t old_set; sigset_t old_set;
int signaled;
memset( &result, 0, sizeof(result) ); memset( &result, 0, sizeof(result) );
...@@ -628,6 +629,7 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT ...@@ -628,6 +629,7 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT
} }
if (context) wine_server_set_reply( req, context, 2 * sizeof(*context) ); if (context) wine_server_set_reply( req, context, 2 * sizeof(*context) );
ret = server_call_unlocked( req ); ret = server_call_unlocked( req );
signaled = reply->signaled;
apc_handle = reply->apc_handle; apc_handle = reply->apc_handle;
call = reply->call; call = reply->call;
} }
...@@ -646,7 +648,7 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT ...@@ -646,7 +648,7 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT
mutex_unlock( mutex ); mutex_unlock( mutex );
mutex = NULL; mutex = NULL;
} }
if (ret != STATUS_PENDING) break; if (signaled) break;
ret = wait_select_reply( &cookie ); ret = wait_select_reply( &cookie );
} }
......
...@@ -1313,8 +1313,8 @@ struct select_reply ...@@ -1313,8 +1313,8 @@ struct select_reply
struct reply_header __header; struct reply_header __header;
apc_call_t call; apc_call_t call;
obj_handle_t apc_handle; obj_handle_t apc_handle;
int signaled;
/* VARARG(contexts,contexts); */ /* VARARG(contexts,contexts); */
char __pad_60[4];
}; };
#define SELECT_ALERTABLE 1 #define SELECT_ALERTABLE 1
#define SELECT_INTERRUPTIBLE 2 #define SELECT_INTERRUPTIBLE 2
...@@ -6252,7 +6252,7 @@ union generic_reply ...@@ -6252,7 +6252,7 @@ union generic_reply
/* ### protocol_version begin ### */ /* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 724 #define SERVER_PROTOCOL_VERSION 725
/* ### protocol_version end ### */ /* ### protocol_version end ### */
......
...@@ -1160,6 +1160,7 @@ typedef struct ...@@ -1160,6 +1160,7 @@ typedef struct
@REPLY @REPLY
apc_call_t call; /* APC call arguments */ apc_call_t call; /* APC call arguments */
obj_handle_t apc_handle; /* handle to next APC */ obj_handle_t apc_handle; /* handle to next APC */
int signaled; /* were the handles immediately signaled? */
VARARG(contexts,contexts); /* suspend context(s) */ VARARG(contexts,contexts); /* suspend context(s) */
@END @END
#define SELECT_ALERTABLE 1 #define SELECT_ALERTABLE 1
......
...@@ -896,6 +896,7 @@ C_ASSERT( FIELD_OFFSET(struct select_request, prev_apc) == 36 ); ...@@ -896,6 +896,7 @@ C_ASSERT( FIELD_OFFSET(struct select_request, prev_apc) == 36 );
C_ASSERT( sizeof(struct select_request) == 40 ); C_ASSERT( sizeof(struct select_request) == 40 );
C_ASSERT( FIELD_OFFSET(struct select_reply, call) == 8 ); C_ASSERT( FIELD_OFFSET(struct select_reply, call) == 8 );
C_ASSERT( FIELD_OFFSET(struct select_reply, apc_handle) == 56 ); C_ASSERT( FIELD_OFFSET(struct select_reply, apc_handle) == 56 );
C_ASSERT( FIELD_OFFSET(struct select_reply, signaled) == 60 );
C_ASSERT( sizeof(struct select_reply) == 64 ); C_ASSERT( sizeof(struct select_reply) == 64 );
C_ASSERT( FIELD_OFFSET(struct create_event_request, access) == 12 ); C_ASSERT( FIELD_OFFSET(struct create_event_request, access) == 12 );
C_ASSERT( FIELD_OFFSET(struct create_event_request, manual_reset) == 16 ); C_ASSERT( FIELD_OFFSET(struct create_event_request, manual_reset) == 16 );
......
...@@ -974,7 +974,7 @@ static int signal_object( obj_handle_t handle ) ...@@ -974,7 +974,7 @@ static int signal_object( obj_handle_t handle )
} }
/* select on a list of handles */ /* select on a list of handles */
static void select_on( const select_op_t *select_op, data_size_t op_size, client_ptr_t cookie, static int select_on( const select_op_t *select_op, data_size_t op_size, client_ptr_t cookie,
int flags, abstime_t when ) int flags, abstime_t when )
{ {
int ret; int ret;
...@@ -984,7 +984,7 @@ static void select_on( const select_op_t *select_op, data_size_t op_size, client ...@@ -984,7 +984,7 @@ static void select_on( const select_op_t *select_op, data_size_t op_size, client
switch (select_op->op) switch (select_op->op)
{ {
case SELECT_NONE: case SELECT_NONE:
if (!wait_on( select_op, 0, NULL, flags, when )) return; if (!wait_on( select_op, 0, NULL, flags, when )) return 1;
break; break;
case SELECT_WAIT: case SELECT_WAIT:
...@@ -993,24 +993,24 @@ static void select_on( const select_op_t *select_op, data_size_t op_size, client ...@@ -993,24 +993,24 @@ static void select_on( const select_op_t *select_op, data_size_t op_size, client
if (op_size < offsetof( select_op_t, wait.handles ) || count > MAXIMUM_WAIT_OBJECTS) if (op_size < offsetof( select_op_t, wait.handles ) || count > MAXIMUM_WAIT_OBJECTS)
{ {
set_error( STATUS_INVALID_PARAMETER ); set_error( STATUS_INVALID_PARAMETER );
return; return 1;
} }
if (!wait_on_handles( select_op, count, select_op->wait.handles, flags, when )) if (!wait_on_handles( select_op, count, select_op->wait.handles, flags, when ))
return; return 1;
break; break;
case SELECT_SIGNAL_AND_WAIT: case SELECT_SIGNAL_AND_WAIT:
if (!wait_on_handles( select_op, 1, &select_op->signal_and_wait.wait, flags, when )) if (!wait_on_handles( select_op, 1, &select_op->signal_and_wait.wait, flags, when ))
return; return 1;
if (select_op->signal_and_wait.signal) if (select_op->signal_and_wait.signal)
{ {
if (!signal_object( select_op->signal_and_wait.signal )) if (!signal_object( select_op->signal_and_wait.signal ))
{ {
end_wait( current, get_error() ); end_wait( current, get_error() );
return; return 1;
} }
/* check if we woke ourselves up */ /* check if we woke ourselves up */
if (!current->wait) return; if (!current->wait) return 1;
} }
break; break;
...@@ -1018,23 +1018,23 @@ static void select_on( const select_op_t *select_op, data_size_t op_size, client ...@@ -1018,23 +1018,23 @@ static void select_on( const select_op_t *select_op, data_size_t op_size, client
case SELECT_KEYED_EVENT_RELEASE: case SELECT_KEYED_EVENT_RELEASE:
object = (struct object *)get_keyed_event_obj( current->process, select_op->keyed_event.handle, 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 ); select_op->op == SELECT_KEYED_EVENT_WAIT ? KEYEDEVENT_WAIT : KEYEDEVENT_WAKE );
if (!object) return; if (!object) return 1;
ret = wait_on( select_op, 1, &object, flags, when ); ret = wait_on( select_op, 1, &object, flags, when );
release_object( object ); release_object( object );
if (!ret) return; if (!ret) return 1;
current->wait->key = select_op->keyed_event.key; current->wait->key = select_op->keyed_event.key;
break; break;
default: default:
set_error( STATUS_INVALID_PARAMETER ); set_error( STATUS_INVALID_PARAMETER );
return; return 1;
} }
if ((ret = check_wait( current )) != -1) if ((ret = check_wait( current )) != -1)
{ {
/* condition is already satisfied */ /* condition is already satisfied */
set_error( end_wait( current, ret )); set_error( end_wait( current, ret ));
return; return 1;
} }
/* now we need to wait */ /* now we need to wait */
...@@ -1044,12 +1044,12 @@ static void select_on( const select_op_t *select_op, data_size_t op_size, client ...@@ -1044,12 +1044,12 @@ static void select_on( const select_op_t *select_op, data_size_t op_size, client
thread_timeout, current->wait ))) thread_timeout, current->wait )))
{ {
end_wait( current, get_error() ); end_wait( current, get_error() );
return; return 1;
} }
} }
current->wait->cookie = cookie; current->wait->cookie = cookie;
set_error( STATUS_PENDING ); set_error( STATUS_PENDING );
return; return 0;
} }
/* attempt to wake threads sleeping on the object wait queue */ /* attempt to wake threads sleeping on the object wait queue */
...@@ -1664,7 +1664,7 @@ DECL_HANDLER(select) ...@@ -1664,7 +1664,7 @@ DECL_HANDLER(select)
release_object( apc ); release_object( apc );
} }
select_on( &select_op, op_size, req->cookie, req->flags, req->timeout ); reply->signaled = select_on( &select_op, op_size, req->cookie, req->flags, req->timeout );
if (get_error() == STATUS_USER_APC) if (get_error() == STATUS_USER_APC)
{ {
...@@ -1684,7 +1684,7 @@ DECL_HANDLER(select) ...@@ -1684,7 +1684,7 @@ DECL_HANDLER(select)
} }
release_object( apc ); release_object( apc );
} }
else if (get_error() != STATUS_PENDING && get_reply_max_size() >= sizeof(context_t) && else if (reply->signaled && get_reply_max_size() >= sizeof(context_t) &&
current->context && current->suspend_cookie == req->cookie) current->context && current->suspend_cookie == req->cookie)
{ {
ctx = current->context; ctx = current->context;
......
...@@ -1803,6 +1803,7 @@ static void dump_select_reply( const struct select_reply *req ) ...@@ -1803,6 +1803,7 @@ static void dump_select_reply( const struct select_reply *req )
{ {
dump_apc_call( " call=", &req->call ); dump_apc_call( " call=", &req->call );
fprintf( stderr, ", apc_handle=%04x", req->apc_handle ); fprintf( stderr, ", apc_handle=%04x", req->apc_handle );
fprintf( stderr, ", signaled=%d", req->signaled );
dump_varargs_contexts( ", contexts=", cur_size ); dump_varargs_contexts( ", contexts=", cur_size );
} }
......
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