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

Alex Henrie alexhenrie24 at gmail.com
Wed Jan 20 22:04:01 CST 2016


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  | 14 ++++++++++++++
 server/fd.c     | 12 ++++++++++++
 server/file.h   |  3 +++
 server/serial.c | 13 ++++++++++++-
 4 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/server/async.c b/server/async.c
index d2da976..e718462 100644
--- a/server/async.c
+++ b/server/async.c
@@ -216,6 +216,20 @@ void free_async_queue( struct async_queue *queue )
     release_object( queue );
 }
 
+/* set the timeout of the async queue head if the new timeout is shorter than the current one */
+/* only pass negative timeouts (i.e. timeouts relative to the current time) to this function */
+void async_queue_set_shorter_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 );
+
+    if (!async->timeout || -timeout < get_timeout_user_remaining( async->timeout ))
+        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..112f8a1 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 )
 {
@@ -1958,6 +1964,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..cdc761d 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,6 +117,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 */
@@ -167,6 +169,7 @@ 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 void async_queue_set_shorter_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..0767c12 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
 {
@@ -115,7 +116,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 */
 };
 
@@ -203,6 +204,16 @@ 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)
+        async_queue_set_shorter_timeout( queue, serial->readinterval * -10000, 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