nsresult nsInputStreamPump::CallOnStateStop() { ReentrantMonitorAutoEnter mon(mMonitor); MOZ_ASSERT(NS_IsMainThread(), "CallOnStateStop should only be called on the main thread."); mState = OnStateStop(); return NS_OK; }
nsresult nsInputStreamPump::OnStateStopForFailure() { MOZ_ASSERT(NS_FAILED(mStatus), "OnStateStopForFailure should be called " "in a failed state"); MOZ_ASSERT(NS_IsMainThread(), "OnStateStopForFailure should be on the " "main thread"); mState = OnStateStop(); return NS_OK; }
NS_IMETHODIMP nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream *stream) { LOG(("nsInputStreamPump::OnInputStreamReady [this=%x]\n", this)); SAMPLE_LABEL("Input", "nsInputStreamPump::OnInputStreamReady"); // this function has been called from a PLEvent, so we can safely call // any listener or progress sink methods directly from here. for (;;) { if (mSuspendCount || mState == STATE_IDLE) { mWaiting = false; break; } PRUint32 nextState; switch (mState) { case STATE_START: nextState = OnStateStart(); break; case STATE_TRANSFER: nextState = OnStateTransfer(); break; case STATE_STOP: nextState = OnStateStop(); break; default: nextState = 0; NS_NOTREACHED("Unknown enum value."); return NS_ERROR_UNEXPECTED; } if (mState == nextState && !mSuspendCount) { NS_ASSERTION(mState == STATE_TRANSFER, "unexpected state"); NS_ASSERTION(NS_SUCCEEDED(mStatus), "unexpected status"); mWaiting = false; mStatus = EnsureWaiting(); if (NS_SUCCEEDED(mStatus)) break; nextState = STATE_STOP; } mState = nextState; } return NS_OK; }
NS_IMETHODIMP nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream *stream) { LOG(("nsInputStreamPump::OnInputStreamReady [this=%p]\n", this)); PROFILER_LABEL("nsInputStreamPump", "OnInputStreamReady", js::ProfileEntry::Category::NETWORK); // this function has been called from a PLEvent, so we can safely call // any listener or progress sink methods directly from here. for (;;) { // There should only be one iteration of this loop happening at a time. // To prevent AsyncWait() (called during callbacks or on other threads) // from creating a parallel OnInputStreamReady(), we use: // -- a monitor; and // -- a boolean mProcessingCallbacks to detect parallel loops // when exiting the monitor for callbacks. ReentrantMonitorAutoEnter lock(mMonitor); // Prevent parallel execution during callbacks, while out of monitor. if (mProcessingCallbacks) { MOZ_ASSERT(!mProcessingCallbacks); break; } mProcessingCallbacks = true; if (mSuspendCount || mState == STATE_IDLE) { mWaitingForInputStreamReady = false; mProcessingCallbacks = false; break; } uint32_t nextState; switch (mState) { case STATE_START: nextState = OnStateStart(); break; case STATE_TRANSFER: nextState = OnStateTransfer(); break; case STATE_STOP: mRetargeting = false; nextState = OnStateStop(); break; default: nextState = 0; NS_NOTREACHED("Unknown enum value."); return NS_ERROR_UNEXPECTED; } bool stillTransferring = (mState == STATE_TRANSFER && nextState == STATE_TRANSFER); if (stillTransferring) { NS_ASSERTION(NS_SUCCEEDED(mStatus), "Should not have failed status for ongoing transfer"); } else { NS_ASSERTION(mState != nextState, "Only OnStateTransfer can be called more than once."); } if (mRetargeting) { NS_ASSERTION(mState != STATE_STOP, "Retargeting should not happen during OnStateStop."); } // Set mRetargeting so EnsureWaiting will be called. It ensures that // OnStateStop is called on the main thread. if (nextState == STATE_STOP && !NS_IsMainThread()) { mRetargeting = true; } // Unset mProcessingCallbacks here (while we have lock) so our own call to // EnsureWaiting isn't blocked by it. mProcessingCallbacks = false; // We must break the loop when we're switching event delivery to another // thread and the input stream pump is suspended, otherwise // OnStateStop() might be called off the main thread. See bug 1026951 // comment #107 for the exact scenario. if (mSuspendCount && mRetargeting) { mState = nextState; mWaitingForInputStreamReady = false; break; } // Wait asynchronously if there is still data to transfer, or we're // switching event delivery to another thread. if (!mSuspendCount && (stillTransferring || mRetargeting)) { mState = nextState; mWaitingForInputStreamReady = false; nsresult rv = EnsureWaiting(); if (NS_SUCCEEDED(rv)) break; // Failure to start asynchronous wait: stop transfer. // Do not set mStatus if it was previously set to report a failure. if (NS_SUCCEEDED(mStatus)) { mStatus = rv; } nextState = STATE_STOP; } mState = nextState; } return NS_OK; }
NS_IMETHODIMP nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream *stream) { LOG(("nsInputStreamPump::OnInputStreamReady [this=%p]\n", this)); PROFILER_LABEL("Input", "nsInputStreamPump::OnInputStreamReady"); // this function has been called from a PLEvent, so we can safely call // any listener or progress sink methods directly from here. for (;;) { if (mSuspendCount || mState == STATE_IDLE) { mWaiting = false; break; } uint32_t nextState; switch (mState) { case STATE_START: nextState = OnStateStart(); break; case STATE_TRANSFER: nextState = OnStateTransfer(); break; case STATE_STOP: mRetargeting = false; nextState = OnStateStop(); break; default: nextState = 0; NS_NOTREACHED("Unknown enum value."); return NS_ERROR_UNEXPECTED; } bool stillTransferring = (mState == STATE_TRANSFER && nextState == STATE_TRANSFER); if (stillTransferring) { NS_ASSERTION(NS_SUCCEEDED(mStatus), "Should not have failed status for ongoing transfer"); } else { NS_ASSERTION(mState != nextState, "Only OnStateTransfer can be called more than once."); } if (mRetargeting) { NS_ASSERTION(mState != STATE_STOP, "Retargeting should not happen during OnStateStop."); } // Set mRetargeting so EnsureWaiting will be called. It ensures that // OnStateStop is called on the main thread. if (nextState == STATE_STOP && !NS_IsMainThread()) { mRetargeting = true; } // Wait asynchronously if there is still data to transfer, or we're // switching event delivery to another thread. if (!mSuspendCount && (stillTransferring || mRetargeting)) { mState = nextState; mWaiting = false; nsresult rv = EnsureWaiting(); if (NS_SUCCEEDED(rv)) break; // Failure to start asynchronous wait: stop transfer. // Do not set mStatus if it was previously set to report a failure. if (NS_SUCCEEDED(mStatus)) { mStatus = rv; } nextState = STATE_STOP; } mState = nextState; } return NS_OK; }