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
);