template <uint32_t K> static bool test_random() { srand(K); error = false; for (uint32_t j = 0; j < iterations; ++j) { Tracker<K> tracker; uint32_t i = 0; for (i = 0; i < ops; ++i) { if ((rand() & 0xF) == 0) { // Simulate work that takes time if (logging) { printf("SLEEPING for %dms (%d)\n", sleepPeriodMS, PR_IntervalNow()); } PR_Sleep(PR_MillisecondsToInterval(sleepPeriodMS)); // Process pending timer events NS_ProcessPendingEvents(nullptr); } tracker.DoRandomOperation(); } } return !error; }
PRIntervalTime DOMStorageDBThread::TimeUntilFlush() { if (mFlushImmediately) { return 0; // Do it now regardless the timeout. } static_assert(PR_INTERVAL_NO_TIMEOUT != 0, "PR_INTERVAL_NO_TIMEOUT must be non-zero"); if (!mDirtyEpoch) { return PR_INTERVAL_NO_TIMEOUT; // No pending task... } static const PRIntervalTime kMaxAge = PR_MillisecondsToInterval(FLUSHING_INTERVAL_MS); PRIntervalTime now = PR_IntervalNow() | 1; PRIntervalTime age = now - mDirtyEpoch; if (age > kMaxAge) { return 0; // It is time. } return kMaxAge - age; // Time left, this is used to sleep the monitor }
static PRAlarmID *pr_getNextAlarm(PRAlarm *alarm, PRAlarmID *id) { /* * Puts 'id' back into the sorted list iff it's not NULL. * Removes the first element from the list and returns it (or NULL). * List is "assumed" to be short. * * NB: Caller is providing locking */ PRCList *timer; PRAlarmID *result = id; PRIntervalTime now = PR_IntervalNow(); if (!PR_CLIST_IS_EMPTY(&alarm->timers)) { if (id != NULL) /* have to put this id back in */ { PRIntervalTime idDelta = now - id->nextNotify; timer = alarm->timers.next; do { result = (PRAlarmID*)timer; if ((PRIntervalTime)(now - result->nextNotify) > idDelta) { PR_INSERT_BEFORE(&id->list, &alarm->timers); break; } timer = timer->next; } while (timer != &alarm->timers); } result = (PRAlarmID*)(timer = PR_LIST_HEAD(&alarm->timers)); PR_REMOVE_LINK(timer); /* remove it from the list */ } return result; } /* pr_getNextAlarm */
void SpdySession31::PrintDiagnostics(nsCString &log) { log.AppendPrintf(" ::: SPDY VERSION 3.1\n"); log.AppendPrintf(" shouldgoaway = %d mClosed = %d CanReuse = %d nextID=0x%X\n", mShouldGoAway, mClosed, CanReuse(), mNextStreamID); log.AppendPrintf(" concurrent = %d maxconcurrent = %d\n", mConcurrent, mMaxConcurrent); log.AppendPrintf(" roomformorestreams = %d roomformoreconcurrent = %d\n", RoomForMoreStreams(), RoomForMoreConcurrent()); log.AppendPrintf(" transactionHashCount = %d streamIDHashCount = %d\n", mStreamTransactionHash.Count(), mStreamIDHash.Count()); log.AppendPrintf(" Queued Stream Size = %d\n", mQueuedStreams.GetSize()); PRIntervalTime now = PR_IntervalNow(); log.AppendPrintf(" Ping Threshold = %ums next ping id = 0x%X\n", PR_IntervalToMilliseconds(mPingThreshold), mNextPingID); log.AppendPrintf(" Ping Timeout = %ums\n", PR_IntervalToMilliseconds(gHttpHandler->SpdyPingTimeout())); log.AppendPrintf(" Idle for Any Activity (ping) = %ums\n", PR_IntervalToMilliseconds(now - mLastReadEpoch)); log.AppendPrintf(" Idle for Data Activity = %ums\n", PR_IntervalToMilliseconds(now - mLastDataReadEpoch)); if (mPingSentEpoch) log.AppendPrintf(" Ping Outstanding (ping) = %ums, expired = %d\n", PR_IntervalToMilliseconds(now - mPingSentEpoch), now - mPingSentEpoch >= gHttpHandler->SpdyPingTimeout()); else log.AppendPrintf(" No Ping Outstanding\n"); }
static PRIntervalTime Alarms1(PRUint32 loops) { PRAlarm *alarm; AlarmData ad; PRIntervalTime overhead, timein = PR_IntervalNow(); PRIntervalTime duration = PR_SecondsToInterval(3); PRLock *ml = PR_NewLock(); PRCondVar *cv = PR_NewCondVar(ml); ad.ml = ml; ad.cv = cv; ad.rate = 1; ad.times = loops; ad.late = ad.times = 0; ad.duration = duration; ad.timein = PR_IntervalNow(); ad.period = PR_SecondsToInterval(1); alarm = PR_CreateAlarm(); (void)PR_SetAlarm( alarm, ad.period, ad.rate, AlarmFn1, &ad); overhead = PR_IntervalNow() - timein; PR_Lock(ml); while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); PR_Unlock(ml); timein = PR_IntervalNow(); (void)PR_DestroyAlarm(alarm); PR_DestroyCondVar(cv); PR_DestroyLock(ml); overhead += (PR_IntervalNow() - timein); return duration + overhead; } /* Alarms1 */
NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsIView* aView, nsEventStatus *aStatus) { NS_ASSERTION(!aView || static_cast<nsView*>(aView)->GetViewManager() == this, "wrong view manager"); SAMPLE_LABEL("event", "nsViewManager::DispatchEvent"); *aStatus = nsEventStatus_eIgnore; switch(aEvent->message) { case NS_SIZE: { if (aView) { // client area dimensions are set on the view nscoord width = ((nsSizeEvent*)aEvent)->windowSize->width; nscoord height = ((nsSizeEvent*)aEvent)->windowSize->height; // The root view may not be set if this is the resize associated with // window creation if (aView == mRootView) { PRInt32 p2a = AppUnitsPerDevPixel(); SetWindowDimensions(NSIntPixelsToAppUnits(width, p2a), NSIntPixelsToAppUnits(height, p2a)); *aStatus = nsEventStatus_eConsumeNoDefault; } else if (IsViewForPopup(aView)) { nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); if (pm) { pm->PopupResized(aView->GetFrame(), nsIntSize(width, height)); *aStatus = nsEventStatus_eConsumeNoDefault; } } } } break; case NS_MOVE: { // A popup's parent view is the root view for the parent window, so when // a popup moves, the popup's frame and view position must be updated // to match. if (aView && IsViewForPopup(aView)) { nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); if (pm) { pm->PopupMoved(aView->GetFrame(), aEvent->refPoint); *aStatus = nsEventStatus_eConsumeNoDefault; } } break; } case NS_DONESIZEMOVE: { if (mPresShell) { nsPresContext* presContext = mPresShell->GetPresContext(); if (presContext) { nsEventStateManager::ClearGlobalActiveContent(nsnull); } } nsIPresShell::ClearMouseCapture(nsnull); } break; case NS_XUL_CLOSE: { // if this is a popup, make a request to hide it. Note that a popuphidden // event listener may cancel the event and the popup will not be hidden. nsIWidget* widget = aView->GetWidget(); if (widget) { nsWindowType type; widget->GetWindowType(type); if (type == eWindowType_popup) { nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); if (pm) { pm->HidePopup(aView->GetFrame()); *aStatus = nsEventStatus_eConsumeNoDefault; } } } } break; case NS_WILL_PAINT: { if (!aView || !mContext) break; *aStatus = nsEventStatus_eConsumeNoDefault; nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent); NS_ASSERTION(static_cast<nsView*>(aView) == nsView::GetViewFor(event->widget), "view/widget mismatch"); // If an ancestor widget was hidden and then shown, we could // have a delayed resize to handle. for (nsViewManager *vm = this; vm; vm = vm->mRootView->GetParent() ? vm->mRootView->GetParent()->GetViewManager() : nsnull) { if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) && vm->mRootView->IsEffectivelyVisible() && mPresShell && mPresShell->IsVisible()) { vm->FlushDelayedResize(true); vm->InvalidateView(vm->mRootView); } } // Flush things like reflows and plugin widget geometry updates by // calling WillPaint on observer presShells. nsRefPtr<nsViewManager> rootVM = RootViewManager(); if (mPresShell) { rootVM->CallWillPaintOnObservers(event->willSendDidPaint); } // Flush view widget geometry updates and invalidations. rootVM->ProcessPendingUpdates(); } break; case NS_PAINT: { if (!aView || !mContext) break; *aStatus = nsEventStatus_eConsumeNoDefault; nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent); nsView* view = static_cast<nsView*>(aView); NS_ASSERTION(view == nsView::GetViewFor(event->widget), "view/widget mismatch"); NS_ASSERTION(IsPaintingAllowed(), "shouldn't be receiving paint events while painting is " "disallowed!"); if (!event->didSendWillPaint) { // Send NS_WILL_PAINT event ourselves. nsPaintEvent willPaintEvent(true, NS_WILL_PAINT, event->widget); willPaintEvent.willSendDidPaint = event->willSendDidPaint; DispatchEvent(&willPaintEvent, view, aStatus); // Get the view pointer again since NS_WILL_PAINT might have // destroyed it during CallWillPaintOnObservers (bug 378273). view = nsView::GetViewFor(event->widget); } if (!view || event->region.IsEmpty()) break; // Paint. Refresh(view, event->region, event->willSendDidPaint); break; } case NS_DID_PAINT: { nsRefPtr<nsViewManager> rootVM = RootViewManager(); rootVM->CallDidPaintOnObserver(); break; } case NS_CREATE: case NS_DESTROY: case NS_SETZLEVEL: /* Don't pass these events through. Passing them through causes performance problems on pages with lots of views/frames @see bug 112861 */ *aStatus = nsEventStatus_eConsumeNoDefault; break; case NS_DISPLAYCHANGED: //Destroy the cached backbuffer to force a new backbuffer //be constructed with the appropriate display depth. //@see bugzilla bug 6061 *aStatus = nsEventStatus_eConsumeDoDefault; break; case NS_SYSCOLORCHANGED: { if (mPresShell) { // Hold a refcount to the presshell. The continued existence of the observer will // delay deletion of this view hierarchy should the event want to cause its // destruction in, say, some JavaScript event handler. nsCOMPtr<nsIPresShell> presShell = mPresShell; presShell->HandleEvent(aView->GetFrame(), aEvent, false, aStatus); } } break; default: { if ((NS_IS_MOUSE_EVENT(aEvent) && // Ignore mouse events that we synthesize. static_cast<nsMouseEvent*>(aEvent)->reason == nsMouseEvent::eReal && // Ignore mouse exit and enter (we'll get moves if the user // is really moving the mouse) since we get them when we // create and destroy widgets. aEvent->message != NS_MOUSE_EXIT && aEvent->message != NS_MOUSE_ENTER) || NS_IS_KEY_EVENT(aEvent) || NS_IS_IME_EVENT(aEvent) || aEvent->message == NS_PLUGIN_INPUT_EVENT) { gLastUserEventTime = PR_IntervalToMicroseconds(PR_IntervalNow()); } if (aEvent->message == NS_DEACTIVATE) { // if a window is deactivated, clear the mouse capture regardless // of what is capturing nsIPresShell::ClearMouseCapture(nsnull); } // Find the view whose coordinates system we're in. nsIView* view = aView; bool dispatchUsingCoordinates = NS_IsEventUsingCoordinates(aEvent); if (dispatchUsingCoordinates) { // Will dispatch using coordinates. Pretty bogus but it's consistent // with what presshell does. view = GetDisplayRootFor(view); } // If the view has no frame, look for a view that does. nsIFrame* frame = view->GetFrame(); if (!frame && (dispatchUsingCoordinates || NS_IS_KEY_EVENT(aEvent) || NS_IS_IME_RELATED_EVENT(aEvent) || NS_IS_NON_RETARGETED_PLUGIN_EVENT(aEvent) || aEvent->message == NS_PLUGIN_ACTIVATE || aEvent->message == NS_PLUGIN_FOCUS)) { while (view && !view->GetFrame()) { view = view->GetParent(); } if (view) { frame = view->GetFrame(); } } if (nsnull != frame) { // Hold a refcount to the presshell. The continued existence of the // presshell will delay deletion of this view hierarchy should the event // want to cause its destruction in, say, some JavaScript event handler. nsCOMPtr<nsIPresShell> shell = view->GetViewManager()->GetPresShell(); if (shell) { shell->HandleEvent(frame, aEvent, false, aStatus); } } break; } } return NS_OK; }
void mozTXTToHTMLConv::ScanHTML(nsString& aInString, PRUint32 whattodo, nsString &aOutString) { // some common variables we were recalculating // every time inside the for loop... PRInt32 lengthOfInString = aInString.Length(); const PRUnichar * uniBuffer = aInString.get(); #ifdef DEBUG_BenB_Perf PRTime parsing_start = PR_IntervalNow(); #endif // Look for simple entities not included in a tags and scan them. /* Skip all tags ("<[...]>") and content in an a tag ("<a[...]</a>") or in a tag ("<!--[...]-->"). Unescape the rest (text between tags) and pass it to ScanTXT. */ for (PRInt32 i = 0; i < lengthOfInString;) { if (aInString[i] == '<') // html tag { PRUint32 start = PRUint32(i); if (nsCRT::ToLower((char)aInString[PRUint32(i) + 1]) == 'a') // if a tag, skip until </a> { i = aInString.Find("</a>", true, i); if (i == kNotFound) i = lengthOfInString; else i += 4; } else if (aInString[PRUint32(i) + 1] == '!' && aInString[PRUint32(i) + 2] == '-' && aInString[PRUint32(i) + 3] == '-') //if out-commended code, skip until --> { i = aInString.Find("-->", false, i); if (i == kNotFound) i = lengthOfInString; else i += 3; } else // just skip tag (attributes etc.) { i = aInString.FindChar('>', i); if (i == kNotFound) i = lengthOfInString; else i++; } aOutString.Append(&uniBuffer[start], PRUint32(i) - start); } else { PRUint32 start = PRUint32(i); i = aInString.FindChar('<', i); if (i == kNotFound) i = lengthOfInString; nsString tempString; tempString.SetCapacity(PRUint32((PRUint32(i) - start) * growthRate)); UnescapeStr(uniBuffer, start, PRUint32(i) - start, tempString); ScanTXT(tempString.get(), tempString.Length(), whattodo, aOutString); } } #ifdef DEBUG_BenB_Perf printf("ScanHTML time: %d ms\n", PR_IntervalToMilliseconds(PR_IntervalNow() - parsing_start)); #endif }
PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) { #ifdef BSD_SELECT fd_set rd, wt, ex; #else int rd, wt, ex; int* socks; unsigned long msecs; int i, j; #endif PRFileDesc *bottom; PRPollDesc *pd, *epd; PRInt32 maxfd = -1, ready, err; PRIntervalTime remaining, elapsed, start; #ifdef BSD_SELECT struct timeval tv, *tvp = NULL; FD_ZERO(&rd); FD_ZERO(&wt); FD_ZERO(&ex); #else rd = 0; wt = 0; ex = 0; socks = (int) PR_MALLOC( npds * 3 * sizeof(int) ); if (!socks) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return -1; } #endif ready = 0; for (pd = pds, epd = pd + npds; pd < epd; pd++) { PRInt16 in_flags_read = 0, in_flags_write = 0; PRInt16 out_flags_read = 0, out_flags_write = 0; if ((NULL != pd->fd) && (0 != pd->in_flags)) { if (pd->in_flags & PR_POLL_READ) { in_flags_read = (pd->fd->methods->poll)( pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read); } if (pd->in_flags & PR_POLL_WRITE) { in_flags_write = (pd->fd->methods->poll)( pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write); } if ((0 != (in_flags_read & out_flags_read)) || (0 != (in_flags_write & out_flags_write))) { /* this one's ready right now */ if (0 == ready) { /* * We will have to return without calling the * system poll/select function. So zero the * out_flags fields of all the poll descriptors * before this one. */ PRPollDesc *prev; for (prev = pds; prev < pd; prev++) { prev->out_flags = 0; } } ready += 1; pd->out_flags = out_flags_read | out_flags_write; } else { pd->out_flags = 0; /* pre-condition */ /* make sure this is an NSPR supported stack */ bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); PR_ASSERT(NULL != bottom); /* what to do about that? */ if ((NULL != bottom) && (_PR_FILEDESC_OPEN == bottom->secret->state)) { if (0 == ready) { PRInt32 osfd = bottom->secret->md.osfd; if (osfd > maxfd) maxfd = osfd; if (in_flags_read & PR_POLL_READ) { pd->out_flags |= _PR_POLL_READ_SYS_READ; #ifdef BSD_SELECT FD_SET(osfd, &rd); #else socks[rd] = osfd; rd++; #endif } if (in_flags_read & PR_POLL_WRITE) { pd->out_flags |= _PR_POLL_READ_SYS_WRITE; #ifdef BSD_SELECT FD_SET(osfd, &wt); #else socks[npds+wt] = osfd; wt++; #endif } if (in_flags_write & PR_POLL_READ) { pd->out_flags |= _PR_POLL_WRITE_SYS_READ; #ifdef BSD_SELECT FD_SET(osfd, &rd); #else socks[rd] = osfd; rd++; #endif } if (in_flags_write & PR_POLL_WRITE) { pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; #ifdef BSD_SELECT FD_SET(osfd, &wt); #else socks[npds+wt] = osfd; wt++; #endif } if (pd->in_flags & PR_POLL_EXCEPT) { #ifdef BSD_SELECT FD_SET(osfd, &ex); #else socks[npds*2+ex] = osfd; ex++; #endif } } } else { if (0 == ready) { PRPollDesc *prev; for (prev = pds; prev < pd; prev++) { prev->out_flags = 0; } } ready += 1; /* this will cause an abrupt return */ pd->out_flags = PR_POLL_NVAL; /* bogii */ } } } else { pd->out_flags = 0; } } if (0 != ready) { #ifndef BSD_SELECT PR_Free(socks); #endif return ready; /* no need to block */ } remaining = timeout; start = PR_IntervalNow(); retry: #ifdef BSD_SELECT if (timeout != PR_INTERVAL_NO_TIMEOUT) { PRInt32 ticksPerSecond = PR_TicksPerSecond(); tv.tv_sec = remaining / ticksPerSecond; tv.tv_usec = PR_IntervalToMicroseconds( remaining % ticksPerSecond ); tvp = &tv; } ready = bsdselect(maxfd + 1, &rd, &wt, &ex, tvp); #else switch (timeout) { case PR_INTERVAL_NO_WAIT: msecs = 0; break; case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break; default: msecs = PR_IntervalToMilliseconds(remaining); } /* compact array */ for( i = rd, j = npds; j < npds+wt; i++,j++ ) socks[i] = socks[j]; for( i = rd+wt, j = npds*2; j < npds*2+ex; i++,j++ ) socks[i] = socks[j]; ready = os2_select(socks, rd, wt, ex, msecs); #endif if (ready == -1 && errno == EINTR) { if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry; else { elapsed = (PRIntervalTime) (PR_IntervalNow() - start); if (elapsed > timeout) ready = 0; /* timed out */ else { remaining = timeout - elapsed; goto retry; } } } /* ** Now to unravel the select sets back into the client's poll ** descriptor list. Is this possibly an area for pissing away ** a few cycles or what? */ if (ready > 0) { ready = 0; for (pd = pds, epd = pd + npds; pd < epd; pd++) { PRInt16 out_flags = 0; if ((NULL != pd->fd) && (0 != pd->in_flags)) { PRInt32 osfd; bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); PR_ASSERT(NULL != bottom); osfd = bottom->secret->md.osfd; #ifdef BSD_SELECT if (FD_ISSET(osfd, &rd)) #else if( IsSocketSet(osfd, socks, 0, rd) ) #endif { if (pd->out_flags & _PR_POLL_READ_SYS_READ) out_flags |= PR_POLL_READ; if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) out_flags |= PR_POLL_WRITE; } #ifdef BSD_SELECT if (FD_ISSET(osfd, &wt)) #else if( IsSocketSet(osfd, socks, rd, wt) ) #endif { if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) out_flags |= PR_POLL_READ; if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) out_flags |= PR_POLL_WRITE; } #ifdef BSD_SELECT if (FD_ISSET(osfd, &ex)) #else if( IsSocketSet(osfd, socks, rd+wt, ex) ) #endif { out_flags |= PR_POLL_EXCEPT; } } pd->out_flags = out_flags; if (out_flags) ready++; } PR_ASSERT(ready > 0); } else if (ready < 0) { err = _MD_ERRNO(); if (err == EBADF) { /* Find the bad fds */ int optval; int optlen = sizeof(optval); ready = 0; for (pd = pds, epd = pd + npds; pd < epd; pd++) { pd->out_flags = 0; if ((NULL != pd->fd) && (0 != pd->in_flags)) { bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET, SO_TYPE, (char *) &optval, &optlen) == -1) { PR_ASSERT(sock_errno() == ENOTSOCK); if (sock_errno() == ENOTSOCK) { pd->out_flags = PR_POLL_NVAL; ready++; } } } } PR_ASSERT(ready > 0); } else _PR_MD_MAP_SELECT_ERROR(err); } #ifndef BSD_SELECT PR_Free(socks); #endif return ready; }
static PRInt32 NativeThreadSelect( PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) { /* * This code is almost a duplicate of w32poll.c's _PR_MD_PR_POLL(). */ fd_set rd, wt, ex; PRFileDesc *bottom; PRPollDesc *pd, *epd; PRInt32 maxfd = -1, ready, err; PRIntervalTime remaining, elapsed, start; struct timeval tv, *tvp = NULL; FD_ZERO(&rd); FD_ZERO(&wt); FD_ZERO(&ex); ready = 0; for (pd = pds, epd = pd + npds; pd < epd; pd++) { PRInt16 in_flags_read = 0, in_flags_write = 0; PRInt16 out_flags_read = 0, out_flags_write = 0; if ((NULL != pd->fd) && (0 != pd->in_flags)) { if (pd->in_flags & PR_POLL_READ) { in_flags_read = (pd->fd->methods->poll)( pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read); } if (pd->in_flags & PR_POLL_WRITE) { in_flags_write = (pd->fd->methods->poll)( pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write); } if ((0 != (in_flags_read & out_flags_read)) || (0 != (in_flags_write & out_flags_write))) { /* this one's ready right now */ if (0 == ready) { /* * We will have to return without calling the * system poll/select function. So zero the * out_flags fields of all the poll descriptors * before this one. */ PRPollDesc *prev; for (prev = pds; prev < pd; prev++) { prev->out_flags = 0; } } ready += 1; pd->out_flags = out_flags_read | out_flags_write; } else { pd->out_flags = 0; /* pre-condition */ /* make sure this is an NSPR supported stack */ bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); PR_ASSERT(NULL != bottom); /* what to do about that? */ if ((NULL != bottom) && (_PR_FILEDESC_OPEN == bottom->secret->state)) { if (0 == ready) { PRInt32 osfd = bottom->secret->md.osfd; if (osfd > maxfd) maxfd = osfd; if (in_flags_read & PR_POLL_READ) { pd->out_flags |= _PR_POLL_READ_SYS_READ; FD_SET(osfd, &rd); } if (in_flags_read & PR_POLL_WRITE) { pd->out_flags |= _PR_POLL_READ_SYS_WRITE; FD_SET(osfd, &wt); } if (in_flags_write & PR_POLL_READ) { pd->out_flags |= _PR_POLL_WRITE_SYS_READ; FD_SET(osfd, &rd); } if (in_flags_write & PR_POLL_WRITE) { pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; FD_SET(osfd, &wt); } if (pd->in_flags & PR_POLL_EXCEPT) FD_SET(osfd, &ex); } } else { if (0 == ready) { PRPollDesc *prev; for (prev = pds; prev < pd; prev++) { prev->out_flags = 0; } } ready += 1; /* this will cause an abrupt return */ pd->out_flags = PR_POLL_NVAL; /* bogii */ } } } else { pd->out_flags = 0; } } if (0 != ready) return ready; /* no need to block */ remaining = timeout; start = PR_IntervalNow(); retry: if (timeout != PR_INTERVAL_NO_TIMEOUT) { PRInt32 ticksPerSecond = PR_TicksPerSecond(); tv.tv_sec = remaining / ticksPerSecond; tv.tv_usec = PR_IntervalToMicroseconds( remaining % ticksPerSecond ); tvp = &tv; } ready = _MD_SELECT(maxfd + 1, &rd, &wt, &ex, tvp); if (ready == -1 && errno == EINTR) { if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry; else { elapsed = (PRIntervalTime) (PR_IntervalNow() - start); if (elapsed > timeout) ready = 0; /* timed out */ else { remaining = timeout - elapsed; goto retry; } } } /* ** Now to unravel the select sets back into the client's poll ** descriptor list. Is this possibly an area for pissing away ** a few cycles or what? */ if (ready > 0) { ready = 0; for (pd = pds, epd = pd + npds; pd < epd; pd++) { PRInt16 out_flags = 0; if ((NULL != pd->fd) && (0 != pd->in_flags)) { PRInt32 osfd; bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); PR_ASSERT(NULL != bottom); osfd = bottom->secret->md.osfd; if (FD_ISSET(osfd, &rd)) { if (pd->out_flags & _PR_POLL_READ_SYS_READ) out_flags |= PR_POLL_READ; if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) out_flags |= PR_POLL_WRITE; } if (FD_ISSET(osfd, &wt)) { if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) out_flags |= PR_POLL_READ; if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) out_flags |= PR_POLL_WRITE; } if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT; } pd->out_flags = out_flags; if (out_flags) ready++; } PR_ASSERT(ready > 0); } else if (ready < 0) { err = _MD_ERRNO(); if (err == EBADF) { /* Find the bad fds */ ready = 0; for (pd = pds, epd = pd + npds; pd < epd; pd++) { pd->out_flags = 0; if ((NULL != pd->fd) && (0 != pd->in_flags)) { bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); if (fcntl(bottom->secret->md.osfd, F_GETFL, 0) == -1) { pd->out_flags = PR_POLL_NVAL; ready++; } } } PR_ASSERT(ready > 0); } else _PR_MD_MAP_SELECT_ERROR(err); } return ready; } /* NativeThreadSelect */
/* * perform netbuf_buf2sd in a timely manner enforcing a timeout handling * the netbuf_grab() that can potentially receive just one char at a time * it can go on for a long time -- potentially leading to tying the thread * resources to the request forever. * * timeout can be PR_INTERVAL_NO_TIMEOUT -- no timeout will be enforced. */ NSAPI_PUBLIC int netbuf_buf2sd_timed(netbuf *buf, SYS_NETFD sd, int len, PRIntervalTime timeout) { register int n = len, t, ns; ns = 0; register PRIntervalTime start = 0; /* Note the starting time */ if (timeout != PR_INTERVAL_NO_TIMEOUT) start = PR_IntervalNow(); /* First, flush the current buffer */ t = buf->cursize - buf->pos; if((n != -1) && (t > n)) t = n; if((t) && (sd != SYS_NET_ERRORFD)) { #if defined(OSF1) || defined(HPUX) || defined(SNI) OSF_label1: #endif if(net_write(sd, (char *)&buf->inbuf[buf->pos], t) == IO_ERROR) { #if defined(OSF1) || defined(HPUX) || defined(SNI) if(errno == EINTR) goto OSF_label1; #endif buf->errmsg = system_errmsg(); return IO_ERROR; } ns += t; } buf->pos += t; if(n != -1) { n -= t; if(!n) return ns; } else t = buf->maxsize; /* Now, keep blasting until done */ while(1) { /* Check to see if this client is taking too long to process */ if (timeout != PR_INTERVAL_NO_TIMEOUT && PR_IntervalNow() > (start + timeout)) { PR_SetError(PR_IO_TIMEOUT_ERROR, 0); buf->errmsg = system_errmsg(); return IO_ERROR; } if(n != -1) t = (n < buf->maxsize ? n : buf->maxsize); #if defined(OSF1) || defined(HPUX) || defined(SNI) OSF_label2: #endif switch(netbuf_grab(buf, t)) { case IO_ERROR: #if defined(OSF1) || defined(HPUX) || defined(SNI) if(errno == EINTR) goto OSF_label2; #endif return IO_ERROR; case IO_EOF: if(n == -1) return ns; else { PR_SetError(PR_END_OF_FILE_ERROR, 0); buf->errmsg = system_errmsg(); return IO_ERROR; } default: if(sd != SYS_NET_ERRORFD) { #if defined(OSF1) || defined(HPUX) OSF_label3: #endif if(net_write(sd, (char *)(buf->inbuf), buf->cursize) == IO_ERROR) { #if defined(OSF1) || defined(HPUX) if(errno == EINTR) goto OSF_label3; #endif buf->errmsg = system_errmsg(); return IO_ERROR; } buf->pos += buf->cursize; ns += buf->cursize; } if(n != -1) { n -= buf->cursize; if(!n) return ns; } break; } } }
/* ** Expire condition variable waits that are ready to expire. "now" is the current ** time. */ void _PR_ClockInterrupt(void) { PRThread *thread, *me = _PR_MD_CURRENT_THREAD(); _PRCPU *cpu = me->cpu; PRIntervalTime elapsed, now; PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); /* Figure out how much time elapsed since the last clock tick */ now = PR_IntervalNow(); elapsed = now - cpu->last_clock; cpu->last_clock = now; #ifndef XP_MAC PR_LOG(_pr_clock_lm, PR_LOG_MAX, ("ExpireWaits: elapsed=%lld usec", elapsed)); #endif while(1) { _PR_SLEEPQ_LOCK(cpu); if (_PR_SLEEPQ(cpu).next == &_PR_SLEEPQ(cpu)) { _PR_SLEEPQ_UNLOCK(cpu); break; } thread = _PR_THREAD_PTR(_PR_SLEEPQ(cpu).next); PR_ASSERT(thread->cpu == cpu); if (elapsed < thread->sleep) { thread->sleep -= elapsed; _PR_SLEEPQMAX(thread->cpu) -= elapsed; _PR_SLEEPQ_UNLOCK(cpu); break; } _PR_SLEEPQ_UNLOCK(cpu); PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread)); _PR_THREAD_LOCK(thread); if (thread->cpu != cpu) { /* ** The thread was switched to another CPU ** between the time we unlocked the sleep ** queue and the time we acquired the thread ** lock, so it is none of our business now. */ _PR_THREAD_UNLOCK(thread); continue; } /* ** Consume this sleeper's amount of elapsed time from the elapsed ** time value. The next remaining piece of elapsed time will be ** available for the next sleeping thread's timer. */ _PR_SLEEPQ_LOCK(cpu); PR_ASSERT(!(thread->flags & _PR_ON_PAUSEQ)); if (thread->flags & _PR_ON_SLEEPQ) { _PR_DEL_SLEEPQ(thread, PR_FALSE); elapsed -= thread->sleep; _PR_SLEEPQ_UNLOCK(cpu); } else { /* Thread was already handled; Go get another one */ _PR_SLEEPQ_UNLOCK(cpu); _PR_THREAD_UNLOCK(thread); continue; } /* Notify the thread waiting on the condition variable */ if (thread->flags & _PR_SUSPENDING) { PR_ASSERT((thread->state == _PR_IO_WAIT) || (thread->state == _PR_COND_WAIT)); /* ** Thread is suspended and its condition timeout ** expired. Transfer thread from sleepQ to suspendQ. */ thread->wait.cvar = NULL; _PR_MISCQ_LOCK(cpu); thread->state = _PR_SUSPENDED; _PR_ADD_SUSPENDQ(thread, cpu); _PR_MISCQ_UNLOCK(cpu); } else { if (thread->wait.cvar) { PRThreadPriority pri; /* Do work very similar to what _PR_NotifyThread does */ PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) ); /* Make thread runnable */ pri = thread->priority; thread->state = _PR_RUNNABLE; PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); PR_ASSERT(thread->cpu == cpu); _PR_RUNQ_LOCK(cpu); _PR_ADD_RUNQ(thread, cpu, pri); _PR_RUNQ_UNLOCK(cpu); if (pri > me->priority) _PR_SET_RESCHED_FLAG(); thread->wait.cvar = NULL; _PR_MD_WAKEUP_WAITER(thread); } else if (thread->io_pending == PR_TRUE) { /* Need to put IO sleeper back on runq */ int pri = thread->priority; thread->io_suspended = PR_TRUE; #ifdef WINNT /* * For NT, record the cpu on which I/O was issued * I/O cancellation is done on the same cpu */ thread->md.thr_bound_cpu = cpu; #endif PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); PR_ASSERT(thread->cpu == cpu); thread->state = _PR_RUNNABLE; _PR_RUNQ_LOCK(cpu); _PR_ADD_RUNQ(thread, cpu, pri); _PR_RUNQ_UNLOCK(cpu); } } _PR_THREAD_UNLOCK(thread); } }
/* queue a job, when a socket is readable or writeable */ static PRJob * queue_io_job(PRThreadPool *tpool, PRJobIoDesc *iod, PRJobFn fn, void * arg, PRBool joinable, io_op_type op) { PRJob *jobp; PRIntervalTime now; jobp = alloc_job(joinable, tpool); if (NULL == jobp) { return NULL; } /* * Add a new job to io_jobq * wakeup io worker thread */ jobp->job_func = fn; jobp->job_arg = arg; jobp->tpool = tpool; jobp->iod = iod; if (JOB_IO_READ == op) { jobp->io_op = JOB_IO_READ; jobp->io_poll_flags = PR_POLL_READ; } else if (JOB_IO_WRITE == op) { jobp->io_op = JOB_IO_WRITE; jobp->io_poll_flags = PR_POLL_WRITE; } else if (JOB_IO_ACCEPT == op) { jobp->io_op = JOB_IO_ACCEPT; jobp->io_poll_flags = PR_POLL_READ; } else if (JOB_IO_CONNECT == op) { jobp->io_op = JOB_IO_CONNECT; jobp->io_poll_flags = PR_POLL_WRITE|PR_POLL_EXCEPT; } else { delete_job(jobp); PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return NULL; } jobp->timeout = iod->timeout; if ((PR_INTERVAL_NO_TIMEOUT == iod->timeout) || (PR_INTERVAL_NO_WAIT == iod->timeout)) { jobp->absolute = iod->timeout; } else { now = PR_IntervalNow(); jobp->absolute = now + iod->timeout; } PR_Lock(tpool->ioq.lock); if (PR_CLIST_IS_EMPTY(&tpool->ioq.list) || (PR_INTERVAL_NO_TIMEOUT == iod->timeout)) { PR_APPEND_LINK(&jobp->links,&tpool->ioq.list); } else if (PR_INTERVAL_NO_WAIT == iod->timeout) { PR_INSERT_LINK(&jobp->links,&tpool->ioq.list); } else { PRCList *qp; PRJob *tmp_jobp; /* * insert into the timeout-sorted ioq */ for (qp = tpool->ioq.list.prev; qp != &tpool->ioq.list; qp = qp->prev) { tmp_jobp = JOB_LINKS_PTR(qp); if ((PRInt32)(jobp->absolute - tmp_jobp->absolute) >= 0) { break; } } PR_INSERT_AFTER(&jobp->links,qp); } jobp->on_ioq = PR_TRUE; tpool->ioq.cnt++; /* * notify io worker thread(s) */ PR_Unlock(tpool->ioq.lock); notify_ioq(tpool); return jobp; }
/* * io worker thread function */ static void io_wstart(void *arg) { PRThreadPool *tp = (PRThreadPool *) arg; int pollfd_cnt, pollfds_used; int rv; PRCList *qp, *nextqp; PRPollDesc *pollfds; PRJob **polljobs; int poll_timeout; PRIntervalTime now; /* * scan io_jobq * construct poll list * call PR_Poll * for all fds, for which poll returns true, move the job to * jobq and wakeup worker thread. */ while (!tp->shutdown) { PRJob *jobp; pollfd_cnt = tp->ioq.cnt + 10; if (pollfd_cnt > tp->ioq.npollfds) { /* * re-allocate pollfd array if the current one is not large * enough */ if (NULL != tp->ioq.pollfds) PR_Free(tp->ioq.pollfds); tp->ioq.pollfds = (PRPollDesc *) PR_Malloc(pollfd_cnt * (sizeof(PRPollDesc) + sizeof(PRJob *))); PR_ASSERT(NULL != tp->ioq.pollfds); /* * array of pollfds */ pollfds = tp->ioq.pollfds; tp->ioq.polljobs = (PRJob **) (&tp->ioq.pollfds[pollfd_cnt]); /* * parallel array of jobs */ polljobs = tp->ioq.polljobs; tp->ioq.npollfds = pollfd_cnt; } pollfds_used = 0; /* * add the notify fd; used for unblocking io thread(s) */ pollfds[pollfds_used].fd = tp->ioq.notify_fd; pollfds[pollfds_used].in_flags = PR_POLL_READ; pollfds[pollfds_used].out_flags = 0; polljobs[pollfds_used] = NULL; pollfds_used++; /* * fill in the pollfd array */ PR_Lock(tp->ioq.lock); for (qp = tp->ioq.list.next; qp != &tp->ioq.list; qp = nextqp) { nextqp = qp->next; jobp = JOB_LINKS_PTR(qp); if (jobp->cancel_io) { CANCEL_IO_JOB(jobp); continue; } if (pollfds_used == (pollfd_cnt)) break; pollfds[pollfds_used].fd = jobp->iod->socket; pollfds[pollfds_used].in_flags = jobp->io_poll_flags; pollfds[pollfds_used].out_flags = 0; polljobs[pollfds_used] = jobp; pollfds_used++; } if (!PR_CLIST_IS_EMPTY(&tp->ioq.list)) { qp = tp->ioq.list.next; jobp = JOB_LINKS_PTR(qp); if (PR_INTERVAL_NO_TIMEOUT == jobp->timeout) poll_timeout = PR_INTERVAL_NO_TIMEOUT; else if (PR_INTERVAL_NO_WAIT == jobp->timeout) poll_timeout = PR_INTERVAL_NO_WAIT; else { poll_timeout = jobp->absolute - PR_IntervalNow(); if (poll_timeout <= 0) /* already timed out */ poll_timeout = PR_INTERVAL_NO_WAIT; } } else { poll_timeout = PR_INTERVAL_NO_TIMEOUT; } PR_Unlock(tp->ioq.lock); /* * XXXX * should retry if more jobs have been added to the queue? * */ PR_ASSERT(pollfds_used <= pollfd_cnt); rv = PR_Poll(tp->ioq.pollfds, pollfds_used, poll_timeout); if (tp->shutdown) { break; } if (rv > 0) { /* * at least one io event is set */ PRStatus rval_status; PRInt32 index; PR_ASSERT(pollfds[0].fd == tp->ioq.notify_fd); /* * reset the pollable event, if notified */ if (pollfds[0].out_flags & PR_POLL_READ) { rval_status = PR_WaitForPollableEvent(tp->ioq.notify_fd); PR_ASSERT(PR_SUCCESS == rval_status); } for(index = 1; index < (pollfds_used); index++) { PRInt16 events = pollfds[index].in_flags; PRInt16 revents = pollfds[index].out_flags; jobp = polljobs[index]; if ((revents & PR_POLL_NVAL) || /* busted in all cases */ (revents & PR_POLL_ERR) || ((events & PR_POLL_WRITE) && (revents & PR_POLL_HUP))) { /* write op & hup */ PR_Lock(tp->ioq.lock); if (jobp->cancel_io) { CANCEL_IO_JOB(jobp); PR_Unlock(tp->ioq.lock); continue; } PR_REMOVE_AND_INIT_LINK(&jobp->links); tp->ioq.cnt--; jobp->on_ioq = PR_FALSE; PR_Unlock(tp->ioq.lock); /* set error */ if (PR_POLL_NVAL & revents) jobp->iod->error = PR_BAD_DESCRIPTOR_ERROR; else if (PR_POLL_HUP & revents) jobp->iod->error = PR_CONNECT_RESET_ERROR; else jobp->iod->error = PR_IO_ERROR; /* * add to jobq */ add_to_jobq(tp, jobp); } else if (revents) { /* * add to jobq */ PR_Lock(tp->ioq.lock); if (jobp->cancel_io) { CANCEL_IO_JOB(jobp); PR_Unlock(tp->ioq.lock); continue; } PR_REMOVE_AND_INIT_LINK(&jobp->links); tp->ioq.cnt--; jobp->on_ioq = PR_FALSE; PR_Unlock(tp->ioq.lock); if (jobp->io_op == JOB_IO_CONNECT) { if (PR_GetConnectStatus(&pollfds[index]) == PR_SUCCESS) jobp->iod->error = 0; else jobp->iod->error = PR_GetError(); } else jobp->iod->error = 0; add_to_jobq(tp, jobp); } } } /* * timeout processing */ now = PR_IntervalNow(); PR_Lock(tp->ioq.lock); for (qp = tp->ioq.list.next; qp != &tp->ioq.list; qp = nextqp) { nextqp = qp->next; jobp = JOB_LINKS_PTR(qp); if (jobp->cancel_io) { CANCEL_IO_JOB(jobp); continue; } if (PR_INTERVAL_NO_TIMEOUT == jobp->timeout) break; if ((PR_INTERVAL_NO_WAIT != jobp->timeout) && ((PRInt32)(jobp->absolute - now) > 0)) break; PR_REMOVE_AND_INIT_LINK(&jobp->links); tp->ioq.cnt--; jobp->on_ioq = PR_FALSE; jobp->iod->error = PR_IO_TIMEOUT_ERROR; add_to_jobq(tp, jobp); } PR_Unlock(tp->ioq.lock); } }
static void PR_CALLBACK Server(void *arg) { PRStatus rv; PRNetAddr serverAddress; PRThread *me = PR_GetCurrentThread(); CSServer_t *server = (CSServer_t*)arg; PRSocketOptionData sockOpt; server->listener = PR_Socket(domain, SOCK_STREAM, protocol); sockOpt.option = PR_SockOpt_Reuseaddr; sockOpt.value.reuse_addr = PR_TRUE; rv = PR_SetSocketOption(server->listener, &sockOpt); TEST_ASSERT(PR_SUCCESS == rv); memset(&serverAddress, 0, sizeof(serverAddress)); if (PR_AF_INET6 != domain) rv = PR_InitializeNetAddr(PR_IpAddrAny, DEFAULT_PORT, &serverAddress); else rv = PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, DEFAULT_PORT, &serverAddress); rv = PR_Bind(server->listener, &serverAddress); TEST_ASSERT(PR_SUCCESS == rv); rv = PR_Listen(server->listener, server->backlog); TEST_ASSERT(PR_SUCCESS == rv); server->started = PR_IntervalNow(); TimeOfDayMessage("Server started at", me); PR_Lock(server->ml); server->state = cs_run; PR_NotifyCondVar(server->stateChange); PR_Unlock(server->ml); /* ** Create the first worker (actually, a thread that accepts ** connections and then processes the work load as needed). ** From this point on, additional worker threads are created ** as they are needed by existing worker threads. */ rv = CreateWorker(server, &server->pool); TEST_ASSERT(PR_SUCCESS == rv); /* ** From here on this thread is merely hanging around as the contact ** point for the main test driver. It's just waiting for the driver ** to declare the test complete. */ TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, ("\tServer(0x%p): waiting for state change\n", me)); PR_Lock(server->ml); while ((cs_run == server->state) && !Aborted(rv)) { rv = PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT); } PR_Unlock(server->ml); PR_ClearInterrupt(); TEST_LOG( cltsrv_log_file, TEST_LOG_INFO, ("\tServer(0x%p): shutting down workers\n", me)); /* ** Get all the worker threads to exit. They know how to ** clean up after themselves, so this is just a matter of ** waiting for clorine in the pool to take effect. During ** this stage we're ignoring interrupts. */ server->workers.minimum = server->workers.maximum = 0; PR_Lock(server->ml); while (!PR_CLIST_IS_EMPTY(&server->list)) { PRCList *head = PR_LIST_HEAD(&server->list); CSWorker_t *worker = (CSWorker_t*)head; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, ("\tServer(0x%p): interrupting worker(0x%p)\n", me, worker)); rv = PR_Interrupt(worker->thread); TEST_ASSERT(PR_SUCCESS == rv); PR_REMOVE_AND_INIT_LINK(head); } while (server->pool.workers > 0) { TEST_LOG( cltsrv_log_file, TEST_LOG_NOTICE, ("\tServer(0x%p): waiting for %u workers to exit\n", me, server->pool.workers)); (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT); } server->state = cs_exit; PR_NotifyCondVar(server->stateChange); PR_Unlock(server->ml); TEST_LOG( cltsrv_log_file, TEST_LOG_ALWAYS, ("\tServer(0x%p): stopped after %u operations and %u bytes\n", me, server->operations, server->bytesTransferred)); if (NULL != server->listener) PR_Close(server->listener); server->stopped = PR_IntervalNow(); } /* Server */
static void PR_CALLBACK Client(void *arg) { PRStatus rv; PRIntn index; char buffer[1024]; PRFileDesc *fd = NULL; PRUintn clipping = DEFAULT_CLIPPING; PRThread *me = PR_GetCurrentThread(); CSClient_t *client = (CSClient_t*)arg; CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t); PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_CLIENT_TIMEOUT); for (index = 0; index < sizeof(buffer); ++index) buffer[index] = (char)index; client->started = PR_IntervalNow(); PR_Lock(client->ml); client->state = cs_run; PR_NotifyCondVar(client->stateChange); PR_Unlock(client->ml); TimeOfDayMessage("Client started at", me); while (cs_run == client->state) { PRInt32 bytes, descbytes, filebytes, netbytes; (void)PR_NetAddrToString(&client->serverAddress, buffer, sizeof(buffer)); TEST_LOG(cltsrv_log_file, TEST_LOG_INFO, ("\tClient(0x%p): connecting to server at %s\n", me, buffer)); fd = PR_Socket(domain, SOCK_STREAM, protocol); TEST_ASSERT(NULL != fd); rv = PR_Connect(fd, &client->serverAddress, timeout); if (PR_FAILURE == rv) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\tClient(0x%p): conection failed (%d, %d)\n", me, PR_GetError(), PR_GetOSError())); goto aborted; } memset(descriptor, 0, sizeof(*descriptor)); descriptor->size = PR_htonl(descbytes = rand() % clipping); PR_snprintf( descriptor->filename, sizeof(descriptor->filename), "CS%p%p-%p.dat", client->started, me, client->operations); TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, ("\tClient(0x%p): sending descriptor for %u bytes\n", me, descbytes)); bytes = PR_Send( fd, descriptor, sizeof(*descriptor), SEND_FLAGS, timeout); if (sizeof(CSDescriptor_t) != bytes) { if (Aborted(PR_FAILURE)) goto aborted; if (PR_IO_TIMEOUT_ERROR == PR_GetError()) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\tClient(0x%p): send descriptor timeout\n", me)); goto retry; } } TEST_ASSERT(sizeof(*descriptor) == bytes); netbytes = 0; while (netbytes < descbytes) { filebytes = sizeof(buffer); if ((descbytes - netbytes) < filebytes) filebytes = descbytes - netbytes; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, ("\tClient(0x%p): sending %d bytes\n", me, filebytes)); bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout); if (filebytes != bytes) { if (Aborted(PR_FAILURE)) goto aborted; if (PR_IO_TIMEOUT_ERROR == PR_GetError()) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\tClient(0x%p): send data timeout\n", me)); goto retry; } } TEST_ASSERT(bytes == filebytes); netbytes += bytes; } filebytes = 0; while (filebytes < descbytes) { netbytes = sizeof(buffer); if ((descbytes - filebytes) < netbytes) netbytes = descbytes - filebytes; TEST_LOG( cltsrv_log_file, TEST_LOG_VERBOSE, ("\tClient(0x%p): receiving %d bytes\n", me, netbytes)); bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout); if (-1 == bytes) { if (Aborted(PR_FAILURE)) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\tClient(0x%p): receive data aborted\n", me)); goto aborted; } else if (PR_IO_TIMEOUT_ERROR == PR_GetError()) TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\tClient(0x%p): receive data timeout\n", me)); else TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\tClient(0x%p): receive error (%d, %d)\n", me, PR_GetError(), PR_GetOSError())); goto retry; } if (0 == bytes) { TEST_LOG( cltsrv_log_file, TEST_LOG_ERROR, ("\t\tClient(0x%p): unexpected end of stream\n", PR_GetCurrentThread())); break; } filebytes += bytes; } rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH); if (Aborted(rv)) goto aborted; TEST_ASSERT(PR_SUCCESS == rv); retry: (void)PR_Close(fd); fd = NULL; TEST_LOG( cltsrv_log_file, TEST_LOG_INFO, ("\tClient(0x%p): disconnected from server\n", me)); PR_Lock(client->ml); client->operations += 1; client->bytesTransferred += 2 * descbytes; rv = PR_WaitCondVar(client->stateChange, rand() % clipping); PR_Unlock(client->ml); if (Aborted(rv)) break; } aborted: client->stopped = PR_IntervalNow(); PR_ClearInterrupt(); if (NULL != fd) rv = PR_Close(fd); PR_Lock(client->ml); client->state = cs_exit; PR_NotifyCondVar(client->stateChange); PR_Unlock(client->ml); PR_DELETE(descriptor); TEST_LOG( cltsrv_log_file, TEST_LOG_ALWAYS, ("\tClient(0x%p): stopped after %u operations and %u bytes\n", PR_GetCurrentThread(), client->operations, client->bytesTransferred)); } /* Client */
void ThreadMain(void*) { PR_SetCurrentThreadName("Hang Monitor"); MonitorAutoLock lock(*gMonitor); // In order to avoid issues with the hang monitor incorrectly triggering // during a general system stop such as sleeping, the monitor thread must // run twice to trigger hang protection. PRIntervalTime lastTimestamp = 0; int waitCount = 0; #ifdef REPORT_CHROME_HANGS Telemetry::ProcessedStack stack; #endif while (true) { if (gShutdown) { return; // Exit the thread } // avoid rereading the volatile value in this loop PRIntervalTime timestamp = gTimestamp; PRIntervalTime now = PR_IntervalNow(); if (timestamp != PR_INTERVAL_NO_WAIT && now < timestamp) { // 32-bit overflow, reset for another waiting period timestamp = 1; // lowest legal PRInterval value } if (timestamp != PR_INTERVAL_NO_WAIT && timestamp == lastTimestamp && gTimeout > 0) { ++waitCount; if (waitCount == 2) { #ifdef REPORT_CHROME_HANGS GetChromeHangReport(stack); #else int32_t delay = int32_t(PR_IntervalToSeconds(now - timestamp)); if (delay > gTimeout) { MonitorAutoUnlock unlock(*gMonitor); Crash(); } #endif } } else { #ifdef REPORT_CHROME_HANGS if (waitCount >= 2) { uint32_t hangDuration = PR_IntervalToSeconds(now - lastTimestamp); Telemetry::RecordChromeHang(hangDuration, stack); stack.Clear(); } #endif lastTimestamp = timestamp; waitCount = 0; } PRIntervalTime timeout; if (gTimeout <= 0) { timeout = PR_INTERVAL_NO_TIMEOUT; } else { timeout = PR_MillisecondsToInterval(gTimeout * 500); } lock.Wait(timeout); } }
/*********************************************************************** ** PRIVATE FUNCTION: main ** DESCRIPTION: ** Hammer on the file I/O system ** INPUTS: The usual argc and argv ** argv[0] - program name (not used) ** argv[1] - the number of times to execute the major loop ** argv[2] - the number of threads to toss into the batch ** argv[3] - the clipping number applied to randoms ** default values: loops = 2, threads = 10, limit = 57 ** OUTPUTS: None ** RETURN: None ** SIDE EFFECTS: ** Creates, accesses and deletes lots of files ** RESTRICTIONS: ** (Currently) must have file create permission in "/usr/tmp". ** MEMORY: NA ** ALGORITHM: ** 1) Fork a "Thread()" ** 2) Wait for 'interleave' seconds ** 3) For [0..'threads') repeat [1..2] ** 4) Mark all objects to stop ** 5) Collect the threads, accumulating the results ** 6) For [0..'loops') repeat [1..5] ** 7) Print accumulated results and exit ** ** Characteristic output (from IRIX) ** Random File: Using loops = 2, threads = 10, limit = 57 ** Random File: [min [avg] max] writes/sec average ***********************************************************************/ int main (int argc, char *argv[]) { PRLock *ml; PRUint32 id = 0; int active, poll; PRIntervalTime interleave; PRIntervalTime duration = 0; int limit = 0, loops = 0, threads = 0, times; PRUint32 writes, writesMin = 0x7fffffff, writesTot = 0, durationTot = 0, writesMax = 0; const char *where[] = {"okay", "open", "close", "delete", "write", "seek"}; /* The command line argument: -d is used to determine if the test is being run in debug mode. The regress tool requires only one line output:PASS or FAIL. All of the printfs associated with this test has been handled with a if (debug_mode) test. Usage: test_name -d */ PLOptStatus os; PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:t:i:"); while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { if (PL_OPT_BAD == os) continue; switch (opt->option) { case 'G': /* global threads */ thread_scope = PR_GLOBAL_THREAD; break; case 'd': /* debug mode */ debug_mode = 1; break; case 'l': /* limiting number */ limit = atoi(opt->value); break; case 't': /* number of threads */ threads = atoi(opt->value); break; case 'i': /* iteration counter */ loops = atoi(opt->value); break; default: break; } } PL_DestroyOptState(opt); /* main test */ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); PR_STDIO_INIT(); interleave = PR_SecondsToInterval(10); #ifdef XP_MAC SetupMacPrintfLog("ranfile.log"); debug_mode = 1; #endif ml = PR_NewLock(); cv = PR_NewCondVar(ml); if (loops == 0) loops = DEFAULT_LOOPS; if (limit == 0) limit = DEFAULT_LIMIT; if (threads == 0) threads = DEFAULT_THREADS; if (debug_mode) printf( "%s: Using loops = %d, threads = %d, limit = %d and %s threads\n", programName, loops, threads, limit, (thread_scope == PR_LOCAL_THREAD) ? "LOCAL" : "GLOBAL"); for (times = 0; times < loops; ++times) { if (debug_mode) printf("%s: Setting concurrency level to %d\n", programName, times + 1); PR_SetConcurrency(times + 1); for (active = 0; active < threads; active++) { hammer[active].ml = ml; hammer[active].cv = cv; hammer[active].id = id++; hammer[active].writes = 0; hammer[active].action = sg_go; hammer[active].problem = sg_okay; hammer[active].limit = (Random() % limit) + 1; hammer[active].timein = PR_IntervalNow(); hammer[active].thread = PR_CreateThread( PR_USER_THREAD, Thread, &hammer[active], PR_GetThreadPriority(PR_GetCurrentThread()), thread_scope, PR_JOINABLE_THREAD, 0); PR_Lock(ml); PR_WaitCondVar(cv, interleave); /* start new ones slowly */ PR_Unlock(ml); } /* * The last thread started has had the opportunity to run for * 'interleave' seconds. Now gather them all back in. */ PR_Lock(ml); for (poll = 0; poll < threads; poll++) { if (hammer[poll].action == sg_go) /* don't overwrite done */ hammer[poll].action = sg_stop; /* ask him to stop */ } PR_Unlock(ml); while (active > 0) { for (poll = 0; poll < threads; poll++) { PR_Lock(ml); while (hammer[poll].action < sg_done) PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); PR_Unlock(ml); active -= 1; /* this is another one down */ (void)PR_JoinThread(hammer[poll].thread); hammer[poll].thread = NULL; if (hammer[poll].problem == sg_okay) { duration = PR_IntervalToMilliseconds( PR_IntervalNow() - hammer[poll].timein); writes = hammer[poll].writes * 1000 / duration; if (writes < writesMin) writesMin = writes; if (writes > writesMax) writesMax = writes; writesTot += hammer[poll].writes; durationTot += duration; } else if (debug_mode) printf( "%s: test failed %s after %ld seconds\n", programName, where[hammer[poll].problem], duration); else failed_already=1; } } } if (debug_mode) printf( "%s: [%ld [%ld] %ld] writes/sec average\n", programName, writesMin, writesTot * 1000 / durationTot, writesMax); PR_DestroyCondVar(cv); PR_DestroyLock(ml); if (failed_already) { printf("FAIL\n"); return 1; } else { printf("PASS\n"); return 0; } } /* main */
PR_QueueJob_Timer(PRThreadPool *tpool, PRIntervalTime timeout, PRJobFn fn, void * arg, PRBool joinable) { PRIntervalTime now; PRJob *jobp; if (PR_INTERVAL_NO_TIMEOUT == timeout) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return NULL; } if (PR_INTERVAL_NO_WAIT == timeout) { /* * no waiting; add to jobq right away */ return(PR_QueueJob(tpool, fn, arg, joinable)); } jobp = alloc_job(joinable, tpool); if (NULL == jobp) { return NULL; } /* * Add a new job to timer_jobq * wakeup timer worker thread */ jobp->job_func = fn; jobp->job_arg = arg; jobp->tpool = tpool; jobp->timeout = timeout; now = PR_IntervalNow(); jobp->absolute = now + timeout; PR_Lock(tpool->timerq.lock); jobp->on_timerq = PR_TRUE; if (PR_CLIST_IS_EMPTY(&tpool->timerq.list)) PR_APPEND_LINK(&jobp->links,&tpool->timerq.list); else { PRCList *qp; PRJob *tmp_jobp; /* * insert into the sorted timer jobq */ for (qp = tpool->timerq.list.prev; qp != &tpool->timerq.list; qp = qp->prev) { tmp_jobp = JOB_LINKS_PTR(qp); if ((PRInt32)(jobp->absolute - tmp_jobp->absolute) >= 0) { break; } } PR_INSERT_AFTER(&jobp->links,qp); } tpool->timerq.cnt++; /* * notify timer worker thread(s) */ notify_timerq(tpool); PR_Unlock(tpool->timerq.lock); return jobp; }
void ServiceWorkerRegistrationInfo::RefreshLastUpdateCheckTime() { AssertIsOnMainThread(); mLastUpdateCheckTime = PR_IntervalNow() / PR_MSEC_PER_SEC; }
PRIntn PR_CALLBACK Switch(PRIntn argc, char **argv) { PLOptStatus os; PRStatus status; PRBool help = PR_FALSE; PRUintn concurrency = 1; Shared *shared, *link; PRIntervalTime timein, timeout; PRThreadScope thread_scope = PR_LOCAL_THREAD; PRUintn thread_count, inner_count, loop_count, average; PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS; PLOptState *opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G"); while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { if (PL_OPT_BAD == os) continue; switch (opt->option) { case 'v': /* verbose mode */ verbosity = PR_TRUE; case 'd': /* debug mode */ debug_mode = PR_TRUE; break; case 'c': /* loop counter */ loop_limit = atoi(opt->value); break; case 't': /* thread limit */ thread_limit = atoi(opt->value); break; case 'C': /* Concurrency limit */ concurrency = atoi(opt->value); break; case 'G': /* global threads only */ thread_scope = PR_GLOBAL_THREAD; break; case 'h': /* help message */ Help(); help = PR_TRUE; break; default: break; } } PL_DestroyOptState(opt); if (help) return -1; if (PR_TRUE == debug_mode) { debug_out = PR_STDOUT; PR_fprintf(debug_out, "Test parameters\n"); PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit); PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit); PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency); PR_fprintf( debug_out, "\tThread type: %s\n", (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL"); } PR_SetConcurrency(concurrency); link = &home; home.ml = PR_NewLock(); home.cv = PR_NewCondVar(home.ml); home.twiddle = PR_FALSE; home.next = NULL; timeout = 0; for (thread_count = 1; thread_count <= thread_limit; ++thread_count) { shared = PR_NEWZAP(Shared); shared->ml = home.ml; shared->cv = PR_NewCondVar(home.ml); shared->twiddle = PR_TRUE; shared->next = link; link = shared; shared->thread = PR_CreateThread( PR_USER_THREAD, Notified, shared, PR_PRIORITY_HIGH, thread_scope, PR_JOINABLE_THREAD, 0); PR_ASSERT(shared->thread != NULL); if (NULL == shared->thread) failed = PR_TRUE; } for (loop_count = 1; loop_count <= loop_limit; ++loop_count) { timein = PR_IntervalNow(); for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count) { PR_Lock(home.ml); home.twiddle = PR_TRUE; shared->twiddle = PR_FALSE; PR_NotifyCondVar(shared->cv); while (home.twiddle) { status = PR_WaitCondVar(home.cv, PR_INTERVAL_NO_TIMEOUT); if (PR_FAILURE == status) failed = PR_TRUE; } PR_Unlock(home.ml); } timeout += (PR_IntervalNow() - timein); } if (debug_mode) { average = PR_IntervalToMicroseconds(timeout) / (INNER_LOOPS * loop_limit * thread_count); PR_fprintf( debug_out, "Average switch times %d usecs for %d threads\n", average, thread_limit); } link = shared; for (thread_count = 1; thread_count <= thread_limit; ++thread_count) { if (&home == link) break; status = PR_Interrupt(link->thread); if (PR_SUCCESS != status) { failed = PR_TRUE; if (debug_mode) PL_FPrintError(debug_out, "Failed to interrupt"); } link = link->next; } for (thread_count = 1; thread_count <= thread_limit; ++thread_count) { link = shared->next; status = PR_JoinThread(shared->thread); if (PR_SUCCESS != status) { failed = PR_TRUE; if (debug_mode) PL_FPrintError(debug_out, "Failed to join"); } PR_DestroyCondVar(shared->cv); PR_DELETE(shared); if (&home == link) break; shared = link; } PR_DestroyCondVar(home.cv); PR_DestroyLock(home.ml); PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n")); return ((failed) ? 1 : 0); } /* Switch */
/* void Run(); */ NS_IMETHODIMP TimerThread::Run() { nsAutoLock lock(mLock); while (!mShutdown) { PRIntervalTime waitFor; if (mSleeping) { // Sleep for 0.1 seconds while not firing timers. waitFor = PR_MillisecondsToInterval(100); } else { waitFor = PR_INTERVAL_NO_TIMEOUT; PRIntervalTime now = PR_IntervalNow(); nsTimerImpl *timer = nsnull; if (mTimers.Count() > 0) { timer = static_cast<nsTimerImpl*>(mTimers[0]); if (!TIMER_LESS_THAN(now, timer->mTimeout + mTimeoutAdjustment)) { next: // NB: AddRef before the Release under RemoveTimerInternal to avoid // mRefCnt passing through zero, in case all other refs than the one // from mTimers have gone away (the last non-mTimers[i]-ref's Release // must be racing with us, blocked in gThread->RemoveTimer waiting // for TimerThread::mLock, under nsTimerImpl::Release. NS_ADDREF(timer); RemoveTimerInternal(timer); // We release mLock around the Fire call to avoid deadlock. lock.unlock(); #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { PR_LOG(gTimerLog, PR_LOG_DEBUG, ("Timer thread woke up %dms from when it was supposed to\n", (now >= timer->mTimeout) ? PR_IntervalToMilliseconds(now - timer->mTimeout) : -(PRInt32)PR_IntervalToMilliseconds(timer->mTimeout-now)) ); } #endif // We are going to let the call to PostTimerEvent here handle the // release of the timer so that we don't end up releasing the timer // on the TimerThread instead of on the thread it targets. if (NS_FAILED(timer->PostTimerEvent())) { nsrefcnt rc; NS_RELEASE2(timer, rc); // The nsITimer interface requires that its users keep a reference // to the timers they use while those timers are initialized but // have not yet fired. If this ever happens, it is a bug in the // code that created and used the timer. // // Further, note that this should never happen even with a // misbehaving user, because nsTimerImpl::Release checks for a // refcount of 1 with an armed timer (a timer whose only reference // is from the timer thread) and when it hits this will remove the // timer from the timer thread and thus destroy the last reference, // preventing this situation from occurring. NS_ASSERTION(rc != 0, "destroyed timer off its target thread!"); } timer = nsnull; lock.lock(); if (mShutdown) break; // Update now, as PostTimerEvent plus the locking may have taken a // tick or two, and we may goto next below. now = PR_IntervalNow(); } } if (mTimers.Count() > 0) { timer = static_cast<nsTimerImpl *>(mTimers[0]); PRIntervalTime timeout = timer->mTimeout + mTimeoutAdjustment; // Don't wait at all (even for PR_INTERVAL_NO_WAIT) if the next timer // is due now or overdue. if (!TIMER_LESS_THAN(now, timeout)) goto next; waitFor = timeout - now; } #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { if (waitFor == PR_INTERVAL_NO_TIMEOUT) PR_LOG(gTimerLog, PR_LOG_DEBUG, ("waiting for PR_INTERVAL_NO_TIMEOUT\n")); else PR_LOG(gTimerLog, PR_LOG_DEBUG, ("waiting for %u\n", PR_IntervalToMilliseconds(waitFor))); } #endif } mWaiting = PR_TRUE; PR_WaitCondVar(mCondVar, waitFor); mWaiting = PR_FALSE; } return NS_OK; }
static void PR_CALLBACK Clientel(void *arg) { PRStatus rv; PRFileDesc *xport; PRInt32 bytes, sampled; PRIntervalTime now, interval; PRBool do_display = PR_FALSE; Shared *shared = (Shared*)arg; char *buffer = (char*)PR_Malloc(buffer_size); PRNetAddr *server_address = &shared->server_address; PRIntervalTime connect_timeout = PR_SecondsToInterval(5); PRIntervalTime sampling_interval = PR_SecondsToInterval(SAMPLING_INTERVAL); PR_fprintf(err, "Client connecting to "); (void)PrintAddress(server_address); do { xport = PR_Socket(domain, PR_SOCK_STREAM, protocol); if (NULL == xport) { PL_FPrintError(err, "PR_Socket"); return; } if (xport_buffer != -1) { PRSocketOptionData data; data.option = PR_SockOpt_RecvBufferSize; data.value.recv_buffer_size = (PRSize)xport_buffer; rv = PR_SetSocketOption(xport, &data); if (PR_FAILURE == rv) PL_FPrintError(err, "PR_SetSocketOption - ignored"); data.option = PR_SockOpt_SendBufferSize; data.value.send_buffer_size = (PRSize)xport_buffer; rv = PR_SetSocketOption(xport, &data); if (PR_FAILURE == rv) PL_FPrintError(err, "PR_SetSocketOption - ignored"); } rv = PR_Connect(xport, server_address, connect_timeout); if (PR_FAILURE == rv) { PL_FPrintError(err, "PR_Connect"); if (PR_IO_TIMEOUT_ERROR != PR_GetError()) PR_Sleep(connect_timeout); PR_Close(xport); /* delete it and start over */ } } while (PR_FAILURE == rv); do { bytes = PR_Recv( xport, buffer, buffer_size, 0, PR_INTERVAL_NO_TIMEOUT); PR_Lock(shared->ml); now = PR_IntervalNow(); shared->sampled += bytes; interval = now - shared->timein; if (interval > sampling_interval) { sampled = shared->sampled; shared->timein = now; shared->sampled = 0; do_display = PR_TRUE; } PR_Unlock(shared->ml); if (do_display) { PRUint32 rate = sampled / PR_IntervalToMilliseconds(interval); PR_fprintf(err, "%u streams @ %u Kbytes/sec\n", shared->threads, rate); do_display = PR_FALSE; } } while (bytes > 0); } /* Clientel */
static PRInt32 NativeThreadPoll( PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) { /* * This function is mostly duplicated from ptio.s's PR_Poll(). */ PRInt32 ready = 0; /* * For restarting poll() if it is interrupted by a signal. * We use these variables to figure out how much time has * elapsed and how much of the timeout still remains. */ PRIntn index, msecs; struct pollfd *syspoll = NULL; PRIntervalTime start, elapsed, remaining; syspoll = (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd)); if (NULL == syspoll) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return -1; } for (index = 0; index < npds; ++index) { PRFileDesc *bottom; PRInt16 in_flags_read = 0, in_flags_write = 0; PRInt16 out_flags_read = 0, out_flags_write = 0; if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) { if (pds[index].in_flags & PR_POLL_READ) { in_flags_read = (pds[index].fd->methods->poll)( pds[index].fd, pds[index].in_flags & ~PR_POLL_WRITE, &out_flags_read); } if (pds[index].in_flags & PR_POLL_WRITE) { in_flags_write = (pds[index].fd->methods->poll)( pds[index].fd, pds[index].in_flags & ~PR_POLL_READ, &out_flags_write); } if ((0 != (in_flags_read & out_flags_read)) || (0 != (in_flags_write & out_flags_write))) { /* this one is ready right now */ if (0 == ready) { /* * We will return without calling the system * poll function. So zero the out_flags * fields of all the poll descriptors before * this one. */ int i; for (i = 0; i < index; i++) { pds[i].out_flags = 0; } } ready += 1; pds[index].out_flags = out_flags_read | out_flags_write; } else { pds[index].out_flags = 0; /* pre-condition */ /* now locate the NSPR layer at the bottom of the stack */ bottom = PR_GetIdentitiesLayer(pds[index].fd, PR_NSPR_IO_LAYER); PR_ASSERT(NULL != bottom); /* what to do about that? */ if ((NULL != bottom) && (_PR_FILEDESC_OPEN == bottom->secret->state)) { if (0 == ready) { syspoll[index].fd = bottom->secret->md.osfd; syspoll[index].events = 0; /* pre-condition */ if (in_flags_read & PR_POLL_READ) { pds[index].out_flags |= _PR_POLL_READ_SYS_READ; syspoll[index].events |= POLLIN; } if (in_flags_read & PR_POLL_WRITE) { pds[index].out_flags |= _PR_POLL_READ_SYS_WRITE; syspoll[index].events |= POLLOUT; } if (in_flags_write & PR_POLL_READ) { pds[index].out_flags |= _PR_POLL_WRITE_SYS_READ; syspoll[index].events |= POLLIN; } if (in_flags_write & PR_POLL_WRITE) { pds[index].out_flags |= _PR_POLL_WRITE_SYS_WRITE; syspoll[index].events |= POLLOUT; } if (pds[index].in_flags & PR_POLL_EXCEPT) syspoll[index].events |= POLLPRI; } } else { if (0 == ready) { int i; for (i = 0; i < index; i++) { pds[i].out_flags = 0; } } ready += 1; /* this will cause an abrupt return */ pds[index].out_flags = PR_POLL_NVAL; /* bogii */ } } } else { /* make poll() ignore this entry */ syspoll[index].fd = -1; syspoll[index].events = 0; pds[index].out_flags = 0; } } if (0 == ready) { switch (timeout) { case PR_INTERVAL_NO_WAIT: msecs = 0; break; case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break; default: msecs = PR_IntervalToMilliseconds(timeout); start = PR_IntervalNow(); } retry: ready = _MD_POLL(syspoll, npds, msecs); if (-1 == ready) { PRIntn oserror = errno; if (EINTR == oserror) { if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry; else if (timeout == PR_INTERVAL_NO_WAIT) ready = 0; else { elapsed = (PRIntervalTime)(PR_IntervalNow() - start); if (elapsed > timeout) ready = 0; /* timed out */ else { remaining = timeout - elapsed; msecs = PR_IntervalToMilliseconds(remaining); goto retry; } } } else _PR_MD_MAP_POLL_ERROR(oserror); } else if (ready > 0) { for (index = 0; index < npds; ++index) { PRInt16 out_flags = 0; if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) { if (0 != syspoll[index].revents) { /* ** Set up the out_flags so that it contains the ** bits that the highest layer thinks are nice ** to have. Then the client of that layer will ** call the appropriate I/O function and maybe ** the protocol will make progress. */ if (syspoll[index].revents & POLLIN) { if (pds[index].out_flags & _PR_POLL_READ_SYS_READ) { out_flags |= PR_POLL_READ; } if (pds[index].out_flags & _PR_POLL_WRITE_SYS_READ) { out_flags |= PR_POLL_WRITE; } } if (syspoll[index].revents & POLLOUT) { if (pds[index].out_flags & _PR_POLL_READ_SYS_WRITE) { out_flags |= PR_POLL_READ; } if (pds[index].out_flags & _PR_POLL_WRITE_SYS_WRITE) { out_flags |= PR_POLL_WRITE; } } if (syspoll[index].revents & POLLPRI) out_flags |= PR_POLL_EXCEPT; if (syspoll[index].revents & POLLERR) out_flags |= PR_POLL_ERR; if (syspoll[index].revents & POLLNVAL) out_flags |= PR_POLL_NVAL; if (syspoll[index].revents & POLLHUP) out_flags |= PR_POLL_HUP; } } pds[index].out_flags = out_flags; } } } PR_DELETE(syspoll); return ready; } /* NativeThreadPoll */
/* * Socket_Misc_Test - test miscellaneous functions * */ static PRInt32 Socket_Misc_Test(void) { PRIntn i, rv = 0, bytes, count, len; PRThread *t; PRThreadScope scope; PRSemaphore *server_sem; Server_Param *sparamp; Client_Param *cparamp; PRMonitor *mon2; PRInt32 datalen; /* * We deliberately pick a buffer size that is not a nice multiple * of 1024. */ #define TRANSMITFILE_BUF_SIZE (4 * 1024 - 11) typedef struct { char data[TRANSMITFILE_BUF_SIZE]; } file_buf; file_buf *buf = NULL; /* * create file(s) to be transmitted */ if ((PR_MkDir(TEST_DIR, 0777)) < 0) { printf("prsocket_test failed to create dir %s\n",TEST_DIR); failed_already=1; return -1; } small_file_fd = PR_Open(SMALL_FILE_NAME, PR_RDWR | PR_CREATE_FILE,0777); if (small_file_fd == NULL) { fprintf(stderr,"prsocket_test failed to create/open file %s\n", SMALL_FILE_NAME); failed_already=1; rv = -1; goto done; } buf = PR_NEW(file_buf); if (buf == NULL) { fprintf(stderr,"prsocket_test failed to allocate buffer\n"); failed_already=1; rv = -1; goto done; } /* * fill in random data */ for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) { buf->data[i] = i; } count = 0; do { len = (SMALL_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE ? TRANSMITFILE_BUF_SIZE : (SMALL_FILE_SIZE - count); bytes = PR_Write(small_file_fd, buf->data, len); if (bytes <= 0) { fprintf(stderr, "prsocket_test failed to write to file %s\n", SMALL_FILE_NAME); failed_already=1; rv = -1; goto done; } count += bytes; } while (count < SMALL_FILE_SIZE); #ifdef XP_UNIX /* * map the small file; used in checking for data corruption */ small_file_addr = mmap(0, SMALL_FILE_SIZE, PROT_READ, MAP_PRIVATE, small_file_fd->secret->md.osfd, 0); if (small_file_addr == (void *) -1) { fprintf(stderr,"prsocket_test failed to mmap file %s\n", SMALL_FILE_NAME); failed_already=1; rv = -1; goto done; } #endif /* * header for small file */ small_file_header = PR_MALLOC(SMALL_FILE_HEADER_SIZE); if (small_file_header == NULL) { fprintf(stderr,"prsocket_test failed to malloc header file\n"); failed_already=1; rv = -1; goto done; } memset(small_file_header, (int) PR_IntervalNow(), SMALL_FILE_HEADER_SIZE); /* * setup large file */ large_file_fd = PR_Open(LARGE_FILE_NAME, PR_RDWR | PR_CREATE_FILE,0777); if (large_file_fd == NULL) { fprintf(stderr,"prsocket_test failed to create/open file %s\n", LARGE_FILE_NAME); failed_already=1; rv = -1; goto done; } /* * fill in random data */ for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) { buf->data[i] = i; } count = 0; do { len = (LARGE_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE ? TRANSMITFILE_BUF_SIZE : (LARGE_FILE_SIZE - count); bytes = PR_Write(large_file_fd, buf->data, len); if (bytes <= 0) { fprintf(stderr, "prsocket_test failed to write to file %s: (%ld, %ld)\n", LARGE_FILE_NAME, PR_GetError(), PR_GetOSError()); failed_already=1; rv = -1; goto done; } count += bytes; } while (count < LARGE_FILE_SIZE); #ifdef XP_UNIX /* * map the large file; used in checking for data corruption */ large_file_addr = mmap(0, LARGE_FILE_SIZE, PROT_READ, MAP_PRIVATE, large_file_fd->secret->md.osfd, 0); if (large_file_addr == (void *) -1) { fprintf(stderr,"prsocket_test failed to mmap file %s\n", LARGE_FILE_NAME); failed_already=1; rv = -1; goto done; } #endif datalen = tcp_mesg_size; thread_count = 0; /* * start the server thread */ sparamp = PR_NEW(Server_Param); if (sparamp == NULL) { fprintf(stderr,"prsocket_test: PR_NEW failed\n"); failed_already=1; rv = -1; goto done; } server_sem = PR_NewSem(0); if (server_sem == NULL) { fprintf(stderr,"prsocket_test: PR_NewSem failed\n"); failed_already=1; rv = -1; goto done; } mon2 = PR_NewMonitor(); if (mon2 == NULL) { fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n"); failed_already=1; rv = -1; goto done; } PR_EnterMonitor(mon2); sparamp->addr_sem = server_sem; sparamp->exit_mon = mon2; sparamp->exit_counter = &thread_count; sparamp->datalen = datalen; t = PR_CreateThread(PR_USER_THREAD, TransmitFile_Server, (void *)sparamp, PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0); if (t == NULL) { fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); failed_already=1; rv = -1; goto done; } DPRINTF(("Created TCP server = 0x%x\n", t)); thread_count++; /* * wait till the server address is setup */ PR_WaitSem(server_sem); /* * Now start a bunch of client threads */ cparamp = PR_NEW(Client_Param); if (cparamp == NULL) { fprintf(stderr,"prsocket_test: PR_NEW failed\n"); failed_already=1; rv = -1; goto done; } cparamp->server_addr = tcp_server_addr; cparamp->server_addr.inet.ip = PR_htonl(INADDR_LOOPBACK); cparamp->exit_mon = mon2; cparamp->exit_counter = &thread_count; cparamp->datalen = datalen; for (i = 0; i < num_transmitfile_clients; i++) { /* * Every other thread is a LOCAL/GLOBAL thread */ if (i & 1) scope = PR_GLOBAL_THREAD; else scope = PR_LOCAL_THREAD; t = PR_CreateThread(PR_USER_THREAD, TransmitFile_Client, (void *) cparamp, PR_PRIORITY_NORMAL, scope, PR_UNJOINABLE_THREAD, 0); if (t == NULL) { fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); rv = -1; failed_already=1; goto done; } DPRINTF(("Created TransmitFile client = 0x%lx\n", t)); thread_count++; } /* Wait for server and client threads to exit */ while (thread_count) { PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); DPRINTF(("Socket_Misc_Test - thread_count = %d\n", thread_count)); } PR_ExitMonitor(mon2); done: if (buf) { PR_DELETE(buf); } #ifdef XP_UNIX munmap(small_file_addr, SMALL_FILE_SIZE); munmap(large_file_addr, LARGE_FILE_SIZE); #endif PR_Close(small_file_fd); PR_Close(large_file_fd); if ((PR_Delete(SMALL_FILE_NAME)) == PR_FAILURE) { fprintf(stderr,"prsocket_test: failed to unlink file %s\n", SMALL_FILE_NAME); failed_already=1; } if ((PR_Delete(LARGE_FILE_NAME)) == PR_FAILURE) { fprintf(stderr,"prsocket_test: failed to unlink file %s\n", LARGE_FILE_NAME); failed_already=1; } if ((PR_RmDir(TEST_DIR)) == PR_FAILURE) { fprintf(stderr,"prsocket_test failed to rmdir %s: (%ld, %ld)\n", TEST_DIR, PR_GetError(), PR_GetOSError()); failed_already=1; } printf("%-29s%s","Socket_Misc_Test",":"); printf("%2d Server %2d Clients\n",1, num_transmitfile_clients); printf("%30s Sizes of Transmitted Files - %4d KB, %2d MB \n",":", SMALL_FILE_SIZE/1024, LARGE_FILE_SIZE/(1024 * 1024)); return rv; }
SECStatus ImportCRL (CERTCertDBHandle *certHandle, char *url, int type, PRFileDesc *inFile, PRInt32 importOptions, PRInt32 decodeOptions, secuPWData *pwdata) { CERTSignedCrl *crl = NULL; SECItem crlDER; PK11SlotInfo* slot = NULL; int rv; #if defined(DEBUG_jp96085) PRIntervalTime starttime, endtime, elapsed; PRUint32 mins, secs, msecs; #endif crlDER.data = NULL; /* Read in the entire file specified with the -f argument */ rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE); if (rv != SECSuccess) { SECU_PrintError(progName, "unable to read input file"); return (SECFailure); } decodeOptions |= CRL_DECODE_DONT_COPY_DER; slot = PK11_GetInternalKeySlot(); if (PK11_NeedLogin(slot)) { rv = PK11_Authenticate(slot, PR_TRUE, pwdata); if (rv != SECSuccess) goto loser; } #if defined(DEBUG_jp96085) starttime = PR_IntervalNow(); #endif crl = PK11_ImportCRL(slot, &crlDER, url, type, NULL, importOptions, NULL, decodeOptions); #if defined(DEBUG_jp96085) endtime = PR_IntervalNow(); elapsed = endtime - starttime; mins = PR_IntervalToSeconds(elapsed) / 60; secs = PR_IntervalToSeconds(elapsed) % 60; msecs = PR_IntervalToMilliseconds(elapsed) % 1000; printf("Elapsed : %2d:%2d.%3d\n", mins, secs, msecs); #endif if (!crl) { const char *errString; rv = SECFailure; errString = SECU_Strerror(PORT_GetError()); if ( errString && PORT_Strlen (errString) == 0) SECU_PrintError (progName, "CRL is not imported (error: input CRL is not up to date.)"); else SECU_PrintError (progName, "unable to import CRL"); } else { SEC_DestroyCrl (crl); } loser: if (slot) { PK11_FreeSlot(slot); } return (rv); }
void mozTXTToHTMLConv::ScanHTML(nsString& aInString, uint32_t whattodo, nsString &aOutString) { // some common variables we were recalculating // every time inside the for loop... int32_t lengthOfInString = aInString.Length(); const char16_t * uniBuffer = aInString.get(); #ifdef DEBUG_BenB_Perf PRTime parsing_start = PR_IntervalNow(); #endif // Look for simple entities not included in a tags and scan them. // Skip all tags ("<[...]>") and content in an a link tag ("<a [...]</a>"), // comment tag ("<!--[...]-->"), style tag, script tag or head tag. // Unescape the rest (text between tags) and pass it to ScanTXT. for (int32_t i = 0; i < lengthOfInString;) { if (aInString[i] == '<') // html tag { int32_t start = i; if (Substring(aInString, i + 1, 2).LowerCaseEqualsASCII("a ")) // if a tag, skip until </a>. // Make sure there's a space after, not to match "abbr". { i = aInString.Find("</a>", true, i); if (i == kNotFound) i = lengthOfInString; else i += 4; } else if (Substring(aInString, i + 1, 3).LowerCaseEqualsASCII("!--")) // if out-commended code, skip until --> { i = aInString.Find("-->", false, i); if (i == kNotFound) i = lengthOfInString; else i += 3; } else if (Substring(aInString, i + 1, 5).LowerCaseEqualsASCII("style") && (aInString.CharAt(i + 6) == ' ' || aInString.CharAt(i + 6) == '>')) // if style tag, skip until </style> { i = aInString.Find("</style>", true, i); if (i == kNotFound) i = lengthOfInString; else i += 8; } else if (Substring(aInString, i + 1, 6).LowerCaseEqualsASCII("script") && (aInString.CharAt(i + 7) == ' ' || aInString.CharAt(i + 7) == '>')) // if script tag, skip until </script> { i = aInString.Find("</script>", true, i); if (i == kNotFound) i = lengthOfInString; else i += 9; } else if (Substring(aInString, i + 1, 4).LowerCaseEqualsASCII("head") && (aInString.CharAt(i + 5) == ' ' || aInString.CharAt(i + 5) == '>')) // if head tag, skip until </head> // Make sure not to match <header>. { i = aInString.Find("</head>", true, i); if (i == kNotFound) i = lengthOfInString; else i += 7; } else // just skip tag (attributes etc.) { i = aInString.FindChar('>', i); if (i == kNotFound) i = lengthOfInString; else i++; } aOutString.Append(&uniBuffer[start], i - start); } else { uint32_t start = uint32_t(i); i = aInString.FindChar('<', i); if (i == kNotFound) i = lengthOfInString; nsString tempString; tempString.SetCapacity(uint32_t((uint32_t(i) - start) * growthRate)); UnescapeStr(uniBuffer, start, uint32_t(i) - start, tempString); ScanTXT(tempString.get(), tempString.Length(), whattodo, aOutString); } } #ifdef DEBUG_BenB_Perf printf("ScanHTML time: %d ms\n", PR_IntervalToMilliseconds(PR_IntervalNow() - parsing_start)); #endif }
void nsTimerImpl::Fire() { if (mCanceled) return; PRIntervalTime now = PR_IntervalNow(); #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { PRIntervalTime a = now - mStart; // actual delay in intervals PRUint32 b = PR_MillisecondsToInterval(mDelay); // expected delay in intervals PRUint32 d = PR_IntervalToMilliseconds((a > b) ? a - b : b - a); // delta in ms sDeltaSum += d; sDeltaSumSquared += double(d) * double(d); sDeltaNum++; PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] expected delay time %4dms\n", this, mDelay)); PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] actual delay time %4dms\n", this, PR_IntervalToMilliseconds(a))); PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] (mType is %d) -------\n", this, mType)); PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] delta %4dms\n", this, (a > b) ? (PRInt32)d : -(PRInt32)d)); mStart = mStart2; mStart2 = 0; } #endif PRIntervalTime timeout = mTimeout; if (mType == TYPE_REPEATING_PRECISE) { // Precise repeating timers advance mTimeout by mDelay without fail before // calling Fire(). timeout -= PR_MillisecondsToInterval(mDelay); } if (gThread) gThread->UpdateFilter(mDelay, timeout, now); if (mCallbackType == CALLBACK_TYPE_INTERFACE) mTimerCallbackWhileFiring = mCallback.i; mFiring = PR_TRUE; // Handle callbacks that re-init the timer, but avoid leaking. // See bug 330128. CallbackUnion callback = mCallback; PRUintn callbackType = mCallbackType; if (callbackType == CALLBACK_TYPE_INTERFACE) NS_ADDREF(callback.i); else if (callbackType == CALLBACK_TYPE_OBSERVER) NS_ADDREF(callback.o); ReleaseCallback(); switch (callbackType) { case CALLBACK_TYPE_FUNC: callback.c(this, mClosure); break; case CALLBACK_TYPE_INTERFACE: callback.i->Notify(this); break; case CALLBACK_TYPE_OBSERVER: callback.o->Observe(static_cast<nsITimer*>(this), NS_TIMER_CALLBACK_TOPIC, nsnull); break; default:; } // If the callback didn't re-init the timer, and it's not a one-shot timer, // restore the callback state. if (mCallbackType == CALLBACK_TYPE_UNKNOWN && mType != TYPE_ONE_SHOT && !mCanceled) { mCallback = callback; mCallbackType = callbackType; } else { // The timer was a one-shot, or the callback was reinitialized. if (callbackType == CALLBACK_TYPE_INTERFACE) NS_RELEASE(callback.i); else if (callbackType == CALLBACK_TYPE_OBSERVER) NS_RELEASE(callback.o); } mFiring = PR_FALSE; mTimerCallbackWhileFiring = nsnull; #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] Took %dms to fire timer callback\n", this, PR_IntervalToMilliseconds(PR_IntervalNow() - now))); } #endif if (mType == TYPE_REPEATING_SLACK) { SetDelayInternal(mDelay); // force mTimeout to be recomputed. if (gThread) gThread->AddTimer(this); } }
// Called from the main thread NS_IMETHODIMP nsBaseAppShell::OnProcessNextEvent(nsIThreadInternal *thr, bool mayWait, uint32_t recursionDepth) { if (mBlockNativeEvent) { if (!mayWait) return NS_OK; // Hmm, we're in a nested native event loop and would like to get // back to it ASAP, but it seems a gecko event has caused us to // spin up a nested XPCOM event loop (eg. modal window), so we // really must start processing native events here again. mBlockNativeEvent = false; if (NS_HasPendingEvents(thr)) OnDispatchedEvent(thr); // in case we blocked it earlier } PRIntervalTime start = PR_IntervalNow(); PRIntervalTime limit = THREAD_EVENT_STARVATION_LIMIT; // Unblock outer nested wait loop (below). if (mBlockedWait) *mBlockedWait = false; bool *oldBlockedWait = mBlockedWait; mBlockedWait = &mayWait; // When mayWait is true, we need to make sure that there is an event in the // thread's event queue before we return. Otherwise, the thread will block // on its event queue waiting for an event. bool needEvent = mayWait; // Reset prior to invoking DoProcessNextNativeEvent which might cause // NativeEventCallback to process gecko events. mProcessedGeckoEvents = false; if (mFavorPerf <= 0 && start > mSwitchTime + mStarvationDelay) { // Favor pending native events PRIntervalTime now = start; bool keepGoing; do { mLastNativeEventTime = now; keepGoing = DoProcessNextNativeEvent(false, recursionDepth); } while (keepGoing && ((now = PR_IntervalNow()) - start) < limit); } else { // Avoid starving native events completely when in performance mode if (start - mLastNativeEventTime > limit) { mLastNativeEventTime = start; DoProcessNextNativeEvent(false, recursionDepth); } } while (!NS_HasPendingEvents(thr) && !mProcessedGeckoEvents) { // If we have been asked to exit from Run, then we should not wait for // events to process. Note that an inner nested event loop causes // 'mayWait' to become false too, through 'mBlockedWait'. if (mExiting) mayWait = false; mLastNativeEventTime = PR_IntervalNow(); if (!DoProcessNextNativeEvent(mayWait, recursionDepth) || !mayWait) break; } mBlockedWait = oldBlockedWait; // Make sure that the thread event queue does not block on its monitor, as // it normally would do if it did not have any pending events. To avoid // that, we simply insert a dummy event into its queue during shutdown. if (needEvent && !mExiting && !NS_HasPendingEvents(thr)) { DispatchDummyEvent(thr); } // We're about to run an event, so we're in a stable state. RunSyncSections(true, recursionDepth); return NS_OK; }
void ThreadMain(void*) { PR_SetCurrentThreadName("Hang Monitor"); MonitorAutoLock lock(*gMonitor); // In order to avoid issues with the hang monitor incorrectly triggering // during a general system stop such as sleeping, the monitor thread must // run twice to trigger hang protection. PRIntervalTime lastTimestamp = 0; int waitCount = 0; #ifdef REPORT_CHROME_HANGS Telemetry::ProcessedStack stack; int32_t systemUptime = -1; int32_t firefoxUptime = -1; auto annotations = MakeUnique<ChromeHangAnnotations>(); #endif while (true) { if (gShutdown) { return; // Exit the thread } // avoid rereading the volatile value in this loop PRIntervalTime timestamp = gTimestamp; PRIntervalTime now = PR_IntervalNow(); if (timestamp != PR_INTERVAL_NO_WAIT && now < timestamp) { // 32-bit overflow, reset for another waiting period timestamp = 1; // lowest legal PRInterval value } if (timestamp != PR_INTERVAL_NO_WAIT && timestamp == lastTimestamp && gTimeout > 0) { ++waitCount; #ifdef REPORT_CHROME_HANGS // Capture the chrome-hang stack + Firefox & system uptimes after // the minimum hang duration has been reached (not when the hang ends) if (waitCount == 2) { GetChromeHangReport(stack, systemUptime, firefoxUptime); ChromeHangAnnotatorCallout(*annotations); } #else // This is the crash-on-hang feature. // See bug 867313 for the quirk in the waitCount comparison if (waitCount >= 2) { int32_t delay = int32_t(PR_IntervalToSeconds(now - timestamp)); if (delay >= gTimeout) { MonitorAutoUnlock unlock(*gMonitor); Crash(); } } #endif } else { #ifdef REPORT_CHROME_HANGS if (waitCount >= 2) { uint32_t hangDuration = PR_IntervalToSeconds(now - lastTimestamp); Telemetry::RecordChromeHang(hangDuration, stack, systemUptime, firefoxUptime, Move(annotations)); stack.Clear(); annotations = MakeUnique<ChromeHangAnnotations>(); } #endif lastTimestamp = timestamp; waitCount = 0; } PRIntervalTime timeout; if (gTimeout <= 0) { timeout = PR_INTERVAL_NO_TIMEOUT; } else { timeout = PR_MillisecondsToInterval(gTimeout * 500); } lock.Wait(timeout); } }
void Resolver :: DNS_manager() { // setup a connection to the DNS (UDP or TCP) PRFileDesc* fd = ar_init(ARES_CALLINIT|ARES_INITSOCK); if (!fd) { error(); return; } started(); PRIntervalTime delay = PR_SecondsToInterval(1); PRPollDesc pfd; pfd.fd = afd; pfd.in_flags = PR_POLL_READ; // wake up periodically to expire clients while(PR_TRUE) { switch (PR_Poll(&pfd, 1, delay)) { case -1: // fail case 0: // timeout break; default: // if there's data, let ar_receive figure out where to route it // read response from the DNS server if (pfd.out_flags & PR_POLL_READ) ar_receive(); break; } PRIntervalTime now = PR_IntervalNow(); DNShash.start_enum(); DNSSession* session; // enumerate session hash table while (session = DNShash.getNextSession()) { if (PR_TRUE == session->hasSendFailed() ) { DNShash.removeCurrent(); // remove this session from the hash table session->error(); // set status and wake up client continue; } session->update(now); // update remaining time for each session if (PR_TRUE == session->hasTimedOut() ) { DNShash.removeCurrent(); // remove this session from the hash table session->expire(); // set status and wake up client continue; } } DNShash.end_enum(); DNShash.check(); } }