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()
23 #include <sys/types.h>
27 #ifdef HAVE_SYS_PARAM_H
28 # include <sys/param.h>
30 #ifdef HAVE_SYS_FILIO_H
31 # include <sys/filio.h>
33 #ifdef HAVE_SYS_FILE_H
34 # include <sys/file.h>
40 #include "selectors.h"
41 #include "sig_context.h"
45 typedef struct _async_fd
{
47 void (*handler
)(int fd
,void *private);
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
;
74 for (i
=nrofasyncfds
;i
--;) {
75 if (asyncfds
[i
].unixfd
== -1)
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
) {
101 #if !defined(FASYNC) && defined(FIOASYNC)
102 #define FASYNC FIOASYNC
106 if (-1==fcntl(unixfd
,F_SETOWN
,getpid()))
107 perror("fcntl F_SETOWN <pid>");
110 if (-1==fcntl(unixfd
,F_GETFL
,&flags
)) {
111 perror("fcntl F_GETFL");
118 if (-1==fcntl(unixfd
,F_SETFL
,&flags
)) {
119 perror("fcntl F_SETFL FASYNC");
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) {
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
);
152 for (i
=0;i
<nrofasyncfds
;i
++)
153 if (asyncfds
[i
].unixfd
== -1)
155 if (i
==nrofasyncfds
) {
157 asyncfds
=(ASYNC_FD
*)xrealloc(asyncfds
,sizeof(ASYNC_FD
)*(nrofasyncfds
+1));
159 asyncfds
=(ASYNC_FD
*)xmalloc(sizeof(ASYNC_FD
)*1);
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)) {
178 for (i
=nrofasyncfds
;i
--;)
179 if ((asyncfds
[i
].unixfd
==unixfd
)||(asyncfds
[i
].handler
==handler
))
183 asyncfds
[i
].unixfd
= -1;
184 asyncfds
[i
].handler
= NULL
;
185 asyncfds
[i
].private = NULL
;