Piotr Caban : server: Use monotonic clock for relative timeouts.

Alexandre Julliard julliard at winehq.org
Thu Apr 9 16:04:46 CDT 2020


Module: wine
Branch: master
Commit: f016a9634545050bc016d589347b7097f2f48f81
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=f016a9634545050bc016d589347b7097f2f48f81

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Mon Apr  6 17:21:03 2020 +0200

server: Use monotonic clock for relative timeouts.

Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 include/wine/server_protocol.h |  3 +++
 server/fd.c                    | 55 ++++++++++++++++++++++++++++++++++--------
 server/file.h                  |  6 +++++
 server/protocol.def            |  3 +++
 server/request.c               | 14 +++++------
 server/request.h               |  8 +++++-
 6 files changed, 71 insertions(+), 18 deletions(-)

diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index ba70d13a39..fa0b7ff406 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 c9ef8fde6d..39fb419f25 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 ea36cdb07d..4f130e2cf7 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 722993e59c..e12e6fbdbf 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 200c2697db..4c1f30a5fe 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 a5472dd1c2..e7e05af0e4 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)
 {




More information about the wine-cvs mailing list