Bugzilla bug 134192: fixed a bug that may cause us to poll or select with
authorwtc%netscape.com
Fri, 29 Mar 2002 16:08:14 +0000
changeset 2313 77cd1954201eaf12fa773584a61547d9f4e2d5f0
parent 2312 cca80d33e519dae71be251caf1672af6a40f8e1e
child 2314 ba1e15124cafee02200f08605d82afab11c62da9
push idunknown
push userunknown
push dateunknown
bugs134192
Bugzilla bug 134192: fixed a bug that may cause us to poll or select with a zero timeout forever. Thanks to Jeff Stewart of Good Technology for the bug report and explaining the bug to me. Modified files: bnet.c os2sock.c unix.c w95sock.c ptio.c
pr/src/md/beos/bnet.c
pr/src/md/os2/os2sock.c
pr/src/md/unix/unix.c
pr/src/md/windows/w95sock.c
pr/src/pthreads/ptio.c
--- a/pr/src/md/beos/bnet.c
+++ b/pr/src/md/beos/bnet.c
@@ -75,16 +75,17 @@ static PRMonitor *_pr_Xfe_mon = NULL;
 
 static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type,
                               PRIntervalTime timeout)
 {
     PRInt32 rv = -1;
     struct timeval tv;
     PRThread *me = _PR_MD_CURRENT_THREAD();
     PRIntervalTime epoch, now, elapsed, remaining;
+    PRBool wait_for_remaining;
     PRInt32 syserror;
     fd_set rd_wr;
 
     switch (timeout) {
     case PR_INTERVAL_NO_WAIT:
         PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
         break;
     case PR_INTERVAL_NO_TIMEOUT:
@@ -127,18 +128,20 @@ static PRInt32 socket_io_wait(PRInt32 os
         FD_ZERO(&rd_wr);
         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.
              */
+            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);
@@ -173,18 +176,22 @@ static PRInt32 socket_io_wait(PRInt32 os
              */
             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) {
-                    now += PR_SecondsToInterval(tv.tv_sec)
-                           + PR_MicrosecondsToInterval(tv.tv_usec);
+                    if (wait_for_remaining) {
+                        now += remaining;
+                    } else {
+                        now += PR_SecondsToInterval(tv.tv_sec)
+                               + PR_MicrosecondsToInterval(tv.tv_usec);
+                    }
                 } else {
                     now = PR_IntervalNow();
                 }
                 elapsed = (PRIntervalTime) (now - epoch);
                 if (elapsed >= timeout) {
                     PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                     rv = -1;
                     break;
--- a/pr/src/md/os2/os2sock.c
+++ b/pr/src/md/os2/os2sock.c
@@ -108,16 +108,17 @@ PRInt32
 }
 
 static PRInt32
 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
@@ -171,34 +172,39 @@ socket_io_wait( PRInt32 osfd, PRInt32 fd
             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)
+                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
@@ -219,22 +225,26 @@ socket_io_wait( PRInt32 osfd, PRInt32 fd
                  */
                 if (rv == 0 || (rv == -1 && syserror == SOCEINTR)) {
                     /*
                      * 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);
+                            now += PR_SecondsToInterval(tv.tv_sec)
+                                + PR_MicrosecondsToInterval(tv.tv_usec);
 #else
-                        now += PR_MillisecondsToInterval(lTimeout);
+                            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;
--- a/pr/src/md/unix/unix.c
+++ b/pr/src/md/unix/unix.c
@@ -509,16 +509,17 @@ PRInt64 _MD_socketavailable64(PRFileDesc
 
 static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type,
     PRIntervalTime timeout)
 {
     PRInt32 rv = -1;
     struct timeval tv;
     PRThread *me = _PR_MD_CURRENT_THREAD();
     PRIntervalTime epoch, now, elapsed, remaining;
+    PRBool wait_for_remaining;
     PRInt32 syserror;
     fd_set rd_wr;
 
     switch (timeout) {
         case PR_INTERVAL_NO_WAIT:
             PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
             break;
         case PR_INTERVAL_NO_TIMEOUT:
@@ -553,18 +554,20 @@ static PRInt32 socket_io_wait(PRInt32 os
             FD_ZERO(&rd_wr);
             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.
                  */
+                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);
@@ -591,18 +594,22 @@ static PRInt32 socket_io_wait(PRInt32 os
                  */
                 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) {
-                        now += PR_SecondsToInterval(tv.tv_sec)
-                            + PR_MicrosecondsToInterval(tv.tv_usec);
+                        if (wait_for_remaining) {
+                            now += remaining;
+                        } else {
+                            now += PR_SecondsToInterval(tv.tv_sec)
+                                + PR_MicrosecondsToInterval(tv.tv_usec);
+                        }
                     } else {
                         now = PR_IntervalNow();
                     }
                     elapsed = (PRIntervalTime) (now - epoch);
                     if (elapsed >= timeout) {
                         PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                         rv = -1;
                         break;
@@ -620,16 +627,17 @@ static PRInt32 socket_io_wait(PRInt32 os
 
 static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type,
     PRIntervalTime timeout)
 {
     PRInt32 rv = -1;
     int msecs;
     PRThread *me = _PR_MD_CURRENT_THREAD();
     PRIntervalTime epoch, now, elapsed, remaining;
+    PRBool wait_for_remaining;
     PRInt32 syserror;
     struct pollfd pfd;
 
     switch (timeout) {
         case PR_INTERVAL_NO_WAIT:
             PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
             break;
         case PR_INTERVAL_NO_TIMEOUT:
@@ -677,18 +685,20 @@ static PRInt32 socket_io_wait(PRInt32 os
             }
             do {
                 /*
                  * We block in _MD_POLL 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.
                  */
+                wait_for_remaining = PR_TRUE;
                 msecs = PR_IntervalToMilliseconds(remaining);
                 if (msecs > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) {
+                    wait_for_remaining = PR_FALSE;
                     msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;
                 }
                 rv = _MD_POLL(&pfd, 1, msecs);
                 /*
                  * we don't consider EINTR a real error
                  */
                 if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
                     _PR_MD_MAP_POLL_ERROR(syserror);
@@ -714,17 +724,21 @@ static PRInt32 socket_io_wait(PRInt32 os
                  */
                 if (rv == 0 || (rv == -1 && syserror == EINTR)) {
                     /*
                      * If _MD_POLL timed out, we know how much time
                      * we spent in blocking, so we can avoid a
                      * PR_IntervalNow() call.
                      */
                     if (rv == 0) {
-                        now += PR_MillisecondsToInterval(msecs);
+                        if (wait_for_remaining) {
+                            now += remaining;
+                        } else {
+                            now += PR_MillisecondsToInterval(msecs);
+                        }
                     } else {
                         now = PR_IntervalNow();
                     }
                     elapsed = (PRIntervalTime) (now - epoch);
                     if (elapsed >= timeout) {
                         PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                         rv = -1;
                         break;
--- a/pr/src/md/windows/w95sock.c
+++ b/pr/src/md/windows/w95sock.c
@@ -469,16 +469,17 @@ static PRInt32 socket_io_wait(
     PRInt32 osfd, 
     PRInt32 fd_type,
     PRIntervalTime timeout)
 {
     PRInt32 rv = -1;
     struct timeval tv;
     PRThread *me = _PR_MD_CURRENT_THREAD();
     PRIntervalTime elapsed, remaining;
+    PRBool wait_for_remaining;
     fd_set rd_wr, ex;
     int err, len;
 
     switch (timeout) {
         case PR_INTERVAL_NO_WAIT:
             PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
             break;
         case PR_INTERVAL_NO_TIMEOUT:
@@ -555,18 +556,20 @@ static PRInt32 socket_io_wait(
             FD_ZERO(&ex);
             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.
                  */
+                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);
@@ -626,18 +629,22 @@ static PRInt32 socket_io_wait(
                     break;
                 }
                 /*
                  * We loop again if _MD_SELECT timed out and the
                  * timeout deadline has not passed yet.
                  */
                 if (rv == 0 )
                 {
-                    elapsed = PR_SecondsToInterval(tv.tv_sec) 
-                                + PR_MicrosecondsToInterval(tv.tv_usec);
+                    if (wait_for_remaining) {
+                        elapsed = remaining;
+                    } else {
+                        elapsed = PR_SecondsToInterval(tv.tv_sec) 
+                                    + PR_MicrosecondsToInterval(tv.tv_usec);
+                    }
                     if (elapsed >= remaining) {
                         PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                         rv = -1;
                         break;
                     } else {
                         remaining = remaining - elapsed;
                     }
                 }
--- a/pr/src/pthreads/ptio.c
+++ b/pr/src/pthreads/ptio.c
@@ -420,16 +420,17 @@ PR_IMPLEMENT(void) PT_FPrintStats(PRFile
  * workaround this problem.
  */
 static void pt_poll_now_with_select(pt_Continuation *op)
 {
     PRInt32 msecs;
 	fd_set rd, wr, *rdp, *wrp;
 	struct timeval tv;
 	PRIntervalTime epoch, now, elapsed, remaining;
+	PRBool wait_for_remaining;
     PRThread *self = PR_GetCurrentThread();
     
 	PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
 	PR_ASSERT(op->arg1.osfd < FD_SETSIZE);
 
     switch (op->timeout) {
         case PR_INTERVAL_NO_TIMEOUT:
 			tv.tv_sec = PT_DEFAULT_SELECT_SEC;
@@ -499,19 +500,22 @@ static void pt_poll_now_with_select(pt_C
 					rdp = NULL;
 				if (op->event & POLLOUT) {
 					FD_ZERO(&wr);
 					FD_SET(op->arg1.osfd, &wr);
 					wrp = &wr;
 				} else
 					wrp = NULL;
 
+    			wait_for_remaining = PR_TRUE;
     			msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
-				if (msecs > PT_DEFAULT_POLL_MSEC)
+				if (msecs > PT_DEFAULT_POLL_MSEC) {
+					wait_for_remaining = PR_FALSE;
 					msecs = PT_DEFAULT_POLL_MSEC;
+				}
 				tv.tv_sec = msecs/PR_MSEC_PER_SEC;
 				tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
 				rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv);
 
 				if (self->state & PT_THREAD_ABORTED)
 				{
 					self->state &= ~PT_THREAD_ABORTED;
 					op->result.code = -1;
@@ -528,19 +532,22 @@ static void pt_poll_now_with_select(pt_C
 					if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr))
 						revents |= POLLOUT;
 						
 					if (op->function(op, revents))
 						op->status = pt_continuation_done;
 
 				} else if ((rv == 0) ||
 						((errno == EINTR) || (errno == EAGAIN))) {
-					if (rv == 0)	/* select timed out */
-						now += PR_MillisecondsToInterval(msecs);
-					else
+					if (rv == 0) {	/* select timed out */
+						if (wait_for_remaining)
+							now += remaining;
+						else
+							now += PR_MillisecondsToInterval(msecs);
+					} else
 						now = PR_IntervalNow();
 					elapsed = (PRIntervalTime) (now - epoch);
 					if (elapsed >= op->timeout) {
 						op->result.code = -1;
 						op->syserrno = ETIMEDOUT;
 						op->status = pt_continuation_done;
 					} else
 						remaining = op->timeout - elapsed;
@@ -556,16 +563,17 @@ static void pt_poll_now_with_select(pt_C
 }  /* pt_poll_now_with_select */
 
 #endif	/* _PR_POLL_WITH_SELECT */
 
 static void pt_poll_now(pt_Continuation *op)
 {
     PRInt32 msecs;
 	PRIntervalTime epoch, now, elapsed, remaining;
+	PRBool wait_for_remaining;
     PRThread *self = PR_GetCurrentThread();
     
 	PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
 #if defined (_PR_POLL_WITH_SELECT)
 	/*
  	 * If the fd is small enough call the select-based poll operation
 	 */
 	if (op->arg1.osfd < FD_SETSIZE) {
@@ -632,19 +640,23 @@ static void pt_poll_now(pt_Continuation 
 			{
 				PRIntn rv;
 				struct pollfd tmp_pfd;
 
 				tmp_pfd.revents = 0;
 				tmp_pfd.fd = op->arg1.osfd;
 				tmp_pfd.events = op->event;
 
+    			wait_for_remaining = PR_TRUE;
     			msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
 				if (msecs > PT_DEFAULT_POLL_MSEC)
+				{
+					wait_for_remaining = PR_FALSE;
 					msecs = PT_DEFAULT_POLL_MSEC;
+				}
 				rv = poll(&tmp_pfd, 1, msecs);
 				
 				if (self->state & PT_THREAD_ABORTED)
 				{
 					self->state &= ~PT_THREAD_ABORTED;
 					op->result.code = -1;
 					op->syserrno = EINTR;
 					op->status = pt_continuation_done;
@@ -668,17 +680,22 @@ static void pt_poll_now(pt_Continuation 
 						if (op->function(op, revents))
 						{
 							op->status = pt_continuation_done;
 						}
 					}
 				} else if ((rv == 0) ||
 						((errno == EINTR) || (errno == EAGAIN))) {
 					if (rv == 0)	/* poll timed out */
-						now += PR_MillisecondsToInterval(msecs);
+					{
+						if (wait_for_remaining)
+							now += remaining;
+						else
+							now += PR_MillisecondsToInterval(msecs);
+					}
 					else
 						now = PR_IntervalNow();
 					elapsed = (PRIntervalTime) (now - epoch);
 					if (elapsed >= op->timeout) {
 						op->result.code = -1;
 						op->syserrno = ETIMEDOUT;
 						op->status = pt_continuation_done;
 					} else