server: Use monotonic clock for relative timeouts.
Signed-off-by: Piotr Caban <piotr@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
9bfbb48662
commit
f016a96345
|
@ -199,6 +199,9 @@ typedef __int64 timeout_t;
|
||||||
#define TIMEOUT_INFINITE (((timeout_t)0x7fffffff) << 32 | 0xffffffff)
|
#define TIMEOUT_INFINITE (((timeout_t)0x7fffffff) << 32 | 0xffffffff)
|
||||||
|
|
||||||
|
|
||||||
|
typedef __int64 abstime_t;
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned int debug_flags;
|
unsigned int debug_flags;
|
||||||
|
|
55
server/fd.c
55
server/fd.c
|
@ -364,13 +364,15 @@ static file_pos_t max_unix_offset = OFF_T_MAX;
|
||||||
struct timeout_user
|
struct timeout_user
|
||||||
{
|
{
|
||||||
struct list entry; /* entry in sorted timeout list */
|
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 */
|
timeout_callback callback; /* callback function */
|
||||||
void *private; /* callback private data */
|
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 current_time;
|
||||||
|
timeout_t monotonic_time;
|
||||||
|
|
||||||
void set_current_time(void)
|
void set_current_time(void)
|
||||||
{
|
{
|
||||||
|
@ -378,6 +380,7 @@ void set_current_time(void)
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
gettimeofday( &now, NULL );
|
gettimeofday( &now, NULL );
|
||||||
current_time = (timeout_t)now.tv_sec * TICKS_PER_SEC + now.tv_usec * 10 + ticks_1601_to_1970;
|
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 */
|
/* add a timeout user */
|
||||||
|
@ -387,16 +390,27 @@ struct timeout_user *add_timeout_user( timeout_t when, timeout_callback func, vo
|
||||||
struct list *ptr;
|
struct list *ptr;
|
||||||
|
|
||||||
if (!(user = mem_alloc( sizeof(*user) ))) return NULL;
|
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->callback = func;
|
||||||
user->private = private;
|
user->private = private;
|
||||||
|
|
||||||
/* Now insert it in the linked list */
|
/* 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 );
|
LIST_FOR_EACH( ptr, &abs_timeout_list )
|
||||||
if (timeout->when >= user->when) break;
|
{
|
||||||
|
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 );
|
list_add_before( ptr, &user->entry );
|
||||||
return user;
|
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 */
|
/* process pending timeouts and return the time until the next timeout, in milliseconds */
|
||||||
static int get_next_timeout(void)
|
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;
|
struct list expired_list, *ptr;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
/* first remove all expired timers from the list */
|
/* first remove all expired timers from the list */
|
||||||
|
|
||||||
list_init( &expired_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 );
|
struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
|
||||||
|
|
||||||
|
@ -869,6 +884,17 @@ static int get_next_timeout(void)
|
||||||
}
|
}
|
||||||
else break;
|
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 */
|
/* now call the callback for all the removed timers */
|
||||||
|
|
||||||
|
@ -880,13 +906,22 @@ static int get_next_timeout(void)
|
||||||
free( timeout );
|
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 );
|
struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry );
|
||||||
int diff = (timeout->when - current_time + 9999) / 10000;
|
int diff = (timeout->when - current_time + 9999) / 10000;
|
||||||
if (diff < 0) diff = 0;
|
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 */
|
return -1; /* no pending timeouts */
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,11 +129,17 @@ static inline struct fd *get_obj_fd( struct object *obj ) { return obj->ops->get
|
||||||
|
|
||||||
struct timeout_user;
|
struct timeout_user;
|
||||||
extern timeout_t current_time;
|
extern timeout_t current_time;
|
||||||
|
extern timeout_t monotonic_time;
|
||||||
|
|
||||||
#define TICKS_PER_SEC 10000000
|
#define TICKS_PER_SEC 10000000
|
||||||
|
|
||||||
typedef void (*timeout_callback)( void *private );
|
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 void set_current_time( void );
|
||||||
extern struct timeout_user *add_timeout_user( timeout_t when, timeout_callback func, void *private );
|
extern struct timeout_user *add_timeout_user( timeout_t when, timeout_callback func, void *private );
|
||||||
extern void remove_timeout_user( struct timeout_user *user );
|
extern void remove_timeout_user( struct timeout_user *user );
|
||||||
|
|
|
@ -214,6 +214,9 @@ struct wake_up_reply
|
||||||
typedef __int64 timeout_t;
|
typedef __int64 timeout_t;
|
||||||
#define TIMEOUT_INFINITE (((timeout_t)0x7fffffff) << 32 | 0xffffffff)
|
#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 */
|
/* structure for process startup info */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|
|
@ -522,8 +522,8 @@ int send_client_fd( struct process *process, int fd, obj_handle_t handle )
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get current tick count to return to client */
|
/* return a monotonic time counter */
|
||||||
unsigned int get_tick_count(void)
|
timeout_t monotonic_counter(void)
|
||||||
{
|
{
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
static mach_timebase_info_data_t timebase;
|
static mach_timebase_info_data_t timebase;
|
||||||
|
@ -531,19 +531,19 @@ unsigned int get_tick_count(void)
|
||||||
if (!timebase.denom) mach_timebase_info( &timebase );
|
if (!timebase.denom) mach_timebase_info( &timebase );
|
||||||
#ifdef HAVE_MACH_CONTINUOUS_TIME
|
#ifdef HAVE_MACH_CONTINUOUS_TIME
|
||||||
if (&mach_continuous_time != NULL)
|
if (&mach_continuous_time != NULL)
|
||||||
return mach_continuous_time() * timebase.numer / timebase.denom / 1000000;
|
return mach_continuous_time() * timebase.numer / timebase.denom / 100;
|
||||||
#endif
|
#endif
|
||||||
return mach_absolute_time() * timebase.numer / timebase.denom / 1000000;
|
return mach_absolute_time() * timebase.numer / timebase.denom / 100;
|
||||||
#elif defined(HAVE_CLOCK_GETTIME)
|
#elif defined(HAVE_CLOCK_GETTIME)
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
#ifdef CLOCK_MONOTONIC_RAW
|
#ifdef CLOCK_MONOTONIC_RAW
|
||||||
if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts ))
|
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
|
#endif
|
||||||
if (!clock_gettime( CLOCK_MONOTONIC, &ts ))
|
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
|
#endif
|
||||||
return (current_time - server_start_time) / 10000;
|
return current_time - server_start_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void master_socket_dump( struct object *obj, int verbose )
|
static void master_socket_dump( struct object *obj, int verbose )
|
||||||
|
|
|
@ -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 int send_client_fd( struct process *process, int fd, obj_handle_t handle );
|
||||||
extern void read_request( struct thread *thread );
|
extern void read_request( struct thread *thread );
|
||||||
extern void write_reply( 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 open_master_socket(void);
|
||||||
extern void close_master_socket( timeout_t timeout );
|
extern void close_master_socket( timeout_t timeout );
|
||||||
extern void shutdown_master_socket(void);
|
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_request(void);
|
||||||
extern void trace_reply( enum request req, const union generic_reply *reply );
|
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 */
|
/* get the request vararg data */
|
||||||
static inline const void *get_req_data(void)
|
static inline const void *get_req_data(void)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue