Added a typedef for __int64 which is a builtin Visual C++ type
[wine/multimedia.git] / files / async.c
blob7f1c69fec03ca48c726ff161234fd0710888b4f6
1 /*
2 * Generic async UNIX file IO handling
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.
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.)
16 * To make this a bit better, we would need an additional thread doing select()
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
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"
44 typedef struct _async_fd {
45 int unixfd;
46 void (*handler)(int fd,void *private);
47 void *private;
48 } ASYNC_FD;
50 static ASYNC_FD *asyncfds = NULL;
51 static int nrofasyncfds = 0;
53 /***************************************************************************
54 * ASYNC_sigio [internal]
56 * Signal handler for asynchronous IO.
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.
62 HANDLER_DEF(ASYNC_sigio) {
63 struct timeval timeout;
64 fd_set rset,wset;
65 int i,maxfd=0;
67 HANDLER_INIT();
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;
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))
89 asyncfds[i].handler(asyncfds[i].unixfd,asyncfds[i].private);
92 /***************************************************************************
93 * ASYNC_MakeFDAsync [internal]
95 * Makes the passed filedescriptor async (or not) depending on flag.
97 static BOOL32 ASYNC_MakeFDAsync(int unixfd,int async) {
98 int flags;
100 #if !defined(FASYNC) && defined(FIOASYNC)
101 #define FASYNC FIOASYNC
102 #endif
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;
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;
121 return TRUE;
122 #else
123 return FALSE;
124 #endif
127 /***************************************************************************
128 * ASYNC_RegisterFD [internal]
130 * Register a UNIX filedescriptor with handler and private data pointer.
131 * this function is _NOT_ safe to be called from a signal handler.
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)
137 void ASYNC_RegisterFD(int unixfd,void (*handler)(int fd,void *private),void *private) {
138 int i;
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;
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++;
161 asyncfds[i].unixfd = unixfd;
162 asyncfds[i].handler = handler;
163 asyncfds[i].private = private;
164 ASYNC_MakeFDAsync(unixfd,1);
165 SIGNAL_MaskAsyncEvents( FALSE );
168 /***************************************************************************
169 * ASYNC_UnregisterFD [internal]
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.
174 void ASYNC_UnregisterFD(int unixfd,void (*handler)(int fd,void *private)) {
175 int i;
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;