- created server object for handling async i/o
- implemented WaitCommEvent with the EV_RXCHAR flag
- implemented GetOverlappedResult
diff --git a/server/Makefile.in b/server/Makefile.in
index a7779f3..6f1c36a 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -6,6 +6,7 @@
MODULE = none
C_SRCS = \
+ async.c \
atom.c \
change.c \
console.c \
diff --git a/server/async.c b/server/async.c
new file mode 100644
index 0000000..379d130
--- /dev/null
+++ b/server/async.c
@@ -0,0 +1,270 @@
+/*
+ * Server-side support for async i/o operations
+ *
+ * Copyright (C) 1998 Alexandre Julliard
+ * Copyright (C) 2000 Mike McCormack
+ *
+ * TODO:
+ * Fix up WaitCommEvent operations. Currently only EV_RXCHAR is supported.
+ * This may require modifications to the linux kernel to enable select
+ * to wait on Modem Status Register deltas. (delta DCD, CTS, DSR or RING)
+ *
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#ifdef HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+
+#include "winerror.h"
+#include "winbase.h"
+
+#include "handle.h"
+#include "thread.h"
+#include "request.h"
+
+struct async
+{
+ struct object obj;
+ void *client_overlapped;
+ int type;
+ int result;
+ int count;
+ int eventmask;
+ struct async *next;
+ struct timeout_user *timeout;
+ struct wait_queue_entry wait;
+ void *buffer;
+ void *func;
+ struct thread *thread;
+ struct object *file;
+};
+
+static void async_dump( struct object *obj, int verbose );
+static void async_destroy( struct object *obj );
+static int async_get_poll_events( struct object *obj );
+static int async_get_read_fd( struct object *obj );
+static int async_get_write_fd( struct object *obj );
+static int async_get_info( struct object *obj, struct get_file_info_request *req );
+static void async_poll_event( struct object *obj, int event );
+
+static const struct object_ops async_ops =
+{
+ sizeof(struct async), /* size */
+ async_dump, /* dump */
+ default_poll_add_queue, /* add_queue */
+ default_poll_remove_queue, /* remove_queue */
+ default_poll_signaled, /* signaled */
+ no_satisfied, /* satisfied */
+ async_get_poll_events, /* get_poll_events */
+ async_poll_event, /* poll_event */
+ async_get_read_fd, /* get_read_fd */
+ async_get_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ async_get_info, /* get_file_info */
+ async_destroy /* destroy */
+};
+
+static void async_dump( struct object *obj, int verbose )
+{
+ struct async *ov = (struct async *)obj;
+
+ assert( obj->ops == &async_ops );
+
+ fprintf( stderr, "async: overlapped %p %s\n",
+ ov->client_overlapped, ov->timeout?"with timeout":"");
+}
+
+/* same as file_destroy, but don't delete comm ports */
+static void async_destroy( struct object *obj )
+{
+ struct async *ov = (struct async *)obj;
+ assert( obj->ops == &async_ops );
+
+ if(ov->timeout)
+ remove_timeout_user(ov->timeout);
+ ov->timeout = NULL;
+}
+
+struct async *get_async_obj( struct process *process, int handle, unsigned int access )
+{
+ return (struct async *)get_handle_obj( process, handle, access, &async_ops );
+}
+
+static int async_get_poll_events( struct object *obj )
+{
+ struct async *ov = (struct async *)obj;
+ assert( obj->ops == &async_ops );
+
+ /* FIXME: this should be a function pointer */
+ return serial_async_get_poll_events(ov);
+}
+
+static int async_get_read_fd( struct object *obj )
+{
+ struct async *async = (struct async *)obj;
+ assert( obj->ops == &async_ops );
+ return dup( async->obj.fd );
+}
+
+static int async_get_write_fd( struct object *obj )
+{
+ struct async *async = (struct async *)obj;
+ assert( obj->ops == &async_ops );
+ return dup( async->obj.fd );
+}
+
+static int async_get_info( struct object *obj, struct get_file_info_request *req ) {
+ assert( obj->ops == &async_ops );
+ req->type = FILE_TYPE_CHAR;
+ req->attr = 0;
+ req->access_time = 0;
+ req->write_time = 0;
+ req->size_high = 0;
+ req->size_low = 0;
+ req->links = 0;
+ req->index_high = 0;
+ req->index_low = 0;
+ req->serial = 0;
+ return 1;
+}
+
+/* data access functions */
+int async_type(struct async *ov)
+{
+ return ov->type;
+}
+
+int async_count(struct async *ov)
+{
+ return ov->count;
+}
+
+int async_get_eventmask(struct async *ov)
+{
+ return ov->eventmask;
+}
+
+int async_set_eventmask(struct async *ov, int eventmask)
+{
+ return ov->eventmask = eventmask;
+}
+
+DECL_HANDLER(create_async)
+{
+ struct object *obj;
+ struct async *ov = NULL;
+ int fd;
+
+ req->ov_handle = -1;
+ if (!(obj = get_handle_obj( current->process, req->file_handle, 0, NULL)) )
+ return;
+
+ fd = dup(obj->fd);
+ if(fd<0)
+ {
+ release_object(obj);
+ set_error(STATUS_UNSUCCESSFUL);
+ return;
+ }
+
+ if(0>fcntl(fd, F_SETFL, O_NONBLOCK))
+ {
+ release_object(obj);
+ set_error(STATUS_UNSUCCESSFUL);
+ return;
+ }
+
+ ov = alloc_object (&async_ops, fd);
+ if(!ov)
+ {
+ release_object(obj);
+ set_error(STATUS_UNSUCCESSFUL);
+ return;
+ }
+
+ ov->client_overlapped = req->overlapped;
+ ov->next = NULL;
+ ov->timeout = NULL;
+ ov->type = req->type;
+ ov->thread = current;
+ ov->func = req->func;
+ ov->file = obj;
+ ov->buffer = req->buffer;
+ ov->count = req->count;
+
+ /* FIXME: this should be a function pointer */
+ serial_async_setup(obj,ov);
+
+ ov->obj.ops->add_queue(&ov->obj,&ov->wait);
+
+ req->ov_handle = alloc_handle( current->process, ov, GENERIC_READ|GENERIC_WRITE, 0 );
+
+ release_object(obj);
+}
+
+/* handler for async poll() events */
+static void async_poll_event( struct object *obj, int event )
+{
+ struct async *ov = (struct async *) obj;
+
+ /* queue an APC in the client thread to do our dirty work */
+ ov->obj.ops->remove_queue(&ov->obj,&ov->wait);
+
+ /* FIXME: this should be a function pointer */
+ event = serial_async_poll_event(obj,event);
+
+ thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 3,
+ ov->client_overlapped, ov->buffer, event);
+}
+
+/* handler for async i/o timeouts */
+static void overlapped_timeout (void *private)
+{
+ struct async *ov = (struct async *) private;
+
+ ov->obj.ops->remove_queue(&ov->obj,&ov->wait);
+
+ thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 3,
+ ov->client_overlapped,ov->buffer, 0);
+}
+
+void async_add_timeout(struct async *ov, int timeout)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv,0);
+ add_timeout(&tv,timeout);
+ ov->timeout = add_timeout_user(&tv, overlapped_timeout, ov);
+}
+
+DECL_HANDLER(async_result)
+{
+ struct async *ov;
+
+ if ((ov = get_async_obj( current->process, req->ov_handle, 0 )))
+ {
+ ov->result = req->result;
+ if(ov->result == STATUS_PENDING)
+ {
+ ov->obj.ops->add_queue(&ov->obj,&ov->wait);
+ }
+ release_object( ov );
+ }
+}
+
diff --git a/server/object.h b/server/object.h
index ab52ed6..746b7f6 100644
--- a/server/object.h
+++ b/server/object.h
@@ -25,6 +25,7 @@
struct process;
struct file;
struct wait_queue_entry;
+struct async;
/* operations valid on all objects */
struct object_ops
@@ -156,6 +157,20 @@
extern struct file *create_temp_file( int access );
extern void file_set_error(void);
+/* async functions */
+
+void async_add_timeout(struct async *ov, int timeout);
+int async_count(struct async *ov);
+int async_type(struct async *ov);
+int async_get_eventmask(struct async *ov);
+int async_set_eventmask(struct async *ov, int eventmask);
+
+/* serial functions */
+
+int serial_async_setup(struct object *obj, struct async *ov);
+int serial_async_get_poll_events( struct async *ov );
+int serial_async_poll_event(struct object *obj, int event);
+
/* console functions */
extern int alloc_console( struct process *process );
diff --git a/server/request.h b/server/request.h
index ac80b7b..14dc2e3 100644
--- a/server/request.h
+++ b/server/request.h
@@ -202,6 +202,8 @@
DECL_HANDLER(create_serial);
DECL_HANDLER(get_serial_info);
DECL_HANDLER(set_serial_info);
+DECL_HANDLER(create_async);
+DECL_HANDLER(async_result);
#ifdef WANT_REQUEST_HANDLERS
@@ -316,6 +318,8 @@
(req_handler)req_create_serial,
(req_handler)req_get_serial_info,
(req_handler)req_set_serial_info,
+ (req_handler)req_create_async,
+ (req_handler)req_async_result,
};
#endif /* WANT_REQUEST_HANDLERS */
diff --git a/server/serial.c b/server/serial.c
index d102233..c549bec 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -182,6 +182,77 @@
return 1;
}
+/* these functions are for interaction with asynchronous i/o objects */
+int serial_async_setup(struct object *obj, struct async *ov)
+{
+ struct serial *serial = (struct serial *)obj;
+ int timeout;
+
+ if(obj->ops != &serial_ops)
+ return 0;
+
+ switch(async_type(ov))
+ {
+ case ASYNC_TYPE_READ:
+ timeout = serial->readconst + serial->readmult*async_count(ov);
+ async_add_timeout(ov, timeout);
+ async_set_eventmask(ov,EV_RXCHAR);
+ break;
+ case ASYNC_TYPE_WRITE:
+ timeout = serial->writeconst + serial->writemult*async_count(ov);
+ async_add_timeout(ov, timeout);
+ async_set_eventmask(ov,EV_TXEMPTY);
+ break;
+ case ASYNC_TYPE_WAIT:
+ async_set_eventmask(ov,serial->eventmask);
+ break;
+ }
+
+ return 1;
+}
+
+int serial_async_get_poll_events( struct async *ov )
+{
+ int events=0,mask;
+
+ switch(async_type(ov))
+ {
+ case ASYNC_TYPE_READ:
+ events |= POLLIN;
+ break;
+ case ASYNC_TYPE_WRITE:
+ events |= POLLOUT;
+ break;
+ case ASYNC_TYPE_WAIT:
+ /*
+ * FIXME: here is the spot to implement other WaitCommEvent flags
+ */
+ mask = async_get_eventmask(ov);
+ if(mask&EV_RXCHAR)
+ events |= POLLIN;
+ if(mask&EV_TXEMPTY)
+ events |= POLLOUT;
+ break;
+ }
+ return events;
+}
+
+/* receive a select event, and output a windows event */
+int serial_async_poll_event(struct object *obj, int event)
+{
+ int r=0;
+
+ /*
+ * FIXME: here is the spot to implement other WaitCommEvent flags
+ */
+ if(event & POLLIN)
+ r |= EV_RXCHAR;
+ if(event & POLLOUT)
+ r |= EV_TXEMPTY;
+
+ return r;
+}
+
/* create a serial */
DECL_HANDLER(create_serial)
{
diff --git a/server/trace.c b/server/trace.c
index 4ac36ea..c5ff2ea 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1455,6 +1455,27 @@
fprintf( stderr, " commerror=%08x", req->commerror );
}
+static void dump_create_async_request( const struct create_async_request *req )
+{
+ fprintf( stderr, " file_handle=%d,", req->file_handle );
+ fprintf( stderr, " overlapped=%p,", req->overlapped );
+ fprintf( stderr, " buffer=%p,", req->buffer );
+ fprintf( stderr, " count=%d,", req->count );
+ fprintf( stderr, " func=%p,", req->func );
+ fprintf( stderr, " type=%d", req->type );
+}
+
+static void dump_create_async_reply( const struct create_async_request *req )
+{
+ fprintf( stderr, " ov_handle=%d", req->ov_handle );
+}
+
+static void dump_async_result_request( const struct async_result_request *req )
+{
+ fprintf( stderr, " ov_handle=%d,", req->ov_handle );
+ fprintf( stderr, " result=%d", req->result );
+}
+
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_new_process_request,
(dump_func)dump_wait_process_request,
@@ -1564,6 +1585,8 @@
(dump_func)dump_create_serial_request,
(dump_func)dump_get_serial_info_request,
(dump_func)dump_set_serial_info_request,
+ (dump_func)dump_create_async_request,
+ (dump_func)dump_async_result_request,
};
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -1675,6 +1698,8 @@
(dump_func)dump_create_serial_reply,
(dump_func)dump_get_serial_info_reply,
(dump_func)0,
+ (dump_func)dump_create_async_reply,
+ (dump_func)0,
};
static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -1786,6 +1811,8 @@
"create_serial",
"get_serial_info",
"set_serial_info",
+ "create_async",
+ "async_result",
};
/* ### make_requests end ### */