summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsfraser%netscape.com <devnull@localhost>2001-04-14 01:11:14 +0000
committersfraser%netscape.com <devnull@localhost>2001-04-14 01:11:14 +0000
commit6eecd80a03a40b5114e14823d28006d56eb59b25 (patch)
tree10a5999b373f81244afa125f904373863f1e0805
parentb28d7407c19cf881f13977c89317e662ccecb17c (diff)
downloadnspr-hg-6eecd80a03a40b5114e14823d28006d56eb59b25.tar.gz
These changes fix PR_Poll on Mac thusly:
1. Factor out checking the fds into a new function CheckPollDescs() 2. Factor out setting/clearing the polling thread on those fds into SetDescPollThread() 3. Be more careful about where we set the polling thread on the fds, ensuring that we turn off interrupts and hold a lock around the code that sets up the polling thread and checks for data on the fds. This fixes the race condition that causes this bug. 4. We now clear the polling thread on the fds when coming out of PR_Poll, so that the notifier doesn't attempt to wake the wrong thread when called when we're not polling. 5. Implement a 0-timeout version that behaves like select(). Bugzilla bugs 72965 and 60509. r=gordon, larryh.
-rw-r--r--pr/src/md/mac/macsockotpt.c85
-rw-r--r--pr/src/md/mac/macthr.c2
2 files changed, 67 insertions, 20 deletions
diff --git a/pr/src/md/mac/macsockotpt.c b/pr/src/md/mac/macsockotpt.c
index 57902ac1..910803c6 100644
--- a/pr/src/md/mac/macsockotpt.c
+++ b/pr/src/md/mac/macsockotpt.c
@@ -1685,19 +1685,13 @@ static PRBool GetState(PRFileDesc *fd, PRBool *readReady, PRBool *writeReady, PR
return *readReady || *writeReady || *exceptReady;
}
-
-PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
+// check to see if any of the poll descriptors have data available
+// for reading or writing.
+static PRInt32 CheckPollDescs(PRPollDesc *pds, PRIntn npds)
{
PRInt32 ready = 0;
PRPollDesc *pd, *epd;
- PRThread *thread = _PR_MD_CURRENT_THREAD();
- PRIntervalTime timein;
- if (PR_INTERVAL_NO_TIMEOUT != timeout)
- timein = PR_IntervalNow();
-
- do
- {
for (pd = pds, epd = pd + npds; pd < epd; pd++)
{
PRInt16 in_flags_read = 0, in_flags_write = 0;
@@ -1729,10 +1723,9 @@ PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
pd->out_flags = 0; /* pre-condition */
bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
PR_ASSERT(NULL != bottomFD);
- if ((NULL != bottomFD) && (_PR_FILEDESC_OPEN == bottomFD->secret->state))
- {
- bottomFD->secret->md.poll.thread = thread;
+ if (bottomFD && (_PR_FILEDESC_OPEN == bottomFD->secret->state))
+ {
if (GetState(bottomFD, &readReady, &writeReady, &exceptReady))
{
if (readReady)
@@ -1756,7 +1749,7 @@ PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
if (0 != pd->out_flags) ready++;
}
}
- else
+ else /* bad state */
{
ready += 1; /* this will cause an abrupt return */
pd->out_flags = PR_POLL_NVAL; /* bogii */
@@ -1764,17 +1757,69 @@ PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
}
}
- if (ready > 0) return ready;
+ return ready;
+}
+
+// set or clear md.poll.thread on the poll descriptors
+static void SetDescPollThread(PRPollDesc *pds, PRIntn npds, PRThread* thread)
+{
+ PRInt32 ready = 0;
+ PRPollDesc *pd, *epd;
+
+ for (pd = pds, epd = pd + npds; pd < epd; pd++)
+ {
+ if (pd->fd)
+ {
+ PRFileDesc *bottomFD = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
+ PR_ASSERT(NULL != bottomFD);
+ if (bottomFD && (_PR_FILEDESC_OPEN == bottomFD->secret->state))
+ {
+ bottomFD->secret->md.poll.thread = thread;
+ }
+ }
+ }
+}
+
+PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
+{
+ PRThread *thread = _PR_MD_CURRENT_THREAD();
+ intn is;
+ PRInt32 ready;
+ OSErr result;
+
+ if (timeout == PR_INTERVAL_NO_WAIT) {
+ return CheckPollDescs(pds, npds);
+ }
+
+ _PR_INTSOFF(is);
+ PR_Lock(thread->md.asyncIOLock);
+
+ // ensure that we don't miss the firing of the notifier while checking socket status
+ // need to set up the thread
+ PrepareForAsyncCompletion(thread, 0);
+
+ SetDescPollThread(pds, npds, thread);
+ ready = CheckPollDescs(pds, npds);
- thread->io_pending = PR_TRUE;
- thread->io_fd = NULL;
- thread->md.osErrCode = noErr;
+ PR_Unlock(thread->md.asyncIOLock);
+ _PR_FAST_INTSON(is);
+
+ if (ready == 0) {
WaitOnThisThread(thread, timeout);
+ result = thread->md.osErrCode;
+ if (result != noErr && result != kETIMEDOUTErr) {
+ PR_ASSERT(0); /* debug: catch unexpected errors */
+ ready = -1;
+ } else {
+ ready = CheckPollDescs(pds, npds);
+ }
+ } else {
+ thread->io_pending = PR_FALSE;
+ }
- } while ((timeout == PR_INTERVAL_NO_TIMEOUT) ||
- (((PRIntervalTime)(PR_IntervalNow() - timein)) < timeout));
+ SetDescPollThread(pds, npds, NULL);
- return 0; /* timed out */
+ return ready;
}
diff --git a/pr/src/md/mac/macthr.c b/pr/src/md/mac/macthr.c
index 53d61206..59b67a67 100644
--- a/pr/src/md/mac/macthr.c
+++ b/pr/src/md/mac/macthr.c
@@ -275,6 +275,8 @@ void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout)
thread->md.osErrCode = kETIMEDOUTErr;
PR_SetError(PR_IO_TIMEOUT_ERROR, kETIMEDOUTErr);
}
+
+ thread->io_pending = PR_FALSE;
PR_Unlock(thread->md.asyncIOLock);
_PR_FAST_INTSON(is);
}