1 /* asyn_special(), asyn_result() Author: Kees J. Bot 2 * 8 Jul 1997 3 */ 4 #include "asyn.h" 5 #include <signal.h> 6 7 /* Saved signal mask between asyn_special() and asyn_result(). */ 8 static sigset_t mask; 9 10 int asyn_special(asynchio_t *asyn, int fd, int op) 11 /* Wait for an operation. This is an odd one out compared to asyn_read() 12 * and asyn_write(). It does not do an operation itself, but together with 13 * asyn_result() it is a set of brackets around a system call xxx that has 14 * no asyn_xxx() for itself. It can be used to build an asyn_accept() or 15 * asyn_connect() for instance. (Minix-vmd has asyn_ioctl() instead, 16 * which is used for any other event like TCP/IP listen/connect. BSD has 17 * a myriad of calls that can't be given an asyn_xxx() counterpart each.) 18 * Asyn_special() returns -1 for "forget it", 0 for "try it", and 1 for 19 * "very first call, maybe you should try it once, maybe not". Errno is 20 * set to EAGAIN if the result is -1 or 1. After trying the system call 21 * make sure errno equals EAGAIN if the call is still in progress and call 22 * asyn_result with the result of the system call. Asyn_result() must be 23 * called if asyn_special() returns 0 or 1. 24 * 25 * Example use: 26 * 27 * int asyn_accept(asynchio_t *asyn, int s, struct sockaddr *addr, int *addrlen) 28 * { 29 * int r; 30 * if ((r= asyn_special(asyn, fd, SEL_READ)) < 0) return -1; 31 * r= r == 0 ? accept(fd, addr, addrlen) : -1; 32 * return asyn_result(asyn, fd, SEL_READ, r); 33 * } 34 * 35 * int asyn_connect(asynchio_t *asyn, int s, struct sockaddr *name, int namelen) 36 * { 37 * int r; 38 * if ((r= asyn_special(asyn, fd, SEL_WRITE)) < 0) return -1; 39 * if (r == 1 && (r= connect(fd, name, namelen)) < 0) { 40 * if (errno == EINPROGRESS) errno= EAGAIN; 41 * } 42 * return asyn_result(asyn, fd, SEL_WRITE, r); 43 * } 44 */ 45 { 46 asynfd_t *afd; 47 int seen; 48 49 asyn->asyn_more++; 50 51 if ((unsigned) fd >= FD_SETSIZE) { errno= EBADF; return -1; } 52 afd= &asyn->asyn_afd[fd]; 53 54 /* If this is the first async call on this filedescriptor then 55 * remember its file flags. 56 */ 57 if (!(seen= afd->afd_seen)) { 58 if ((afd->afd_flags= fcntl(fd, F_GETFL)) < 0) return -1; 59 afd->afd_seen= 1; 60 } 61 62 /* Try to read if I/O is pending. */ 63 if (!seen || afd->afd_state[op] == PENDING) { 64 sigemptyset(&mask); 65 if (sigprocmask(SIG_SETMASK, &mask, &mask) < 0) return -1; 66 (void) fcntl(fd, F_SETFL, afd->afd_flags | O_NONBLOCK); 67 68 /* Let the caller try the system call. */ 69 errno= EAGAIN; 70 return seen ? 0 : 1; 71 } 72 73 /* Record this read as "waiting". */ 74 afd->afd_state[op]= WAITING; 75 FD_SET(fd, &asyn->asyn_fdset[op]); 76 errno= EAGAIN; 77 asyn->asyn_more--; 78 return -1; 79 } 80 81 int asyn_result(asynchio_t *asyn, int fd, int op, int result) 82 /* The caller has tried the system call with the given result. Finish up. */ 83 { 84 int err; 85 asynfd_t *afd= &asyn->asyn_afd[fd]; 86 87 err= errno; 88 89 (void) fcntl(fd, F_SETFL, afd->afd_flags); 90 (void) sigprocmask(SIG_SETMASK, &mask, nil); 91 92 errno= err; 93 if (result != -1 || errno != EAGAIN) { 94 afd->afd_state[op]= IDLE; 95 return result; 96 } 97 98 /* Record this operation as "waiting". */ 99 afd->afd_state[op]= WAITING; 100 FD_SET(fd, &asyn->asyn_fdset[op]); 101 errno= EAGAIN; 102 asyn->asyn_more--; 103 return -1; 104 } 105