Calculate the timeout time once when the async is created.
[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 timeval          tv;
51     struct timeout_user    *timeout;
52     struct wait_queue_entry wait;
53     void                   *buffer;
54     void                   *func;
55     struct thread          *thread;
56     struct object          *file;
57 };
58
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);
66
67 static const struct object_ops async_ops =
68 {
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 */
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     {
101         remove_timeout_user(ov->timeout);
102         ov->timeout = NULL;
103     }
104 }
105
106 struct async *get_async_obj( struct process *process, handle_t handle, unsigned int access )
107 {
108     return (struct async *)get_handle_obj( process, handle, access, &async_ops );
109 }
110
111 static int async_get_poll_events( struct object *obj )
112 {
113     struct async *ov = (struct async *)obj;
114     assert( obj->ops == &async_ops );
115
116     /* FIXME: this should be a function pointer */
117     return serial_async_get_poll_events(ov);
118 }
119
120 static int async_get_fd( struct object *obj )
121 {
122     struct async *async = (struct async *)obj;
123     assert( obj->ops == &async_ops );
124     return async->obj.fd;
125 }
126
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;
130     req->attr        = 0;
131     req->access_time = 0;
132     req->write_time  = 0;
133     req->size_high   = 0;
134     req->size_low    = 0;
135     req->links       = 0;
136     req->index_high  = 0;
137     req->index_low   = 0;
138     req->serial      = 0;
139     return 1;
140 }
141
142 /* data access functions */
143 int async_type(struct async *ov)
144 {
145     return ov->type;
146 }
147
148 int async_count(struct async *ov)
149 {
150     return ov->count;
151 }
152
153 int async_get_eventmask(struct async *ov)
154 {
155     return ov->eventmask;
156 }
157
158 int async_set_eventmask(struct async *ov, int eventmask)
159 {
160     return ov->eventmask = eventmask;
161 }
162
163 DECL_HANDLER(create_async)
164 {
165     struct object *obj;
166     struct async *ov = NULL;
167     int fd;
168
169     req->ov_handle = 0;
170     if (!(obj = get_handle_obj( current->process, req->file_handle, 0, NULL)) )
171         return;
172
173     fd = dup(obj->fd);
174     if(fd<0)
175     {
176         release_object(obj);
177         set_error(STATUS_UNSUCCESSFUL);
178         return;
179     }
180
181     if(0>fcntl(fd, F_SETFL, O_NONBLOCK))
182     {
183         release_object(obj);
184         set_error(STATUS_UNSUCCESSFUL);
185         return;
186     }
187
188     ov = alloc_object (&async_ops, fd);
189     if(!ov)
190     {
191         release_object(obj);
192         set_error(STATUS_UNSUCCESSFUL);
193         return;
194     }
195
196     ov->client_overlapped = req->overlapped;
197     ov->next    = NULL;
198     ov->timeout = NULL;
199     ov->type    = req->type;
200     ov->thread  = current;
201     ov->func    = req->func;
202     ov->file    = obj;
203     ov->buffer  = req->buffer;
204     ov->count   = req->count;
205     ov->tv.tv_sec = 0;
206     ov->tv.tv_usec = 0;
207
208     /* FIXME: this should be a function pointer */
209     serial_async_setup(obj,ov);
210
211     if( ov->tv.tv_sec || ov->tv.tv_usec )
212     {
213         ov->timeout = add_timeout_user(&ov->tv, overlapped_timeout, ov);
214     }
215
216     ov->obj.ops->add_queue(&ov->obj,&ov->wait);
217
218     req->ov_handle = alloc_handle( current->process, ov, GENERIC_READ|GENERIC_WRITE, 0 );
219
220     release_object(obj);
221 }
222
223 /* handler for async poll() events */
224 static void async_poll_event( struct object *obj, int event )
225 {
226     struct async *ov = (struct async *) obj;
227
228     /* queue an APC in the client thread to do our dirty work */
229     ov->obj.ops->remove_queue(&ov->obj,&ov->wait);
230     if(ov->timeout)
231     {
232         remove_timeout_user(ov->timeout);
233         ov->timeout = NULL;
234     }
235
236     /* FIXME: this should be a function pointer */
237     event = serial_async_poll_event(obj,event);
238
239     thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 1, 3,
240                      ov->client_overlapped, ov->buffer, event);
241 }
242
243 /* handler for async i/o timeouts */
244 static void overlapped_timeout (void *private)
245 {
246     struct async *ov = (struct async *) private;
247
248     ov->obj.ops->remove_queue(&ov->obj,&ov->wait);
249     ov->timeout = NULL;
250
251     thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 1, 3,
252                      ov->client_overlapped,ov->buffer, 0);
253 }
254
255 void async_add_timeout(struct async *ov, int timeout)
256 {
257     if(timeout)
258     {
259         gettimeofday(&ov->tv,0);
260         add_timeout(&ov->tv,timeout);
261     }
262 }
263
264 DECL_HANDLER(async_result)
265 {
266     struct async *ov;
267
268     if ((ov = get_async_obj( current->process, req->ov_handle, 0 )))
269     {
270         ov->result = req->result;
271         if(ov->result == STATUS_PENDING)
272         {
273             ov->obj.ops->add_queue(&ov->obj,&ov->wait);
274             if( (ov->tv.tv_sec || ov->tv.tv_usec) && !ov->timeout)
275             {
276                 ov->timeout = add_timeout_user(&ov->tv, overlapped_timeout, ov);
277             }
278         }
279         release_object( ov );
280     }
281 }
282