[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