#define _POSIX_C_SOURCE 200112L #include #include #include #include #include #include "cbits.h" #ifndef NDEBUG #include #endif int xselect(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout) { struct timespec remaining; int ret; struct timespec start; struct timespec current; struct timespec stop; if (timeout != NULL) { remaining.tv_sec = timeout->tv_sec; remaining.tv_nsec = timeout->tv_usec*1000; clock_gettime(CLOCK_MONOTONIC, &start); stop.tv_sec = start.tv_sec + timeout->tv_sec; stop.tv_nsec = start.tv_nsec + timeout->tv_usec*1000; } fd_set readfds_orig = *readfds; fd_set writefds_orig = *writefds; fd_set exceptfds_orig = *exceptfds; for (;;) { #ifndef NDEBUG if (timeout != NULL) { printf("C: Remaining time: %ld s, %ld ns\n", remaining.tv_sec, remaining.tv_nsec); printf("C: Will select for %ld s, %ld us\n", timeout->tv_sec, timeout->tv_usec); } else printf("C: Will select forever.\n"); #endif ret = select(nfds, readfds, writefds, exceptfds, timeout); if (ret == -1 && errno == EINTR) { #ifndef NDEBUG printf("C: Was interrupted.\n"); #endif if (timeout != NULL) // Case of finite timeouts. { clock_gettime(CLOCK_MONOTONIC, ¤t); remaining.tv_sec = stop.tv_sec - current.tv_sec; remaining.tv_nsec = stop.tv_nsec - current.tv_nsec; while (remaining.tv_nsec > 1000000000) { remaining.tv_sec++; remaining.tv_nsec -= 1000000000; } while (remaining.tv_nsec < 0) { remaining.tv_sec--; remaining.tv_nsec += 1000000000; } if (remaining.tv_sec < 0) { remaining.tv_sec = 0; remaining.tv_nsec = 0; } #ifndef NDEBUG printf("C: Was interrupted with %ld s, %ld ns remaining\n", remaining.tv_sec, remaining.tv_nsec); #endif // Set up for retry. timeout->tv_sec = remaining.tv_sec; timeout->tv_usec = remaining.tv_nsec/1000; } // Set up for retry (also in infinite case). *readfds = readfds_orig; *writefds = writefds_orig; *exceptfds = exceptfds_orig; #ifndef NDEBUG printf("C: Retrying select.\n"); #endif } else return ret; } return -2; // Cannot happen. }