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;