2 * Server-side support for async i/o operations
4 * Copyright (C) 1998 Alexandre Julliard
5 * Copyright (C) 2000 Mike McCormack
8 * Fix up WaitCommEvent operations. Currently only EV_RXCHAR is supported.
9 * This may require modifications to the linux kernel to enable select
10 * to wait on Modem Status Register deltas. (delta DCD, CTS, DSR or RING)
22 #ifdef HAVE_SYS_ERRNO_H
23 #include <sys/errno.h>
27 #include <sys/types.h>
32 #include <sys/ioctl.h>
44 void *client_overlapped;
51 struct timeout_user *timeout;
52 struct wait_queue_entry wait;
55 struct thread *thread;
59 static void async_dump( struct object *obj, int verbose );
60 static void async_destroy( struct object *obj );
61 static int async_get_poll_events( struct object *obj );
62 static int async_get_fd( struct object *obj );
63 static int async_get_info( struct object *obj, struct get_file_info_request *req );
64 static void async_poll_event( struct object *obj, int event );
65 static void overlapped_timeout (void *private);
67 static const struct object_ops async_ops =
69 sizeof(struct async), /* size */
70 async_dump, /* dump */
71 default_poll_add_queue, /* add_queue */
72 default_poll_remove_queue, /* remove_queue */
73 default_poll_signaled, /* signaled */
74 no_satisfied, /* satisfied */
75 async_get_poll_events, /* get_poll_events */
76 async_poll_event, /* poll_event */
77 async_get_fd, /* get_fd */
79 async_get_info, /* get_file_info */
80 async_destroy /* destroy */
83 static void async_dump( struct object *obj, int verbose )
85 struct async *ov = (struct async *)obj;
87 assert( obj->ops == &async_ops );
89 fprintf( stderr, "async: overlapped %p %s\n",
90 ov->client_overlapped, ov->timeout?"with timeout":"");
93 /* same as file_destroy, but don't delete comm ports */
94 static void async_destroy( struct object *obj )
96 struct async *ov = (struct async *)obj;
97 assert( obj->ops == &async_ops );
101 remove_timeout_user(ov->timeout);
106 struct async *get_async_obj( struct process *process, handle_t handle, unsigned int access )
108 return (struct async *)get_handle_obj( process, handle, access, &async_ops );
111 static int async_get_poll_events( struct object *obj )
113 struct async *ov = (struct async *)obj;
114 assert( obj->ops == &async_ops );
116 /* FIXME: this should be a function pointer */
117 return serial_async_get_poll_events(ov);
120 static int async_get_fd( struct object *obj )
122 struct async *async = (struct async *)obj;
123 assert( obj->ops == &async_ops );
124 return async->obj.fd;
127 static int async_get_info( struct object *obj, struct get_file_info_request *req ) {
128 assert( obj->ops == &async_ops );
129 req->type = FILE_TYPE_CHAR;
131 req->access_time = 0;
142 /* data access functions */
143 int async_type(struct async *ov)
148 int async_count(struct async *ov)
153 int async_get_eventmask(struct async *ov)
155 return ov->eventmask;
158 int async_set_eventmask(struct async *ov, int eventmask)
160 return ov->eventmask = eventmask;
163 DECL_HANDLER(create_async)
166 struct async *ov = NULL;
170 if (!(obj = get_handle_obj( current->process, req->file_handle, 0, NULL)) )
177 set_error(STATUS_UNSUCCESSFUL);
181 if(0>fcntl(fd, F_SETFL, O_NONBLOCK))
184 set_error(STATUS_UNSUCCESSFUL);
188 ov = alloc_object (&async_ops, fd);
192 set_error(STATUS_UNSUCCESSFUL);
196 ov->client_overlapped = req->overlapped;
199 ov->type = req->type;
200 ov->thread = current;
201 ov->func = req->func;
203 ov->buffer = req->buffer;
204 ov->count = req->count;
208 /* FIXME: this should be a function pointer */
209 serial_async_setup(obj,ov);
211 if( ov->tv.tv_sec || ov->tv.tv_usec )
213 ov->timeout = add_timeout_user(&ov->tv, overlapped_timeout, ov);
216 ov->obj.ops->add_queue(&ov->obj,&ov->wait);
218 req->ov_handle = alloc_handle( current->process, ov, GENERIC_READ|GENERIC_WRITE, 0 );
223 /* handler for async poll() events */
224 static void async_poll_event( struct object *obj, int event )
226 struct async *ov = (struct async *) obj;
228 /* queue an APC in the client thread to do our dirty work */
229 ov->obj.ops->remove_queue(&ov->obj,&ov->wait);
232 remove_timeout_user(ov->timeout);
236 /* FIXME: this should be a function pointer */
237 event = serial_async_poll_event(obj,event);
239 thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 1, 3,
240 ov->client_overlapped, ov->buffer, event);
243 /* handler for async i/o timeouts */
244 static void overlapped_timeout (void *private)
246 struct async *ov = (struct async *) private;
248 ov->obj.ops->remove_queue(&ov->obj,&ov->wait);
251 thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 1, 3,
252 ov->client_overlapped,ov->buffer, 0);
255 void async_add_timeout(struct async *ov, int timeout)
259 gettimeofday(&ov->tv,0);
260 add_timeout(&ov->tv,timeout);
264 DECL_HANDLER(async_result)
268 if ((ov = get_async_obj( current->process, req->ov_handle, 0 )))
270 ov->result = req->result;
271 if(ov->result == STATUS_PENDING)
273 ov->obj.ops->add_queue(&ov->obj,&ov->wait);
274 if( (ov->tv.tv_sec || ov->tv.tv_usec) && !ov->timeout)
276 ov->timeout = add_timeout_user(&ov->tv, overlapped_timeout, ov);
279 release_object( ov );