* We loop again if _MD_SELECT timed out or got interrupted
* We loop again if select timed out or got interrupted
socket_io_wait( PRInt32 osfd, PRInt32 fd_type, PRIntervalTime timeout ){    PRInt32 rv = -1;    PRThread *me = _PR_MD_CURRENT_THREAD();    PRIntervalTime epoch, now, elapsed, remaining;    PRBool wait_for_remaining;    PRInt32 syserror;#ifdef BSD_SELECT    struct timeval tv;    fd_set rd_wr;#else    int socks[1];    long lTimeout;#endif    switch (timeout) {        case PR_INTERVAL_NO_WAIT:            PR_SetError(PR_IO_TIMEOUT_ERROR, 0);            break;        case PR_INTERVAL_NO_TIMEOUT:            /*             * This is a special case of the 'default' case below.             * Please see the comments there.             */#ifdef BSD_SELECT            tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;            tv.tv_usec = 0;            FD_ZERO(&rd_wr);            do {                FD_SET(osfd, &rd_wr);                if (fd_type == READ_FD)                    rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);                else                    rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);#else            lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;             do {                socks[0] = osfd;                if (fd_type == READ_FD)                    rv = _MD_SELECT(socks, 1, 0, 0, lTimeout);                else                    rv = _MD_SELECT(socks, 0, 1, 0, lTimeout);#endif                                    if (rv == -1 && (syserror = sock_errno()) != EINTR) {                    _PR_MD_MAP_SELECT_ERROR(syserror);                    break;                }                if (_PR_PENDING_INTERRUPT(me)) {                    me->flags &= ~_PR_INTERRUPT;                    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);                    rv = -1;                    break;                }            } while (rv == 0 || (rv == -1 && syserror == EINTR));            break;        default:            now = epoch = PR_IntervalNow();            remaining = timeout;#ifdef BSD_SELECT            FD_ZERO(&rd_wr);#endif            do {                /*                 * We block in _MD_SELECT for at most                 * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,                 * so that there is an upper limit on the delay                 * before the interrupt bit is checked.                 */#ifdef BSD_SELECT                wait_for_remaining = PR_TRUE;                tv.tv_sec = PR_IntervalToSeconds(remaining);                if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {                    wait_for_remaining = PR_FALSE;                    tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;                    tv.tv_usec = 0;                } else {                    tv.tv_usec = PR_IntervalToMicroseconds(                        remaining -                        PR_SecondsToInterval(tv.tv_sec));                }                FD_SET(osfd, &rd_wr);                if (fd_type == READ_FD)                    rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);                else                    rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);#else                wait_for_remaining = PR_TRUE;                lTimeout = PR_IntervalToMilliseconds(remaining);                if (lTimeout > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) {                    wait_for_remaining = PR_FALSE;                    lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;                }                socks[0] = osfd;                if (fd_type == READ_FD)                    rv = _MD_SELECT(socks, 1, 0, 0, lTimeout);                else                    rv = _MD_SELECT(socks, 0, 1, 0, lTimeout);#endif                /*                 * we don't consider EINTR a real error                 */                if (rv == -1 && (syserror = sock_errno()) != EINTR) {                    _PR_MD_MAP_SELECT_ERROR(syserror);                    break;                }                if (_PR_PENDING_INTERRUPT(me)) {                    me->flags &= ~_PR_INTERRUPT;                    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);                    rv = -1;                    break;                }                /*                 * We loop again if _MD_SELECT timed out or got interrupted                 * by a signal, and the timeout deadline has not passed yet.                 */                if (rv == 0 || (rv == -1 && syserror == EINTR)) {                    /*                     * If _MD_SELECT timed out, we know how much time                     * we spent in blocking, so we can avoid a                     * PR_IntervalNow() call.                     */                    if (rv == 0) {                        if (wait_for_remaining) {                            now += remaining;                        } else {#ifdef BSD_SELECT                            now += PR_SecondsToInterval(tv.tv_sec)                                + PR_MicrosecondsToInterval(tv.tv_usec);#else                            now += PR_MillisecondsToInterval(lTimeout);#endif                        }                    } else {                        now = PR_IntervalNow();                    }                    elapsed = (PRIntervalTime) (now - epoch);                    if (elapsed >= timeout) {                        PR_SetError(PR_IO_TIMEOUT_ERROR, 0);                        rv = -1;                        break;                    } else {                        remaining = timeout - elapsed;                    }                }            } while (rv == 0 || (rv == -1 && syserror == EINTR));            break;        }    return(rv);}