From: Piotr Caban Subject: [PATCH 5/6 v2] server: Use correct clock in select. Message-Id: <4000fd2b-fd22-3654-71c0-e07d4437af2f@codeweavers.com> Date: Mon, 6 Apr 2020 17:21:19 +0200 Signed-off-by: Piotr Caban --- dlls/ntdll/server.c | 11 +++++++-- dlls/ntdll/sync.c | 11 +++++++-- server/protocol.def | 3 +-- server/thread.c | 55 ++++++++++++++++++++++----------------------- server/trace.c | 6 +++++ tools/make_requests | 1 + 6 files changed, 53 insertions(+), 34 deletions(-) diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index df847d09a2..d6b9b2ff0a 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 4a7b461627..bd71511cfb 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/server/protocol.def b/server/protocol.def index cc23ee84db..93b558cc2b 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/thread.c b/server/thread.c index 6e677c8cf2..ba481223b7 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 b60422c448..18c994eaac 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) diff --git a/tools/make_requests b/tools/make_requests index a30c9be905..7251cd86fc 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" ],