diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index fe57b622f94..5348b07fe13 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -691,10 +691,15 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT int cookie; obj_handle_t apc_handle = 0; BOOL suspend_context = !!context; - apc_call_t call; apc_result_t result; sigset_t old_set; int signaled; + data_size_t reply_size; + struct + { + apc_call_t call; + context_t context[2]; + } reply_data; memset( &result, 0, sizeof(result) ); @@ -718,16 +723,17 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT wine_server_add_data( req, context, ctx_size ); suspend_context = FALSE; /* server owns the context now */ } - if (context) wine_server_set_reply( req, context, 2 * sizeof(*context) ); + wine_server_set_reply( req, &reply_data, + context ? sizeof(reply_data) : sizeof(reply_data.call) ); ret = server_call_unlocked( req ); signaled = reply->signaled; apc_handle = reply->apc_handle; - call = reply->call; + reply_size = wine_server_reply_size( reply ); } SERVER_END_REQ; if (ret != STATUS_KERNEL_APC) break; - invoke_system_apc( &call, &result, FALSE ); + invoke_system_apc( &reply_data.call, &result, FALSE ); /* don't signal multiple times */ if (size >= sizeof(select_op->signal_and_wait) && select_op->op == SELECT_SIGNAL_AND_WAIT) @@ -740,7 +746,9 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT } while (ret == STATUS_USER_APC || ret == STATUS_KERNEL_APC); - if (ret == STATUS_USER_APC) *user_apc = call.user; + if (ret == STATUS_USER_APC) *user_apc = reply_data.call.user; + if (reply_size > sizeof(reply_data.call)) + memcpy( context, reply_data.context, reply_size - sizeof(reply_data.call) ); return ret; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 340512a054e..5a14a3c4370 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1381,9 +1381,9 @@ struct select_request struct select_reply { struct reply_header __header; - apc_call_t call; obj_handle_t apc_handle; int signaled; + /* VARARG(call,apc_call); */ /* VARARG(contexts,contexts); */ }; #define SELECT_ALERTABLE 1 @@ -6413,7 +6413,7 @@ union generic_reply /* ### protocol_version begin ### */ -#define SERVER_PROTOCOL_VERSION 773 +#define SERVER_PROTOCOL_VERSION 774 /* ### protocol_version end ### */ diff --git a/server/protocol.def b/server/protocol.def index 7995f481e19..4237737ab40 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1221,9 +1221,9 @@ typedef struct VARARG(data,select_op,size); /* operation-specific data */ VARARG(contexts,contexts); /* suspend context(s) */ @REPLY - apc_call_t call; /* APC call arguments */ obj_handle_t apc_handle; /* handle to next APC */ int signaled; /* were the handles immediately signaled? */ + VARARG(call,apc_call); /* APC call arguments */ VARARG(contexts,contexts); /* suspend context(s) */ @END #define SELECT_ALERTABLE 1 diff --git a/server/request.h b/server/request.h index b13381d3fe1..ea08babdda8 100644 --- a/server/request.h +++ b/server/request.h @@ -689,7 +689,6 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = C_ASSERT( sizeof(abstime_t) == 8 ); C_ASSERT( sizeof(affinity_t) == 8 ); -C_ASSERT( sizeof(apc_call_t) == 48 ); C_ASSERT( sizeof(apc_param_t) == 8 ); C_ASSERT( sizeof(apc_result_t) == 40 ); C_ASSERT( sizeof(async_data_t) == 40 ); @@ -909,10 +908,9 @@ C_ASSERT( FIELD_OFFSET(struct select_request, timeout) == 24 ); C_ASSERT( FIELD_OFFSET(struct select_request, size) == 32 ); C_ASSERT( FIELD_OFFSET(struct select_request, prev_apc) == 36 ); C_ASSERT( sizeof(struct select_request) == 40 ); -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, signaled) == 60 ); -C_ASSERT( sizeof(struct select_reply) == 64 ); +C_ASSERT( FIELD_OFFSET(struct select_reply, apc_handle) == 8 ); +C_ASSERT( FIELD_OFFSET(struct select_reply, signaled) == 12 ); +C_ASSERT( sizeof(struct select_reply) == 16 ); 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, initial_state) == 20 ); diff --git a/server/thread.c b/server/thread.c index 5299f6c042d..3e35b27f694 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1658,17 +1658,19 @@ DECL_HANDLER(select) 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 && get_reply_max_size() >= sizeof(apc_call_t)) { apc = thread_dequeue_apc( current, 0 ); - reply->call = apc->call; + set_reply_data( &apc->call, sizeof(apc->call) ); release_object( apc ); } - else if (get_error() == STATUS_KERNEL_APC) + else if (get_error() == STATUS_KERNEL_APC && get_reply_max_size() >= sizeof(apc_call_t)) { apc = thread_dequeue_apc( current, 1 ); if ((reply->apc_handle = alloc_handle( current->process, apc, SYNCHRONIZE, 0 ))) - reply->call = apc->call; + { + set_reply_data( &apc->call, sizeof(apc->call) ); + } else { apc->executed = 1; @@ -1676,16 +1678,23 @@ DECL_HANDLER(select) } release_object( apc ); } - else if (reply->signaled && get_reply_max_size() >= sizeof(context_t) && + else if (reply->signaled && get_reply_max_size() >= sizeof(apc_call_t) + sizeof(context_t) && current->context && current->suspend_cookie == req->cookie) { ctx = current->context; if (ctx->regs[CTX_NATIVE].flags || ctx->regs[CTX_WOW].flags) { - data_size_t size = (ctx->regs[CTX_WOW].flags ? 2 : 1) * sizeof(context_t); + apc_call_t *data; + data_size_t size = sizeof(*data) + (ctx->regs[CTX_WOW].flags ? 2 : 1) * sizeof(context_t); unsigned int flags = system_flags & ctx->regs[CTX_NATIVE].flags; + if (flags) set_thread_context( current, &ctx->regs[CTX_NATIVE], flags ); - set_reply_data( ctx->regs, min( size, get_reply_max_size() )); + size = min( size, get_reply_max_size() ); + if ((data = set_reply_data_size( size ))) + { + memset( data, 0, sizeof(*data) ); + memcpy( data + 1, ctx->regs, size - sizeof(*data) ); + } } release_object( ctx ); current->context = NULL; diff --git a/server/trace.c b/server/trace.c index 7cd6f8938d3..96b8992f351 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1752,9 +1752,9 @@ static void dump_select_request( const struct select_request *req ) static void dump_select_reply( const struct select_reply *req ) { - 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_apc_call( ", call=", cur_size ); dump_varargs_contexts( ", contexts=", cur_size ); } diff --git a/tools/make_requests b/tools/make_requests index 158b2006ae5..e5db1c7fc0a 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -45,7 +45,6 @@ my %formats = "timeout_t" => [ 8, 8, "&dump_timeout" ], "abstime_t" => [ 8, 8, "&dump_abstime" ], "rectangle_t" => [ 16, 4, "&dump_rectangle" ], - "apc_call_t" => [ 48, 8, "&dump_apc_call" ], "apc_result_t" => [ 40, 8, "&dump_apc_result" ], "async_data_t" => [ 40, 8, "&dump_async_data" ], "irp_params_t" => [ 32, 8, "&dump_irp_params" ],