2 * Generic async UNIX file IO handling
4 * Copyright 1996,1997 Alex Korobka
5 * Copyright 1998 Marcus Meissner
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()
22 #include <sys/types.h>
26 #ifdef HAVE_SYS_PARAM_H
27 # include <sys/param.h>
29 #ifdef HAVE_SYS_FILIO_H
30 # include <sys/filio.h>
33 # include <sys/file.h>
39 #include "selectors.h"
40 #include "sig_context.h"
44 typedef struct _async_fd
{
46 void (*handler
)(int fd
,void *private);
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
;
73 for (i
=nrofasyncfds
;i
--;) {
74 if (asyncfds
[i
].unixfd
== -1)
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
) {
100 #if !defined(FASYNC) && defined(FIOASYNC)
101 #define FASYNC FIOASYNC
105 if (-1==fcntl(unixfd
,F_SETOWN
,getpid()))
106 perror("fcntl F_SETOWN <pid>");
109 if (-1==fcntl(unixfd
,F_GETFL
,&flags
)) {
110 perror("fcntl F_GETFL");
117 if (-1==fcntl(unixfd
,F_SETFL
,&flags
)) {
118 perror("fcntl F_SETFL FASYNC");
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) {
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
);
151 for (i
=0;i
<nrofasyncfds
;i
++)
152 if (asyncfds
[i
].unixfd
== -1)
154 if (i
==nrofasyncfds
) {
156 asyncfds
=(ASYNC_FD
*)xrealloc(asyncfds
,sizeof(ASYNC_FD
)*(nrofasyncfds
+1));
158 asyncfds
=(ASYNC_FD
*)xmalloc(sizeof(ASYNC_FD
)*1);
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)) {
177 for (i
=nrofasyncfds
;i
--;)
178 if ((asyncfds
[i
].unixfd
==unixfd
)||(asyncfds
[i
].handler
==handler
))
182 asyncfds
[i
].unixfd
= -1;
183 asyncfds
[i
].handler
= NULL
;
184 asyncfds
[i
].private = NULL
;