From 321d26cbb4404ee63df439759cbc5a546434dde6 Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Mon, 6 Apr 2020 17:21:19 +0200 Subject: [PATCH] server: Use correct clock in select. Signed-off-by: Piotr Caban Signed-off-by: Alexandre Julliard --- dlls/ntdll/server.c | 11 +++++-- dlls/ntdll/sync.c | 11 +++++-- include/wine/server_protocol.h | 7 ++--- server/protocol.def | 3 +- server/request.h | 8 ++--- server/thread.c | 55 +++++++++++++++++----------------- server/trace.c | 11 +++++-- tools/make_requests | 1 + 8 files changed, 62 insertions(+), 45 deletions(-) diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index df847d09a2c..d6b9b2ff0ab 100644 --- a/dlls/ntdll/server.c +++ b/dlls/ntdll/server.c @@ -600,11 +600,19 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT obj_handle_t apc_handle = 0; apc_call_t call; apc_result_t result; - timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE; + abstime_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE; sigset_t old_set; memset( &result, 0, sizeof(result) ); + if (abs_timeout < 0) + { + LARGE_INTEGER now; + + RtlQueryPerformanceCounter(&now); + abs_timeout -= now.QuadPart; + } + do { pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set ); @@ -619,7 +627,6 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT wine_server_add_data( req, &result, sizeof(result) ); wine_server_add_data( req, select_op, size ); ret = server_call_unlocked( req ); - abs_timeout = reply->timeout; apc_handle = reply->apc_handle; call = reply->call; } diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 4a7b4616273..bd71511cfb3 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -2463,7 +2463,7 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size obj_handle_t apc_handle = 0; apc_call_t call; apc_result_t result; - timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE; + abstime_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE; sigset_t old_set; if (size != 1 && size != 2 && size != 4 && size != 8) @@ -2478,6 +2478,14 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size memset( &result, 0, sizeof(result) ); + if (abs_timeout < 0) + { + LARGE_INTEGER now; + + RtlQueryPerformanceCounter(&now); + abs_timeout -= now.QuadPart; + } + do { RtlEnterCriticalSection( &addr_section ); @@ -2499,7 +2507,6 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size wine_server_add_data( req, &result, sizeof(result) ); wine_server_add_data( req, &select_op, sizeof(select_op.keyed_event) ); ret = server_call_unlocked( req ); - abs_timeout = reply->timeout; apc_handle = reply->apc_handle; call = reply->call; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index cb3a0738862..ba3045be62f 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1250,7 +1250,7 @@ struct select_request struct request_header __header; int flags; client_ptr_t cookie; - timeout_t timeout; + abstime_t timeout; obj_handle_t prev_apc; /* VARARG(result,apc_result); */ /* VARARG(data,select_op); */ @@ -1259,10 +1259,9 @@ struct select_request struct select_reply { struct reply_header __header; - timeout_t timeout; apc_call_t call; obj_handle_t apc_handle; - char __pad_60[4]; + char __pad_52[4]; }; #define SELECT_ALERTABLE 1 #define SELECT_INTERRUPTIBLE 2 @@ -6711,7 +6710,7 @@ union generic_reply /* ### protocol_version begin ### */ -#define SERVER_PROTOCOL_VERSION 596 +#define SERVER_PROTOCOL_VERSION 597 /* ### protocol_version end ### */ diff --git a/server/protocol.def b/server/protocol.def index cc23ee84db4..93b558cc2b4 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1099,12 +1099,11 @@ struct rawinput_device @REQ(select) int flags; /* wait flags (see below) */ client_ptr_t cookie; /* magic cookie to return to client */ - timeout_t timeout; /* timeout */ + abstime_t timeout; /* timeout */ obj_handle_t prev_apc; /* handle to previous APC */ VARARG(result,apc_result); /* result of previous APC */ VARARG(data,select_op); /* operation-specific data */ @REPLY - timeout_t timeout; /* timeout converted to absolute */ apc_call_t call; /* APC call arguments */ obj_handle_t apc_handle; /* handle to next APC */ @END diff --git a/server/request.h b/server/request.h index e7e05af0e49..d8967211e7b 100644 --- a/server/request.h +++ b/server/request.h @@ -721,6 +721,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_resume_process, }; +C_ASSERT( sizeof(abstime_t) == 8 ); C_ASSERT( sizeof(affinity_t) == 8 ); C_ASSERT( sizeof(apc_call_t) == 40 ); C_ASSERT( sizeof(apc_param_t) == 8 ); @@ -939,10 +940,9 @@ C_ASSERT( FIELD_OFFSET(struct select_request, cookie) == 16 ); C_ASSERT( FIELD_OFFSET(struct select_request, timeout) == 24 ); C_ASSERT( FIELD_OFFSET(struct select_request, prev_apc) == 32 ); C_ASSERT( sizeof(struct select_request) == 40 ); -C_ASSERT( FIELD_OFFSET(struct select_reply, timeout) == 8 ); -C_ASSERT( FIELD_OFFSET(struct select_reply, call) == 16 ); -C_ASSERT( FIELD_OFFSET(struct select_reply, apc_handle) == 56 ); -C_ASSERT( sizeof(struct select_reply) == 64 ); +C_ASSERT( FIELD_OFFSET(struct select_reply, call) == 8 ); +C_ASSERT( FIELD_OFFSET(struct select_reply, apc_handle) == 48 ); +C_ASSERT( sizeof(struct select_reply) == 56 ); 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 6e677c8cf29..ba481223b7c 100644 --- a/server/thread.c +++ b/server/thread.c @@ -79,7 +79,7 @@ struct thread_wait 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; + abstime_t when; struct timeout_user *user; struct wait_queue_entry queues[1]; }; @@ -687,7 +687,7 @@ static unsigned int end_wait( struct thread *thread, unsigned int status ) /* build the thread wait structure */ static int wait_on( const select_op_t *select_op, unsigned int count, struct object *objects[], - int flags, timeout_t timeout ) + int flags, abstime_t when ) { struct thread_wait *wait; struct wait_queue_entry *entry; @@ -701,7 +701,7 @@ static int wait_on( const select_op_t *select_op, unsigned int count, struct obj wait->select = select_op->op; wait->cookie = 0; wait->user = NULL; - wait->timeout = timeout; + wait->when = when; wait->abandoned = 0; current->wait = wait; @@ -720,7 +720,7 @@ static int wait_on( const select_op_t *select_op, unsigned int count, struct obj } static int wait_on_handles( const select_op_t *select_op, unsigned int count, const obj_handle_t *handles, - int flags, timeout_t timeout ) + int flags, abstime_t when ) { struct object *objects[MAXIMUM_WAIT_OBJECTS]; unsigned int i; @@ -732,7 +732,7 @@ static int wait_on_handles( const select_op_t *select_op, unsigned int count, co if (!(objects[i] = get_handle_obj( current->process, handles[i], SYNCHRONIZE, NULL ))) break; - if (i == count) ret = wait_on( select_op, count, objects, flags, timeout ); + if (i == count) ret = wait_on( select_op, count, objects, flags, when ); while (i > 0) release_object( objects[--i] ); return ret; @@ -769,7 +769,8 @@ static int check_wait( struct thread *thread ) } if ((wait->flags & SELECT_ALERTABLE) && !list_empty(&thread->user_apc)) return STATUS_USER_APC; - if (wait->timeout <= current_time) return STATUS_TIMEOUT; + if (wait->when >= 0 && wait->when <= current_time) return STATUS_TIMEOUT; + if (wait->when < 0 && -wait->when <= monotonic_time) return STATUS_TIMEOUT; return -1; } @@ -875,19 +876,17 @@ static int signal_object( obj_handle_t handle ) } /* select on a list of handles */ -static timeout_t select_on( const select_op_t *select_op, data_size_t op_size, client_ptr_t cookie, - int flags, timeout_t timeout ) +static void select_on( const select_op_t *select_op, data_size_t op_size, client_ptr_t cookie, + int flags, abstime_t when ) { int ret; unsigned int count; struct object *object; - if (timeout <= 0) timeout = current_time - timeout; - switch (select_op->op) { case SELECT_NONE: - if (!wait_on( select_op, 0, NULL, flags, timeout )) return timeout; + if (!wait_on( select_op, 0, NULL, flags, when )) return; break; case SELECT_WAIT: @@ -896,24 +895,24 @@ static timeout_t select_on( const select_op_t *select_op, data_size_t op_size, c if (op_size < offsetof( select_op_t, wait.handles ) || count > MAXIMUM_WAIT_OBJECTS) { set_error( STATUS_INVALID_PARAMETER ); - return 0; + return; } - if (!wait_on_handles( select_op, count, select_op->wait.handles, flags, timeout )) - return timeout; + if (!wait_on_handles( select_op, count, select_op->wait.handles, flags, when )) + return; break; case SELECT_SIGNAL_AND_WAIT: - if (!wait_on_handles( select_op, 1, &select_op->signal_and_wait.wait, flags, timeout )) - return timeout; + if (!wait_on_handles( select_op, 1, &select_op->signal_and_wait.wait, flags, when )) + return; if (select_op->signal_and_wait.signal) { if (!signal_object( select_op->signal_and_wait.signal )) { end_wait( current, get_error() ); - return timeout; + return; } /* check if we woke ourselves up */ - if (!current->wait) return timeout; + if (!current->wait) return; } break; @@ -921,38 +920,38 @@ static timeout_t select_on( const select_op_t *select_op, data_size_t op_size, c 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 ); + if (!object) return; + ret = wait_on( select_op, 1, &object, flags, when ); release_object( object ); - if (!ret) return timeout; + if (!ret) return; current->wait->key = select_op->keyed_event.key; break; default: set_error( STATUS_INVALID_PARAMETER ); - return 0; + return; } if ((ret = check_wait( current )) != -1) { /* condition is already satisfied */ set_error( end_wait( current, ret )); - return timeout; + return; } /* now we need to wait */ - if (current->wait->timeout != TIMEOUT_INFINITE) + if (current->wait->when != TIMEOUT_INFINITE) { - if (!(current->wait->user = add_timeout_user( current->wait->timeout, + if (!(current->wait->user = add_timeout_user( abstime_to_timeout(current->wait->when), thread_timeout, current->wait ))) { end_wait( current, get_error() ); - return timeout; + return; } } current->wait->cookie = cookie; set_error( STATUS_PENDING ); - return timeout; + return; } /* attempt to wake threads sleeping on the object wait queue */ @@ -1577,7 +1576,7 @@ DECL_HANDLER(select) release_object( apc ); } - reply->timeout = select_on( &select_op, op_size, req->cookie, req->flags, req->timeout ); + select_on( &select_op, op_size, req->cookie, req->flags, req->timeout ); while (get_error() == STATUS_USER_APC) { diff --git a/server/trace.c b/server/trace.c index b60422c4481..46c433e7a1d 100644 --- a/server/trace.c +++ b/server/trace.c @@ -88,6 +88,12 @@ static void dump_timeout( const char *prefix, const timeout_t *time ) fprintf( stderr, "%s%s", prefix, get_timeout_str(*time) ); } +static void dump_abstime( const char *prefix, const abstime_t *when ) +{ + timeout_t timeout = abstime_to_timeout( *when ); + dump_timeout( prefix, &timeout ); +} + static void dump_uint64( const char *prefix, const unsigned __int64 *val ) { if ((unsigned int)*val != *val) @@ -1581,7 +1587,7 @@ static void dump_select_request( const struct select_request *req ) { fprintf( stderr, " flags=%d", req->flags ); dump_uint64( ", cookie=", &req->cookie ); - dump_timeout( ", timeout=", &req->timeout ); + dump_abstime( ", timeout=", &req->timeout ); fprintf( stderr, ", prev_apc=%04x", req->prev_apc ); dump_varargs_apc_result( ", result=", cur_size ); dump_varargs_select_op( ", data=", cur_size ); @@ -1589,8 +1595,7 @@ static void dump_select_request( const struct select_request *req ) static void dump_select_reply( const struct select_reply *req ) { - dump_timeout( " timeout=", &req->timeout ); - dump_apc_call( ", call=", &req->call ); + dump_apc_call( " call=", &req->call ); fprintf( stderr, ", apc_handle=%04x", req->apc_handle ); } diff --git a/tools/make_requests b/tools/make_requests index a30c9be9056..7251cd86fcd 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -43,6 +43,7 @@ my %formats = "mem_size_t" => [ 8, 8, "&dump_uint64" ], "affinity_t" => [ 8, 8, "&dump_uint64" ], "timeout_t" => [ 8, 8, "&dump_timeout" ], + "abstime_t" => [ 8, 8, "&dump_abstime" ], "rectangle_t" => [ 16, 4, "&dump_rectangle" ], "char_info_t" => [ 4, 2, "&dump_char_info" ], "apc_call_t" => [ 40, 8, "&dump_apc_call" ],