- add -lossaudio if needed, and a check for <soundcard.h>, to configure.in
[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 <unistd.h>
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #ifdef HAVE_SYS_PARAM_H
27 # include <sys/param.h>
28 #endif
29 #ifdef HAVE_SYS_FILIO_H
30 # include <sys/filio.h>
31 #endif
32 #ifdef __svr4__
33 # include <sys/file.h>
34 #endif
35
36 #include "xmalloc.h"
37 #include "wintypes.h"
38 #include "miscemu.h"
39 #include "selectors.h"
40 #include "sig_context.h"
41 #include "async.h"
42 #include "debug.h"
43
44 typedef struct _async_fd {
45         int     unixfd;
46         void    (*handler)(int fd,void *private);
47         void    *private;
48 } ASYNC_FD;
49
50 static ASYNC_FD *asyncfds = NULL;
51 static int       nrofasyncfds = 0;
52
53 /***************************************************************************
54  *              ASYNC_sigio                             [internal]
55  * 
56  * Signal handler for asynchronous IO.
57  *
58  * Note: This handler and the function it calls may not block. Neither they
59  * are allowed to use blocking IO (write/read). No memory management.
60  * No possible blocking synchronization of any kind.
61  */
62 HANDLER_DEF(ASYNC_sigio) {
63         struct timeval  timeout;
64         fd_set  rset,wset;
65         int     i,maxfd=0;
66
67         HANDLER_INIT();
68
69         if (!nrofasyncfds) 
70                 return;
71         FD_ZERO(&rset);
72         FD_ZERO(&wset);
73         for (i=nrofasyncfds;i--;) {
74                 if (asyncfds[i].unixfd == -1)
75                         continue;
76                 FD_SET(asyncfds[i].unixfd,&rset);
77                 FD_SET(asyncfds[i].unixfd,&wset);
78                 if (maxfd<asyncfds[i].unixfd)
79                         maxfd=asyncfds[i].unixfd;
80         }
81         /* select() with timeout values set to 0 is nonblocking. */
82         memset(&timeout,0,sizeof(timeout));
83         if (select(maxfd+1,&rset,&wset,NULL,&timeout)<=0)
84                 return; /* Can't be. hmm */
85         for (i=nrofasyncfds;i--;)
86                 if (    (FD_ISSET(asyncfds[i].unixfd,&rset)) ||
87                         (FD_ISSET(asyncfds[i].unixfd,&wset))
88                 )
89                         asyncfds[i].handler(asyncfds[i].unixfd,asyncfds[i].private);
90 }
91
92 /***************************************************************************
93  *              ASYNC_MakeFDAsync                       [internal]
94  *
95  * Makes the passed filedescriptor async (or not) depending on flag.
96  */
97 static BOOL32 ASYNC_MakeFDAsync(int unixfd,int async) {
98     int flags;
99
100 #if !defined(FASYNC) && defined(FIOASYNC)
101 #define FASYNC FIOASYNC
102 #endif
103
104 #ifdef F_SETOWN
105     if (-1==fcntl(unixfd,F_SETOWN,getpid()))
106         perror("fcntl F_SETOWN <pid>");
107 #endif
108 #ifdef FASYNC
109     if (-1==fcntl(unixfd,F_GETFL,&flags)) {
110         perror("fcntl F_GETFL");
111         return FALSE;
112     }
113     if (async)
114         flags|=FASYNC;
115     else
116         flags&=~FASYNC;
117     if (-1==fcntl(unixfd,F_SETFL,&flags)) {
118         perror("fcntl F_SETFL FASYNC");
119         return FALSE;
120     }
121     return TRUE;
122 #else
123     return FALSE;
124 #endif
125 }
126
127 /***************************************************************************
128  *              ASYNC_RegisterFD                        [internal]
129  *
130  * Register a UNIX filedescriptor with handler and private data pointer. 
131  * this function is _NOT_ safe to be called from a signal handler.
132  *
133  * Additional Constraint:  The handler passed to this function _MUST_ adhere
134  * to the same signalsafeness as ASYNC_sigio itself. (nonblocking, no thread/
135  * signal unsafe operations, no blocking synchronization)
136  */
137 void ASYNC_RegisterFD(int unixfd,void (*handler)(int fd,void *private),void *private) {
138     int i;
139
140     SIGNAL_MaskAsyncEvents( TRUE );
141     for (i=0;i<nrofasyncfds;i++) {
142         if (asyncfds[i].unixfd==unixfd) {
143             /* Might be a leftover entry. Make fd async anyway... */
144             if (asyncfds[i].handler==handler) {
145                 ASYNC_MakeFDAsync(unixfd,1);
146                 SIGNAL_MaskAsyncEvents( FALSE );
147                 return;
148             }
149         }
150     }
151    for (i=0;i<nrofasyncfds;i++)
152         if (asyncfds[i].unixfd == -1)
153                 break;
154    if (i==nrofasyncfds) {
155        if (nrofasyncfds)
156            asyncfds=(ASYNC_FD*)xrealloc(asyncfds,sizeof(ASYNC_FD)*(nrofasyncfds+1));
157        else
158            asyncfds=(ASYNC_FD*)xmalloc(sizeof(ASYNC_FD)*1);
159        nrofasyncfds++;
160    }
161    asyncfds[i].unixfd   = unixfd;
162    asyncfds[i].handler  = handler;
163    asyncfds[i].private  = private;
164    ASYNC_MakeFDAsync(unixfd,1);
165    SIGNAL_MaskAsyncEvents( FALSE );
166 }
167
168 /***************************************************************************
169  *              ASYNC_UnregisterFD                      [internal]
170  *
171  * Unregister a UNIX filedescriptor with handler. This function is basically
172  * signal safe, but try to not call it in the signal handler anyway.
173  */
174 void ASYNC_UnregisterFD(int unixfd,void (*handler)(int fd,void *private)) {
175     int i;
176
177     for (i=nrofasyncfds;i--;)
178         if ((asyncfds[i].unixfd==unixfd)||(asyncfds[i].handler==handler))
179             break;
180     if (i==nrofasyncfds)
181         return;
182     asyncfds[i].unixfd  = -1;
183     asyncfds[i].handler = NULL;
184     asyncfds[i].private = NULL;
185     return;
186 }