diff options
author | sfraser%netscape.com <devnull@localhost> | 2001-04-14 01:11:14 +0000 |
---|---|---|
committer | sfraser%netscape.com <devnull@localhost> | 2001-04-14 01:11:14 +0000 |
commit | 6eecd80a03a40b5114e14823d28006d56eb59b25 (patch) | |
tree | 10a5999b373f81244afa125f904373863f1e0805 | |
parent | b28d7407c19cf881f13977c89317e662ccecb17c (diff) | |
download | nspr-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.c | 85 | ||||
-rw-r--r-- | pr/src/md/mac/macthr.c | 2 |
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); } |