[PATCH] server: Implement serial port read interval timeouts.

Alex Henrie alexhenrie24 at gmail.com
Wed Jan 27 00:57:01 CST 2016


Fixes https://bugs.winehq.org/show_bug.cgi?id=39875

There is a test program attached to the bug report.

Version 3 has all the logic in serial.c, even though this required
adding a getter in async.c and another getter in fd.c. The first
interval timeout no longer trashes subsequent interval timeouts or
the total timeout, and absolute timeouts are used exclusively.

Signed-off-by: Alex Henrie <alexhenrie24 at gmail.com>
---
 server/async.c  | 22 ++++++++++++++++++++++
 server/fd.c     | 16 ++++++++++++++++
 server/file.h   |  5 +++++
 server/serial.c | 29 ++++++++++++++++++++++++++++-
 4 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/server/async.c b/server/async.c
index d2da976..c369264 100644
--- a/server/async.c
+++ b/server/async.c
@@ -216,6 +216,28 @@ void free_async_queue( struct async_queue *queue )
     release_object( queue );
 }
 
+timeout_t get_async_queue_head_timeout( struct async_queue *queue )
+{
+    struct list *ptr;
+    struct async *async;
+
+    if (!(ptr = list_head( &queue->queue ))) return 0;
+    async = LIST_ENTRY( ptr, struct async, queue_entry );
+
+    return async->timeout ? get_timeout_user_when( async->timeout ) : TIMEOUT_INFINITE;
+}
+
+void set_async_queue_head_timeout( struct async_queue *queue, timeout_t timeout, unsigned int status )
+{
+    struct list *ptr;
+    struct async *async;
+
+    if (!(ptr = list_head( &queue->queue ))) return;
+    async = LIST_ENTRY( ptr, struct async, queue_entry );
+
+    async_set_timeout( async, timeout, status );
+}
+
 /* create an async on a given queue of a fd */
 struct async *create_async( struct thread *thread, struct async_queue *queue, const async_data_t *data )
 {
diff --git a/server/fd.c b/server/fd.c
index 559a737..39e0046 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -391,6 +391,11 @@ void remove_timeout_user( struct timeout_user *user )
     free( user );
 }
 
+timeout_t get_timeout_user_when( struct timeout_user *user )
+{
+    return user->when;
+}
+
 /* return a text description of a timeout for debugging purposes */
 const char *get_timeout_str( timeout_t timeout )
 {
@@ -426,6 +431,11 @@ const char *get_timeout_str( timeout_t timeout )
     return buffer;
 }
 
+timeout_t get_current_time( void )
+{
+    return current_time;
+}
+
 
 /****************************************************************/
 /* poll support */
@@ -1958,6 +1968,12 @@ int is_fd_signaled( struct fd *fd )
     return fd->signaled;
 }
 
+/* check if a queue is this fd's read queue */
+int is_read_queue( struct fd *fd, struct async_queue *queue )
+{
+    return fd->read_q == queue;
+}
+
 /* handler for close_handle that refuses to close fd-associated handles in other processes */
 int fd_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
 {
diff --git a/server/file.h b/server/file.h
index b59de1c..d7b0734 100644
--- a/server/file.h
+++ b/server/file.h
@@ -81,6 +81,7 @@ extern void unlock_fd( struct fd *fd, file_pos_t offset, file_pos_t count );
 extern void allow_fd_caching( struct fd *fd );
 extern void set_fd_signaled( struct fd *fd, int signaled );
 extern int is_fd_signaled( struct fd *fd );
+extern int is_read_queue( struct fd *fd, struct async_queue *queue );
 extern char *dup_fd_name( struct fd *root, const char *name );
 
 extern int default_fd_signaled( struct object *obj, struct wait_queue_entry *entry );
@@ -116,7 +117,9 @@ typedef void (*timeout_callback)( 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 timeout_t get_timeout_user_when( struct timeout_user *user );
 extern const char *get_timeout_str( timeout_t timeout );
+extern timeout_t get_current_time( void );
 
 /* file functions */
 
@@ -167,6 +170,8 @@ extern struct object *create_serial( struct fd *fd );
 /* async I/O functions */
 extern struct async_queue *create_async_queue( struct fd *fd );
 extern void free_async_queue( struct async_queue *queue );
+extern timeout_t get_async_queue_head_timeout( struct async_queue *queue );
+extern void set_async_queue_head_timeout( struct async_queue *queue, timeout_t timeout, unsigned int status );
 extern struct async *create_async( struct thread *thread, struct async_queue *queue,
                                    const async_data_t *data );
 extern void async_set_timeout( struct async *async, timeout_t timeout, unsigned int status );
diff --git a/server/serial.c b/server/serial.c
index 164a4b1..1a42a1d 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -62,6 +62,7 @@ static void serial_destroy(struct object *obj);
 
 static enum server_fd_type serial_get_fd_type( struct fd *fd );
 static void serial_queue_async( struct fd *fd, const async_data_t *data, int type, int count );
+static void serial_reselect_async( struct fd *fd, struct async_queue *queue );
 
 struct serial
 {
@@ -82,6 +83,9 @@ struct serial
 
     struct termios      original;
 
+    timeout_t           read_total_timeout;
+    timeout_t           read_interval_timeout;
+
     /* FIXME: add dcb, comm status, handler module, sharing */
 };
 
@@ -115,7 +119,7 @@ static const struct fd_ops serial_fd_ops =
     no_fd_flush,                  /* flush */
     default_fd_ioctl,             /* ioctl */
     serial_queue_async,           /* queue_async */
-    default_fd_reselect_async,    /* reselect_async */
+    serial_reselect_async,        /* reselect_async */
     default_fd_cancel_async       /* cancel_async */
 };
 
@@ -143,6 +147,8 @@ struct object *create_serial( struct fd *fd )
     serial->generation   = 0;
     serial->pending_write = 0;
     serial->pending_wait = 0;
+    serial->read_total_timeout = 0;
+    serial->read_interval_timeout = 0;
     serial->fd = (struct fd *)grab_object( fd );
     set_fd_user( fd, &serial_fd_ops, &serial->obj );
     return &serial->obj;
@@ -203,6 +209,27 @@ static void serial_queue_async( struct fd *fd, const async_data_t *data, int typ
     }
 }
 
+static void serial_reselect_async( struct fd *fd, struct async_queue *queue )
+{
+    struct serial *serial = get_fd_user( fd );
+
+    if (is_read_queue( fd, queue ) && serial->readinterval)
+    {
+        timeout_t queue_timeout = get_async_queue_head_timeout( queue );
+
+        /* if the queue timeout does not equal the saved total or interval timeout, a new read operation has begun */
+        if (queue_timeout != serial->read_total_timeout && queue_timeout != serial->read_interval_timeout)
+            serial->read_total_timeout = queue_timeout;
+
+        serial->read_interval_timeout = get_current_time() + serial->readinterval * 10000;
+
+        queue_timeout = min( serial->read_total_timeout, serial->read_interval_timeout );
+        set_async_queue_head_timeout( queue, queue_timeout, STATUS_TIMEOUT );
+    }
+
+    default_fd_reselect_async( fd, queue );
+}
+
 DECL_HANDLER(get_serial_info)
 {
     struct serial *serial;
-- 
2.7.0




More information about the wine-patches mailing list