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; }
void TimeLapsePhotoModeManager::RunStateMachine() { if (m_spScheduler->IsFinished()) { m_host.SetStatusText(_T("TimeLapse state: Finished")); m_stateMachineState = T_enStateMachineState::finished; if (m_fnFinished != nullptr) m_fnFinished(); if (m_options.m_releaseTrigger == TimeLapseOptions::T_enReleaseTrigger::releaseAfterLastImage) { DisableMirrorLockup(); } return; } bool exit = false; while (!exit) { switch (m_stateMachineState) { case T_enStateMachineState::notRunning: m_stateMachineState = T_enStateMachineState::started; break; case T_enStateMachineState::started: OnStateStart(exit); break; case T_enStateMachineState::waitManualRelease: exit = true; // next state is set by OnStateEvent() break; case T_enStateMachineState::takePhoto: OnStateTakePhoto(exit); break; case T_enStateMachineState::waitTransferFinished: OnStateWaitTransferFinished(exit); break; case T_enStateMachineState::finished: exit = true; if (m_fnFinished != nullptr) m_fnFinished(); if (m_options.m_releaseTrigger == TimeLapseOptions::T_enReleaseTrigger::releaseAfterLastImage) { DisableMirrorLockup(); } break; default: ATLASSERT(false); // invalid state machine state break; } } }
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; }