[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