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

Alex Henrie alexhenrie24 at gmail.com
Fri Jan 15 00:50:21 CST 2016


Cc: Sebastian Lackner <sebastian at fds-team.de>

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

There is a test program attached to the bug report.

Signed-off-by: Alex Henrie <alexhenrie24 at gmail.com>
---
 server/async.c  | 13 +++++++++++++
 server/fd.c     |  6 ++++++
 server/file.h   |  2 ++
 server/serial.c |  3 +++
 4 files changed, 24 insertions(+)

diff --git a/server/async.c b/server/async.c
index d2da976..e435f39 100644
--- a/server/async.c
+++ b/server/async.c
@@ -41,6 +41,8 @@ struct async
     unsigned int         status;          /* current status */
     struct timeout_user *timeout;
     unsigned int         timeout_status;  /* status to report upon timeout */
+    timeout_t            read_interval;   /* max time between receiving one byte and the next */
+    unsigned int         interval_status; /* status to report upon read interval timeout */
     int                  signaled;
     struct event        *event;
     async_data_t         data;            /* data for async I/O call */
@@ -237,6 +239,7 @@ struct async *create_async( struct thread *thread, struct async_queue *queue, co
     async->data    = *data;
     async->timeout = NULL;
     async->queue   = (struct async_queue *)grab_object( queue );
+    async->read_interval = TIMEOUT_INFINITE;
     async->signaled = 0;
 
     list_add_tail( &queue->queue, &async->queue_entry );
@@ -256,6 +259,13 @@ void async_set_timeout( struct async *async, timeout_t timeout, unsigned int sta
     async->timeout_status = status;
 }
 
+/* set the maximum allowed time between receiving one byte and the next during an async operation */
+void async_set_read_interval( struct async *async, timeout_t interval, unsigned int status )
+{
+    async->read_interval = interval;
+    async->interval_status = status;
+}
+
 static void add_async_completion( struct async_queue *queue, apc_param_t cvalue, unsigned int status,
                                   apc_param_t information )
 {
@@ -294,6 +304,9 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota
             async_terminate( async, status );
         else
             async_reselect( async );
+
+        if (!async->timeout || async->read_interval < get_timeout_user_remaining( async->timeout ))
+            async_set_timeout( async, -async->read_interval, async->interval_status );
     }
     else
     {
diff --git a/server/fd.c b/server/fd.c
index e3fe292..05e6c5f 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -391,6 +391,12 @@ void remove_timeout_user( struct timeout_user *user )
     free( user );
 }
 
+/* return how much time is left before the timeout happens */
+timeout_t get_timeout_user_remaining( struct timeout_user *user )
+{
+    return user->when - current_time;
+}
+
 /* return a text description of a timeout for debugging purposes */
 const char *get_timeout_str( timeout_t timeout )
 {
diff --git a/server/file.h b/server/file.h
index b59de1c..0d8fd39 100644
--- a/server/file.h
+++ b/server/file.h
@@ -116,6 +116,7 @@ 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_remaining( struct timeout_user *user );
 extern const char *get_timeout_str( timeout_t timeout );
 
 /* file functions */
@@ -170,6 +171,7 @@ extern void free_async_queue( struct async_queue *queue );
 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 );
+extern void async_set_read_interval( struct async *async, timeout_t interval, unsigned int status );
 extern void async_set_result( struct object *obj, unsigned int status,
                               apc_param_t total, client_ptr_t apc, client_ptr_t apc_arg );
 extern int async_queued( struct async_queue *queue );
diff --git a/server/serial.c b/server/serial.c
index 164a4b1..1303f68 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -181,6 +181,7 @@ static void serial_queue_async( struct fd *fd, const async_data_t *data, int typ
 {
     struct serial *serial = get_fd_user( fd );
     timeout_t timeout = 0;
+    timeout_t read_interval = 0;
     struct async *async;
 
     assert(serial->obj.ops == &serial_ops);
@@ -189,6 +190,7 @@ static void serial_queue_async( struct fd *fd, const async_data_t *data, int typ
     {
     case ASYNC_TYPE_READ:
         timeout = serial->readconst + (timeout_t)serial->readmult*count;
+        read_interval = serial->readinterval;
         break;
     case ASYNC_TYPE_WRITE:
         timeout = serial->writeconst + (timeout_t)serial->writemult*count;
@@ -198,6 +200,7 @@ static void serial_queue_async( struct fd *fd, const async_data_t *data, int typ
     if ((async = fd_queue_async( fd, data, type )))
     {
         if (timeout) async_set_timeout( async, timeout * -10000, STATUS_TIMEOUT );
+        if (read_interval) async_set_read_interval( async, read_interval * 10000, STATUS_TIMEOUT );
         release_object( async );
         set_error( STATUS_PENDING );
     }
-- 
2.7.0




More information about the wine-patches mailing list