- 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 ### */