Avoid dup'ing file descriptors when not necessary.
[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_fd( struct object *obj );
62 static int async_get_info( struct object *obj, struct get_file_info_request *req );
63 static void async_poll_event( struct object *obj, int event );
64
65 static const struct object_ops async_ops =
66 {
67     sizeof(struct async),         /* size */
68     async_dump,                   /* dump */
69     default_poll_add_queue,       /* add_queue */
70     default_poll_remove_queue,    /* remove_queue */
71     default_poll_signaled,        /* signaled */
72     no_satisfied,                 /* satisfied */
73     async_get_poll_events,        /* get_poll_events */
74     async_poll_event,             /* poll_event */
75     async_get_fd,                 /* get_fd */
76     no_flush,                     /* flush */
77     async_get_info,               /* get_file_info */
78     async_destroy                 /* destroy */
79 };
80
81 static void async_dump( struct object *obj, int verbose )
82 {
83     struct async *ov = (struct async *)obj;
84
85     assert( obj->ops == &async_ops );
86
87     fprintf( stderr, "async: overlapped %p %s\n", 
88                  ov->client_overlapped, ov->timeout?"with timeout":"");
89 }
90
91 /* same as file_destroy, but don't delete comm ports */
92 static void async_destroy( struct object *obj )
93 {
94     struct async *ov = (struct async *)obj;
95     assert( obj->ops == &async_ops );
96
97     if(ov->timeout)
98         remove_timeout_user(ov->timeout);
99     ov->timeout = NULL;
100 }
101
102 struct async *get_async_obj( struct process *process, int handle, unsigned int access )
103 {
104     return (struct async *)get_handle_obj( process, handle, access, &async_ops );
105 }
106
107 static int async_get_poll_events( struct object *obj )
108 {
109     struct async *ov = (struct async *)obj;
110     assert( obj->ops == &async_ops );
111
112     /* FIXME: this should be a function pointer */
113     return serial_async_get_poll_events(ov);
114 }
115
116 static int async_get_fd( struct object *obj )
117 {
118     struct async *async = (struct async *)obj;
119     assert( obj->ops == &async_ops );
120     return async->obj.fd;
121 }
122
123 static int async_get_info( struct object *obj, struct get_file_info_request *req ) {
124     assert( obj->ops == &async_ops );
125     req->type        = FILE_TYPE_CHAR;
126     req->attr        = 0;
127     req->access_time = 0;
128     req->write_time  = 0;
129     req->size_high   = 0;
130     req->size_low    = 0;
131     req->links       = 0;
132     req->index_high  = 0;
133     req->index_low   = 0;
134     req->serial      = 0;
135     return 1;
136 }
137
138 /* data access functions */
139 int async_type(struct async *ov)
140 {
141     return ov->type;
142 }
143
144 int async_count(struct async *ov)
145 {
146     return ov->count;
147 }
148
149 int async_get_eventmask(struct async *ov)
150 {
151     return ov->eventmask;
152 }
153
154 int async_set_eventmask(struct async *ov, int eventmask)
155 {
156     return ov->eventmask = eventmask;
157 }
158
159 DECL_HANDLER(create_async)
160 {
161     struct object *obj;
162     struct async *ov = NULL;
163     int fd;
164
165     req->ov_handle = -1;
166     if (!(obj = get_handle_obj( current->process, req->file_handle, 0, NULL)) )
167         return;
168
169     fd = dup(obj->fd);
170     if(fd<0)
171     {
172         release_object(obj);
173         set_error(STATUS_UNSUCCESSFUL);
174         return;
175     }
176
177     if(0>fcntl(fd, F_SETFL, O_NONBLOCK))
178     {
179         release_object(obj);
180         set_error(STATUS_UNSUCCESSFUL);
181         return;
182     }
183
184     ov = alloc_object (&async_ops, fd);
185     if(!ov)
186     {
187         release_object(obj);
188         set_error(STATUS_UNSUCCESSFUL);
189         return;
190     }
191
192     ov->client_overlapped = req->overlapped;
193     ov->next    = NULL;
194     ov->timeout = NULL;
195     ov->type    = req->type;
196     ov->thread  = current;
197     ov->func    = req->func;
198     ov->file    = obj;
199     ov->buffer  = req->buffer;
200     ov->count   = req->count;
201
202     /* FIXME: this should be a function pointer */
203     serial_async_setup(obj,ov);
204
205     ov->obj.ops->add_queue(&ov->obj,&ov->wait);
206
207     req->ov_handle = alloc_handle( current->process, ov, GENERIC_READ|GENERIC_WRITE, 0 );
208
209     release_object(obj);
210 }
211
212 /* handler for async poll() events */
213 static void async_poll_event( struct object *obj, int event )
214 {
215     struct async *ov = (struct async *) obj;
216  
217     /* queue an APC in the client thread to do our dirty work */
218     ov->obj.ops->remove_queue(&ov->obj,&ov->wait);
219
220     /* FIXME: this should be a function pointer */
221     event = serial_async_poll_event(obj,event);
222
223     thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 3,
224                      ov->client_overlapped, ov->buffer, event);
225
226
227 /* handler for async i/o timeouts */
228 static void overlapped_timeout (void *private)
229 {
230     struct async *ov = (struct async *) private;
231  
232     ov->obj.ops->remove_queue(&ov->obj,&ov->wait);
233  
234     thread_queue_apc(ov->thread, NULL, ov->func, APC_ASYNC, 3,
235                      ov->client_overlapped,ov->buffer, 0);
236 }
237
238 void async_add_timeout(struct async *ov, int timeout)
239 {
240     struct timeval tv;
241
242     gettimeofday(&tv,0);
243     add_timeout(&tv,timeout);
244     ov->timeout = add_timeout_user(&tv, overlapped_timeout, ov);
245 }
246
247 DECL_HANDLER(async_result)
248 {
249     struct async *ov;
250
251     if ((ov = get_async_obj( current->process, req->ov_handle, 0 )))
252     {
253         ov->result = req->result;
254         if(ov->result == STATUS_PENDING)
255         {
256             ov->obj.ops->add_queue(&ov->obj,&ov->wait);
257         }
258         release_object( ov );
259     }
260 }
261