Bugfix: cope with quoted arguments for CreateProcess().
[wine/hacks.git] / files / async.c
blob0a7c06c0bc5352b44a2f2029a3b0a225963a28ce
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 <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
37 #include "xmalloc.h"
38 #include "windef.h"
39 #include "miscemu.h"
40 #include "selectors.h"
41 #include "sig_context.h"
42 #include "async.h"
43 #include "debug.h"
45 typedef struct _async_fd {
46 int unixfd;
47 void (*handler)(int fd,void *private);
48 void *private;
49 } ASYNC_FD;
51 static ASYNC_FD *asyncfds = NULL;
52 static int nrofasyncfds = 0;
54 /***************************************************************************
55 * ASYNC_sigio [internal]
57 * Signal handler for asynchronous IO.
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.
63 HANDLER_DEF(ASYNC_sigio) {
64 struct timeval timeout;
65 fd_set rset,wset;
66 int i,maxfd=0;
68 HANDLER_INIT();
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;
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))
90 asyncfds[i].handler(asyncfds[i].unixfd,asyncfds[i].private);
93 /***************************************************************************
94 * ASYNC_MakeFDAsync [internal]
96 * Makes the passed filedescriptor async (or not) depending on flag.
98 static BOOL ASYNC_MakeFDAsync(int unixfd,int async) {
99 int flags;
101 #if !defined(FASYNC) && defined(FIOASYNC)
102 #define FASYNC FIOASYNC
103 #endif
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;
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;
122 return TRUE;
123 #else
124 return FALSE;
125 #endif
128 /***************************************************************************
129 * ASYNC_RegisterFD [internal]
131 * Register a UNIX filedescriptor with handler and private data pointer.
132 * this function is _NOT_ safe to be called from a signal handler.
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)
138 void ASYNC_RegisterFD(int unixfd,void (*handler)(int fd,void *private),void *private) {
139 int i;
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;
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++;
162 asyncfds[i].unixfd = unixfd;
163 asyncfds[i].handler = handler;
164 asyncfds[i].private = private;
165 ASYNC_MakeFDAsync(unixfd,1);
166 SIGNAL_MaskAsyncEvents( FALSE );
169 /***************************************************************************
170 * ASYNC_UnregisterFD [internal]
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.
175 void ASYNC_UnregisterFD(int unixfd,void (*handler)(int fd,void *private)) {
176 int i;
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;