Wrong access on server handle was demanded (GENERIC_READ instead of
[wine] / files / async.c
1 /*
2  * Generic async UNIX file IO handling
3  *
4  * Copyright 1996,1997 Alex Korobka
5  * Copyright 1998 Marcus Meissner
6  */
7 /*
8  * This file handles asynchronous signaling for UNIX filedescriptors. 
9  * The passed handler gets called when input arrived for the filedescriptor.
10  * 
11  * This is done either by the kernel or (in the WINSOCK case) by the pipe
12  * handler, since pipes do not support asynchronous signaling.
13  * (Not all possible filedescriptors support async IO. Generic files do not
14  *  for instance, sockets do, ptys don't.)
15  * 
16  * To make this a bit better, we would need an additional thread doing select()
17  */
18
19 #include <assert.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/time.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #ifdef HAVE_SYS_PARAM_H
28 # include <sys/param.h>
29 #endif
30 #ifdef HAVE_SYS_FILIO_H
31 # include <sys/filio.h>
32 #endif
33 #ifdef HAVE_SYS_FILE_H
34 # include <sys/file.h>
35 #endif
36
37 #include "xmalloc.h"
38 #include "wintypes.h"
39 #include "miscemu.h"
40 #include "selectors.h"
41 #include "sig_context.h"
42 #include "async.h"
43 #include "debug.h"
44
45 typedef struct _async_fd {
46         int     unixfd;
47         void    (*handler)(int fd,void *private);
48         void    *private;
49 } ASYNC_FD;
50
51 static ASYNC_FD *asyncfds = NULL;
52 static int       nrofasyncfds = 0;
53
54 /***************************************************************************
55  *              ASYNC_sigio                             [internal]
56  * 
57  * Signal handler for asynchronous IO.
58  *
59  * Note: This handler and the function it calls may not block. Neither they
60  * are allowed to use blocking IO (write/read). No memory management.
61  * No possible blocking synchronization of any kind.
62  */
63 HANDLER_DEF(ASYNC_sigio) {
64         struct timeval  timeout;
65         fd_set  rset,wset;
66         int     i,maxfd=0;
67
68         HANDLER_INIT();
69
70         if (!nrofasyncfds) 
71                 return;
72         FD_ZERO(&rset);
73         FD_ZERO(&wset);
74         for (i=nrofasyncfds;i--;) {
75                 if (asyncfds[i].unixfd == -1)
76                         continue;
77                 FD_SET(asyncfds[i].unixfd,&rset);
78                 FD_SET(asyncfds[i].unixfd,&wset);
79                 if (maxfd<asyncfds[i].unixfd)
80                         maxfd=asyncfds[i].unixfd;
81         }
82         /* select() with timeout values set to 0 is nonblocking. */
83         memset(&timeout,0,sizeof(timeout));
84         if (select(maxfd+1,&rset,&wset,NULL,&timeout)<=0)
85                 return; /* Can't be. hmm */
86         for (i=nrofasyncfds;i--;)
87                 if (    (FD_ISSET(asyncfds[i].unixfd,&rset)) ||
88                         (FD_ISSET(asyncfds[i].unixfd,&wset))
89                 )
90                         asyncfds[i].handler(asyncfds[i].unixfd,asyncfds[i].private);
91 }
92
93 /***************************************************************************
94  *              ASYNC_MakeFDAsync                       [internal]
95  *
96  * Makes the passed filedescriptor async (or not) depending on flag.
97  */
98 static BOOL32 ASYNC_MakeFDAsync(int unixfd,int async) {
99     int flags;
100
101 #if !defined(FASYNC) && defined(FIOASYNC)
102 #define FASYNC FIOASYNC
103 #endif
104
105 #ifdef F_SETOWN
106     if (-1==fcntl(unixfd,F_SETOWN,getpid()))
107         perror("fcntl F_SETOWN <pid>");
108 #endif
109 #ifdef FASYNC
110     if (-1==fcntl(unixfd,F_GETFL,&flags)) {
111         perror("fcntl F_GETFL");
112         return FALSE;
113     }
114     if (async)
115         flags|=FASYNC;
116     else
117         flags&=~FASYNC;
118     if (-1==fcntl(unixfd,F_SETFL,&flags)) {
119         perror("fcntl F_SETFL FASYNC");
120         return FALSE;
121     }
122     return TRUE;
123 #else
124     return FALSE;
125 #endif
126 }
127
128 /***************************************************************************
129  *              ASYNC_RegisterFD                        [internal]
130  *
131  * Register a UNIX filedescriptor with handler and private data pointer. 
132  * this function is _NOT_ safe to be called from a signal handler.
133  *
134  * Additional Constraint:  The handler passed to this function _MUST_ adhere
135  * to the same signalsafeness as ASYNC_sigio itself. (nonblocking, no thread/
136  * signal unsafe operations, no blocking synchronization)
137  */
138 void ASYNC_RegisterFD(int unixfd,void (*handler)(int fd,void *private),void *private) {
139     int i;
140
141     SIGNAL_MaskAsyncEvents( TRUE );
142     for (i=0;i<nrofasyncfds;i++) {
143         if (asyncfds[i].unixfd==unixfd) {
144             /* Might be a leftover entry. Make fd async anyway... */
145             if (asyncfds[i].handler==handler) {
146                 ASYNC_MakeFDAsync(unixfd,1);
147                 SIGNAL_MaskAsyncEvents( FALSE );
148                 return;
149             }
150         }
151     }
152    for (i=0;i<nrofasyncfds;i++)
153         if (asyncfds[i].unixfd == -1)
154                 break;
155    if (i==nrofasyncfds) {
156        if (nrofasyncfds)
157            asyncfds=(ASYNC_FD*)xrealloc(asyncfds,sizeof(ASYNC_FD)*(nrofasyncfds+1));
158        else
159            asyncfds=(ASYNC_FD*)xmalloc(sizeof(ASYNC_FD)*1);
160        nrofasyncfds++;
161    }
162    asyncfds[i].unixfd   = unixfd;
163    asyncfds[i].handler  = handler;
164    asyncfds[i].private  = private;
165    ASYNC_MakeFDAsync(unixfd,1);
166    SIGNAL_MaskAsyncEvents( FALSE );
167 }
168
169 /***************************************************************************
170  *              ASYNC_UnregisterFD                      [internal]
171  *
172  * Unregister a UNIX filedescriptor with handler. This function is basically
173  * signal safe, but try to not call it in the signal handler anyway.
174  */
175 void ASYNC_UnregisterFD(int unixfd,void (*handler)(int fd,void *private)) {
176     int i;
177
178     for (i=nrofasyncfds;i--;)
179         if ((asyncfds[i].unixfd==unixfd)||(asyncfds[i].handler==handler))
180             break;
181     if (i==nrofasyncfds)
182         return;
183     asyncfds[i].unixfd  = -1;
184     asyncfds[i].handler = NULL;
185     asyncfds[i].private = NULL;
186     return;
187 }