1 /* asyn_wait() - wait for asynch operations Author: Kees J. Bot 2 * 7 Jul 1997 3 */ 4 5 #include "asyn.h" 6 #include <time.h> 7 #ifdef DEBUG 8 #include <stdio.h> 9 #endif 10 11 #define TBOUND_MIN 1 12 #define TBOUND_MAX 16 13 14 int asyn_wait(asynchio_t *asyn, int flags, struct timeval *to) 15 /* Wait for one or more nonblocking operations to return a result. */ 16 { 17 int r; 18 static struct timeval zero_time; 19 struct timeval t; 20 static time_t tbound= TBOUND_MIN; 21 22 /* Are there more things to do before we can block? */ 23 if (asyn->asyn_more > 0) { asyn->asyn_more= 0; return 0; } 24 25 if (flags & ASYN_NONBLOCK) { 26 /* Don't block by using a zero second timeout. */ 27 to= &zero_time; 28 } else 29 if (to != nil) { 30 /* asyn_wait() uses an absolute time. */ 31 if (to->tv_usec >= 1000000L) { 32 to->tv_sec+= to->tv_usec / 1000000L; 33 to->tv_usec%= 1000000L; 34 } 35 (void) gettimeofday(&t, nil); 36 if (t.tv_sec > to->tv_sec || (t.tv_sec == to->tv_sec 37 && t.tv_usec >= to->tv_usec)) { 38 to= &zero_time; 39 } else { 40 t.tv_sec= to->tv_sec - t.tv_sec; 41 t.tv_usec= to->tv_usec - t.tv_usec; 42 if (t.tv_usec < 0) { 43 t.tv_sec--; 44 t.tv_usec+= 1000000L; 45 } 46 to= &t; 47 } 48 49 /* Don't sleep too long, we don't trust select(). */ 50 if (to->tv_sec > tbound) goto bound; 51 } else { 52 bound: 53 /* No timeout? Don't hang in (buggy?) select() forever. */ 54 to= &t; 55 t.tv_sec= tbound; 56 t.tv_usec= 0; 57 } 58 59 #ifdef DEBUG 60 { 61 int op; 62 63 fprintf(stderr, "select: "); 64 for (op= 0; op < SEL_NR; op++) { 65 fd_set *fdsetp= &asyn->asyn_fdset[op]; 66 int fd; 67 68 for (fd= 0; fd < FD_SETSIZE; fd++) { 69 if (FD_ISSET(fd, fdsetp)) { 70 asyn->asyn_afd[fd].afd_state[op]= 71 PENDING; 72 fprintf(stderr, "%d%c", fd, "rwx"[op]); 73 } 74 } 75 } 76 fflush(stderr); 77 } 78 #endif 79 r= select(FD_SETSIZE, &asyn->asyn_fdset[SEL_READ], 80 &asyn->asyn_fdset[SEL_WRITE], 81 &asyn->asyn_fdset[SEL_EXCEPT], to); 82 #ifdef DEBUG 83 fprintf(stderr, " (%d) ", r); 84 #endif 85 if (r > 0) { 86 /* An event occurred on one or more file descriptors. */ 87 int op; 88 89 for (op= 0; op < SEL_NR; op++) { 90 fd_set *fdsetp= &asyn->asyn_fdset[op]; 91 int fd; 92 93 for (fd= 0; fd < FD_SETSIZE; fd++) { 94 if (FD_ISSET(fd, fdsetp)) { 95 asyn->asyn_afd[fd].afd_state[op]= 96 PENDING; 97 #ifdef DEBUG 98 fprintf(stderr, "%d%c", fd, "rwx"[op]); 99 #endif 100 } 101 } 102 } 103 tbound= TBOUND_MIN; 104 } else 105 if (r == 0) { 106 /* If nothing happened then let the time boundary slip a bit. */ 107 if (tbound < TBOUND_MAX) tbound <<= 1; 108 } 109 #ifdef DEBUG 110 fputc('\n', stderr); 111 #endif 112 113 FD_ZERO(&asyn->asyn_fdset[SEL_READ]); 114 FD_ZERO(&asyn->asyn_fdset[SEL_WRITE]); 115 FD_ZERO(&asyn->asyn_fdset[SEL_EXCEPT]); 116 117 return r == 0 ? (errno= EINTR, -1) : r; 118 } 119