diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index ba70d13a391..fa0b7ff406b 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -199,6 +199,9 @@ typedef __int64 timeout_t; #define TIMEOUT_INFINITE (((timeout_t)0x7fffffff) << 32 | 0xffffffff) +typedef __int64 abstime_t; + + typedef struct { unsigned int debug_flags; diff --git a/server/fd.c b/server/fd.c index c9ef8fde6db..39fb419f25f 100644 --- a/server/fd.c +++ b/server/fd.c @@ -364,13 +364,15 @@ static file_pos_t max_unix_offset = OFF_T_MAX; struct timeout_user { struct list entry; /* entry in sorted timeout list */ - timeout_t when; /* timeout expiry (absolute time) */ + abstime_t when; /* timeout expiry */ timeout_callback callback; /* callback function */ void *private; /* callback private data */ }; -static struct list timeout_list = LIST_INIT(timeout_list); /* sorted timeouts list */ +static struct list abs_timeout_list = LIST_INIT(abs_timeout_list); /* sorted absolute timeouts list */ +static struct list rel_timeout_list = LIST_INIT(rel_timeout_list); /* sorted relative timeouts list */ timeout_t current_time; +timeout_t monotonic_time; void set_current_time(void) { @@ -378,6 +380,7 @@ void set_current_time(void) struct timeval now; gettimeofday( &now, NULL ); current_time = (timeout_t)now.tv_sec * TICKS_PER_SEC + now.tv_usec * 10 + ticks_1601_to_1970; + monotonic_time = monotonic_counter(); } /* add a timeout user */ @@ -387,16 +390,27 @@ struct timeout_user *add_timeout_user( timeout_t when, timeout_callback func, vo struct list *ptr; if (!(user = mem_alloc( sizeof(*user) ))) return NULL; - user->when = (when > 0) ? when : current_time - when; + user->when = timeout_to_abstime( when ); user->callback = func; user->private = private; /* Now insert it in the linked list */ - LIST_FOR_EACH( ptr, &timeout_list ) + if (user->when > 0) { - struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry ); - if (timeout->when >= user->when) break; + LIST_FOR_EACH( ptr, &abs_timeout_list ) + { + struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry ); + if (timeout->when >= user->when) break; + } + } + else + { + LIST_FOR_EACH( ptr, &rel_timeout_list ) + { + struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry ); + if (timeout->when <= user->when) break; + } } list_add_before( ptr, &user->entry ); return user; @@ -851,14 +865,15 @@ static void remove_poll_user( struct fd *fd, int user ) /* process pending timeouts and return the time until the next timeout, in milliseconds */ static int get_next_timeout(void) { - if (!list_empty( &timeout_list )) + if (!list_empty( &abs_timeout_list ) || !list_empty( &rel_timeout_list )) { struct list expired_list, *ptr; + int ret = -1; /* first remove all expired timers from the list */ list_init( &expired_list ); - while ((ptr = list_head( &timeout_list )) != NULL) + while ((ptr = list_head( &abs_timeout_list )) != NULL) { struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry ); @@ -869,6 +884,17 @@ static int get_next_timeout(void) } else break; } + while ((ptr = list_head( &rel_timeout_list )) != NULL) + { + struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry ); + + if (-timeout->when <= monotonic_time) + { + list_remove( &timeout->entry ); + list_add_tail( &expired_list, &timeout->entry ); + } + else break; + } /* now call the callback for all the removed timers */ @@ -880,13 +906,22 @@ static int get_next_timeout(void) free( timeout ); } - if ((ptr = list_head( &timeout_list )) != NULL) + if ((ptr = list_head( &abs_timeout_list )) != NULL) { struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry ); int diff = (timeout->when - current_time + 9999) / 10000; if (diff < 0) diff = 0; - return diff; + ret = diff; } + + if ((ptr = list_head( &rel_timeout_list )) != NULL) + { + struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry ); + int diff = (-timeout->when - monotonic_time + 9999) / 10000; + if (diff < 0) diff = 0; + if (ret == -1 || diff < ret) ret = diff; + } + return ret; } return -1; /* no pending timeouts */ } diff --git a/server/file.h b/server/file.h index ea36cdb07d5..4f130e2cf78 100644 --- a/server/file.h +++ b/server/file.h @@ -129,11 +129,17 @@ static inline struct fd *get_obj_fd( struct object *obj ) { return obj->ops->get struct timeout_user; extern timeout_t current_time; +extern timeout_t monotonic_time; #define TICKS_PER_SEC 10000000 typedef void (*timeout_callback)( void *private ); +static inline abstime_t timeout_to_abstime( timeout_t timeout ) +{ + return timeout > 0 ? timeout : timeout - monotonic_time; +} + extern void set_current_time( void ); extern struct timeout_user *add_timeout_user( timeout_t when, timeout_callback func, void *private ); extern void remove_timeout_user( struct timeout_user *user ); diff --git a/server/protocol.def b/server/protocol.def index 722993e59c7..e12e6fbdbf6 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -214,6 +214,9 @@ struct wake_up_reply typedef __int64 timeout_t; #define TIMEOUT_INFINITE (((timeout_t)0x7fffffff) << 32 | 0xffffffff) +/* absolute timeout, negative means that monotonic clock is used */ +typedef __int64 abstime_t; + /* structure for process startup info */ typedef struct { diff --git a/server/request.c b/server/request.c index 200c2697dbd..4c1f30a5fe7 100644 --- a/server/request.c +++ b/server/request.c @@ -522,8 +522,8 @@ int send_client_fd( struct process *process, int fd, obj_handle_t handle ) return -1; } -/* get current tick count to return to client */ -unsigned int get_tick_count(void) +/* return a monotonic time counter */ +timeout_t monotonic_counter(void) { #ifdef __APPLE__ static mach_timebase_info_data_t timebase; @@ -531,19 +531,19 @@ unsigned int get_tick_count(void) if (!timebase.denom) mach_timebase_info( &timebase ); #ifdef HAVE_MACH_CONTINUOUS_TIME if (&mach_continuous_time != NULL) - return mach_continuous_time() * timebase.numer / timebase.denom / 1000000; + return mach_continuous_time() * timebase.numer / timebase.denom / 100; #endif - return mach_absolute_time() * timebase.numer / timebase.denom / 1000000; + return mach_absolute_time() * timebase.numer / timebase.denom / 100; #elif defined(HAVE_CLOCK_GETTIME) struct timespec ts; #ifdef CLOCK_MONOTONIC_RAW if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts )) - return ts.tv_sec * 1000 + ts.tv_nsec / 1000000; + return (timeout_t)ts.tv_sec * TICKS_PER_SEC + ts.tv_nsec / 100; #endif if (!clock_gettime( CLOCK_MONOTONIC, &ts )) - return ts.tv_sec * 1000 + ts.tv_nsec / 1000000; + return (timeout_t)ts.tv_sec * TICKS_PER_SEC + ts.tv_nsec / 100; #endif - return (current_time - server_start_time) / 10000; + return current_time - server_start_time; } static void master_socket_dump( struct object *obj, int verbose ) diff --git a/server/request.h b/server/request.h index a5472dd1c2c..e7e05af0e49 100644 --- a/server/request.h +++ b/server/request.h @@ -54,7 +54,7 @@ extern int receive_fd( struct process *process ); extern int send_client_fd( struct process *process, int fd, obj_handle_t handle ); extern void read_request( struct thread *thread ); extern void write_reply( struct thread *thread ); -extern unsigned int get_tick_count(void); +extern timeout_t monotonic_counter(void); extern void open_master_socket(void); extern void close_master_socket( timeout_t timeout ); extern void shutdown_master_socket(void); @@ -66,6 +66,12 @@ extern int server_dir_fd, config_dir_fd; extern void trace_request(void); extern void trace_reply( enum request req, const union generic_reply *reply ); +/* get current tick count to return to client */ +static inline unsigned int get_tick_count(void) +{ + return monotonic_counter() / 10000; +} + /* get the request vararg data */ static inline const void *get_req_data(void) {