- created server object for handling async i/o
[wine] / server / async.c
1 /*
2  * Server-side support for async i/o operations
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  * Copyright (C) 2000 Mike McCormack
6  *
7  * TODO:
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)
11  *
12  */
13
14 #include "config.h"
15
16 #include <assert.h>
17 #include <fcntl.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 #ifdef HAVE_SYS_ERRNO_H
23 #include <sys/errno.h>
24 #endif
25 #include <sys/stat.h>
26 #include <sys/time.h>
27 #include <sys/types.h>
28 #include <time.h>
29 #include <unistd.h>
30 #include <utime.h>
31 #include <termios.h>
32 #include <sys/ioctl.h>
33
34 #include "winerror.h"
35 #include "winbase.h"
36
37 #include "handle.h"
38 #include "thread.h"
39 #include "request.h"
40
41 struct async 
42 {
43     struct object           obj;
44     void                   *client_overlapped;
45     int                     type;
46     int                     result;
47     int                     count;
48     int                     eventmask;
49     struct async           *next;
50     struct timeout_user    *timeout;
51     struct wait_queue_entry wait;
52     void                   *buffer;
53     void                   *func;
54     struct thread          *thread;
55     struct object          *file;
56 };
57
58 static void async_dump( struct object *obj, int verbose );
59 static void async_destroy( struct object *obj );
60 static int async_get_poll_events( struct object *obj );
61 static int async_get_read_fd( struct object *obj );
62 static int async_get_write_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
66 static const struct object_ops async_ops =
67 {
68     sizeof(struct async),         /* size */
69     async_dump,                   /* dump */
70     default_poll_add_queue,       /* add_queue */
71     default_poll_remove_queue,    /* remove_queue */
72     default_poll_signaled,        /* signaled */
73     no_satisfied,                 /* satisfied */
74     async_get_poll_events,        /* get_poll_events */
75     async_poll_event,             /* poll_event */
76     async_get_read_fd,            /* get_read_fd */
77     async_get_write_fd,           /* get_write_fd */
78     no_flush,                     /* flush */
79     async_get_info,               /* get_file_info */
80     async_destroy                 /* destroy */
81 };
82
83 static void async_dump( struct object *obj, int verbose )
84 {
85     struct async *ov = (struct async *)obj;
86
87     assert( obj->ops == &async_ops );
88
89     fprintf( stderr, "async: overlapped %p %s\n", 
90                  ov->client_overlapped, ov->timeout?"with timeout":"");
91 }
92
93 /* same as file_destroy, but don't delete comm ports */
94 static void async_destroy( struct object *obj )
95 {
96     struct async *ov = (struct async *)obj;
97     assert( obj->ops == &async_ops );
98
99     if(ov->timeout)
100         remove_timeout_user(ov->timeout);
101     ov->timeout = NULL;
102 }
103
104 struct async *get_async_obj( struct process *process, int handle, unsigned int access )
105 {
106     return (struct async *)get_handle_obj( process, handle, access, &async_ops );
107 }
108
109 static int async_get_poll_events( struct object *obj )
110 {
111     struct async *ov = (struct async *)obj;
112     assert( obj->ops == &async_ops );
113
114     /* FIXME: this should be a function pointer */
115     return serial_async_get_poll_events(ov);
116 }
117
118 static int async_get_read_fd( struct object *obj )
119 {
120     struct async *async = (struct async *)obj;
121     assert( obj->ops == &async_ops );
122     return dup( async->obj.fd );
123 }
124
125 static int async_get_write_fd( struct object *obj )
126 {
127     struct async *async = (struct async *)obj;
128     assert( obj->ops == &async_ops );
129     return dup( async->obj.fd );
130 }
131
132 static int async_get_info( struct object *obj, struct get_file_info_request *req ) {
133     assert( obj->ops == &async_ops );
134     req->type        = FILE_TYPE_CHAR;
135     req->attr        = 0;
136     req->access_time = 0;
137     req->write_time  = 0;
138     req->size_high   = 0;
139     req->size_low    = 0;
140     req->links       = 0;
141     req->index_high  = 0;
142     req->index_low   = 0;
143     req->serial      = 0;
144     return 1;
145 }
146
147 /* data access functions */
148 int async_type(struct async *ov)
149 {
150     return ov->type;
151 }
152
153 int async_count(struct async *ov)
154 {
155     return ov->count;
156 }
157
158 int async_get_eventmask(struct async *ov)
159 {
160     return ov->eventmask;
161 }
162
163 int async_set_eventmask(struct async *ov, int eventmask)
164 {
165     return ov->eventmask = eventmask;
166 }
167
168 DECL_HANDLER(create_async)
169 {
170     struct object *obj;
171     struct async *ov = NULL;
172     int fd;
173
174     req->ov_handle = -1;
175     if (!(obj = get_handle_obj( current->process, req->file_handle, 0, NULL)) )
176         return;
177
178     fd = dup(obj->fd);
179     if(fd<0)
180     {
181         release_object(obj);
182         set_error(STATUS_UNSUCCESSFUL);
183         return;
184     }
185
186     if(0>fcntl(fd, F_SETFL, O_NONBLOCK))
187     {
188         release_object(obj);
189         set_error(STATUS_UNSUCCESSFUL);
190         return;
191     }
192
193     ov = alloc_object (&async_ops, fd);
194     if(!ov)
195     {
196         release_object(obj);
197         set_error(STATUS_UNSUCCESSFUL);
198         return;
199     }
200
201     ov->client_overlapped = req->overlapped;
202     ov->next    = NULL;
203     ov->timeout = NULL;
204     ov->type    = req->type;
205     ov->thread  = current;
206     ov->func    = req->func;
207     ov->file    = obj;
208     ov->buffer  = req->buffer;
209     ov->count   = req->count;
210
211     /* FIXME: this should be a function pointer */
212     serial_async_setup(obj,ov);
213
214     ov->obj.ops->add_queue(&ov->obj,&ov->wait);
215
216     req->ov_handle = alloc_handle( current->process, ov, GENERIC_READ|GENERIC_WRITE, 0 );
217
218     release_object(obj);
219 }
220
221 /* handler for async poll() events */
222 static void async_poll_event( struct object *obj, int event )
223 {
224     struct async *ov = (struct async *) obj;
225  
226     /* queue an APC in the client thread to do our dirty work */
227     ov->obj.ops->remove_queue(&ov->obj,&ov->wait);
228
229     /* FIXME: this should be a function pointer */
230     event = serial_async_poll_event(obj,event);
231
232     thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 3,
233                      ov->client_overlapped, ov->buffer, event);
234
235
236 /* handler for async i/o timeouts */
237 static void overlapped_timeout (void *private)
238 {
239     struct async *ov = (struct async *) private;
240  
241     ov->obj.ops->remove_queue(&ov->obj,&ov->wait);
242  
243     thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 3,
244                      ov->client_overlapped,ov->buffer, 0);
245 }
246
247 void async_add_timeout(struct async *ov, int timeout)
248 {
249     struct timeval tv;
250
251     gettimeofday(&tv,0);
252     add_timeout(&tv,timeout);
253     ov->timeout = add_timeout_user(&tv, overlapped_timeout, ov);
254 }
255
256 DECL_HANDLER(async_result)
257 {
258     struct async *ov;
259
260     if ((ov = get_async_obj( current->process, req->ov_handle, 0 )))
261     {
262         ov->result = req->result;
263         if(ov->result == STATUS_PENDING)
264         {
265             ov->obj.ops->add_queue(&ov->obj,&ov->wait);
266         }
267         release_object( ov );
268     }
269 }
270