nsresult nsTimerImpl::InitCommon(PRUint32 aType, PRUint32 aDelay) { nsresult rv; NS_ENSURE_TRUE(gThread, NS_ERROR_NOT_INITIALIZED); rv = gThread->Init(); NS_ENSURE_SUCCESS(rv, rv); /** * In case of re-Init, both with and without a preceding Cancel, clear the * mCanceled flag and assign a new mGeneration. But first, remove any armed * timer from the timer thread's list. * * If we are racing with the timer thread to remove this timer and we lose, * the RemoveTimer call made here will fail to find this timer in the timer * thread's list, and will return false harmlessly. We test mArmed here to * avoid the small overhead in RemoveTimer of locking the timer thread and * checking its list for this timer. It's safe to test mArmed even though * it might be cleared on another thread in the next cycle (or even already * be cleared by another CPU whose store hasn't reached our CPU's cache), * because RemoveTimer is idempotent. */ if (mArmed) gThread->RemoveTimer(this); mCanceled = false; mTimeout = TimeStamp(); mGeneration = PR_ATOMIC_INCREMENT(&gGenerator); mType = (PRUint8)aType; SetDelayInternal(aDelay); return gThread->AddTimer(this); }
nsresult nsTimerImpl::InitCommon(uint32_t aDelay, uint32_t aType) { nsresult rv; if (NS_WARN_IF(!gThread)) { return NS_ERROR_NOT_INITIALIZED; } if (!mEventTarget) { NS_ERROR("mEventTarget is NULL"); return NS_ERROR_NOT_INITIALIZED; } rv = gThread->Init(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } gThread->RemoveTimer(this); mCanceled = false; mTimeout = TimeStamp(); mGeneration = gGenerator++; mType = (uint8_t)aType; SetDelayInternal(aDelay); return gThread->AddTimer(this); }
void nsTimerImpl::Fire() { if (mCanceled) return; TimeStamp now = TimeStamp::Now(); #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { TimeDuration a = now - mStart; // actual delay in intervals TimeDuration b = TimeDuration::FromMilliseconds(mDelay); // expected delay in intervals TimeDuration delta = (a > b) ? a - b : b - a; PRUint32 d = delta.ToMilliseconds(); // delta in ms sDeltaSum += d; sDeltaSumSquared += double(d) * double(d); sDeltaNum++; PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] expected delay time %4ums\n", this, mDelay)); PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] actual delay time %fms\n", this, a.ToMilliseconds())); 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 = TimeStamp(); } #endif TimeStamp timeout = mTimeout; if (IsRepeatingPrecisely()) { // Precise repeating timers advance mTimeout by mDelay without fail before // calling Fire(). timeout -= TimeDuration::FromMilliseconds(mDelay); } if (gThread) gThread->UpdateFilter(mDelay, timeout, now); if (mCallbackType == CALLBACK_TYPE_INTERFACE) mTimerCallbackWhileFiring = mCallback.i; mFiring = 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 = false; mTimerCallbackWhileFiring = nsnull; #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] Took %fms to fire timer callback\n", this, (TimeStamp::Now() - now).ToMilliseconds())); } #endif // Reschedule repeating timers, except REPEATING_PRECISE which already did // that in PostTimerEvent, but make sure that we aren't armed already (which // can happen if the callback reinitialized the timer). if (IsRepeating() && mType != TYPE_REPEATING_PRECISE && !mArmed) { if (mType == TYPE_REPEATING_SLACK) SetDelayInternal(mDelay); // force mTimeout to be recomputed. For // REPEATING_PRECISE_CAN_SKIP timers this has // already happened. if (gThread) gThread->AddTimer(this); } }
void nsTimerImpl::Fire() { if (mCanceled) { return; } #if !defined(MOZILLA_XPCOMRT_API) PROFILER_LABEL("Timer", "Fire", js::ProfileEntry::Category::OTHER); #endif TimeStamp now = TimeStamp::Now(); if (MOZ_LOG_TEST(GetTimerLog(), LogLevel::Debug)) { TimeDuration a = now - mStart; // actual delay in intervals TimeDuration b = TimeDuration::FromMilliseconds(mDelay); // expected delay in intervals TimeDuration delta = (a > b) ? a - b : b - a; uint32_t d = delta.ToMilliseconds(); // delta in ms sDeltaSum += d; sDeltaSumSquared += double(d) * double(d); sDeltaNum++; MOZ_LOG(GetTimerLog(), LogLevel::Debug, ("[this=%p] expected delay time %4ums\n", this, mDelay)); MOZ_LOG(GetTimerLog(), LogLevel::Debug, ("[this=%p] actual delay time %fms\n", this, a.ToMilliseconds())); MOZ_LOG(GetTimerLog(), LogLevel::Debug, ("[this=%p] (mType is %d) -------\n", this, mType)); MOZ_LOG(GetTimerLog(), LogLevel::Debug, ("[this=%p] delta %4dms\n", this, (a > b) ? (int32_t)d : -(int32_t)d)); mStart = mStart2; mStart2 = TimeStamp(); } TimeStamp timeout = mTimeout; if (IsRepeatingPrecisely()) { // Precise repeating timers advance mTimeout by mDelay without fail before // calling Fire(). timeout -= TimeDuration::FromMilliseconds(mDelay); } if (mCallbackType == CallbackType::Interface) { mTimerCallbackWhileFiring = mCallback.i; } mFiring = true; // Handle callbacks that re-init the timer, but avoid leaking. // See bug 330128. CallbackUnion callback = mCallback; CallbackType callbackType = mCallbackType; if (callbackType == CallbackType::Interface) { NS_ADDREF(callback.i); } else if (callbackType == CallbackType::Observer) { NS_ADDREF(callback.o); } ReleaseCallback(); if (MOZ_LOG_TEST(GetTimerFiringsLog(), LogLevel::Debug)) { LogFiring(callbackType, callback); } switch (callbackType) { case CallbackType::Function: callback.c(this, mClosure); break; case CallbackType::Interface: callback.i->Notify(this); break; case CallbackType::Observer: callback.o->Observe(static_cast<nsITimer*>(this), NS_TIMER_CALLBACK_TOPIC, nullptr); 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 == CallbackType::Unknown && mType != TYPE_ONE_SHOT && !mCanceled) { mCallback = callback; mCallbackType = callbackType; } else { // The timer was a one-shot, or the callback was reinitialized. if (callbackType == CallbackType::Interface) { NS_RELEASE(callback.i); } else if (callbackType == CallbackType::Observer) { NS_RELEASE(callback.o); } } mFiring = false; mTimerCallbackWhileFiring = nullptr; MOZ_LOG(GetTimerLog(), LogLevel::Debug, ("[this=%p] Took %fms to fire timer callback\n", this, (TimeStamp::Now() - now).ToMilliseconds())); // Reschedule repeating timers, but make sure that we aren't armed already // (which can happen if the callback reinitialized the timer). if (IsRepeating() && !mArmed) { if (mType == TYPE_REPEATING_SLACK) { SetDelayInternal(mDelay); // force mTimeout to be recomputed. For } // REPEATING_PRECISE_CAN_SKIP timers this has // already happened. if (gThread) { gThread->AddTimer(this); } } }
NS_IMETHODIMP AsyncConnectionHelper::Run() { if (NS_IsMainThread()) { if (mTransaction && mTransaction->IsAborted() && NS_SUCCEEDED(mResultCode)) { // Don't fire success events if the transaction has since been aborted. // Instead convert to an error event. mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR; } IDBTransaction* oldTransaction = gCurrentTransaction; gCurrentTransaction = mTransaction; if (mRequest) { nsresult rv = mRequest->SetDone(this); if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) { mResultCode = rv; } } // Call OnError if the database had an error or if the OnSuccess handler // has an error. if (NS_FAILED(mResultCode) || NS_FAILED((mResultCode = OnSuccess()))) { OnError(); } NS_ASSERTION(gCurrentTransaction == mTransaction, "Should be unchanged!"); gCurrentTransaction = oldTransaction; if (mDispatched && mTransaction) { mTransaction->OnRequestFinished(); } ReleaseMainThreadObjects(); NS_ASSERTION(!(mDatabase || mTransaction || mRequest), "Subclass didn't " "call AsyncConnectionHelper::ReleaseMainThreadObjects!"); return NS_OK; } nsresult rv = NS_OK; nsCOMPtr<mozIStorageConnection> connection; if (mTransaction) { rv = mTransaction->GetOrCreateConnection(getter_AddRefs(connection)); if (NS_SUCCEEDED(rv)) { NS_ASSERTION(connection, "This should never be null!"); } } if (connection) { rv = connection->SetProgressHandler(kProgressHandlerGranularity, this, getter_AddRefs(mOldProgressHandler)); NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "SetProgressHandler failed!"); if (NS_SUCCEEDED(rv)) { mStartTime = TimeStamp::Now(); } } if (NS_SUCCEEDED(rv)) { bool hasSavepoint = false; if (mDatabase) { IDBFactory::SetCurrentDatabase(mDatabase); // Make the first savepoint. if (mTransaction) { if (!(hasSavepoint = mTransaction->StartSavepoint())) { NS_WARNING("Failed to make savepoint!"); } } } mResultCode = DoDatabaseWork(connection); if (mDatabase) { IDBFactory::SetCurrentDatabase(nsnull); // Release or roll back the savepoint depending on the error code. if (hasSavepoint) { NS_ASSERTION(mTransaction, "Huh?!"); if (NS_SUCCEEDED(mResultCode)) { mTransaction->ReleaseSavepoint(); } else { mTransaction->RollbackSavepoint(); } } } } else { // NS_ERROR_NOT_AVAILABLE is our special code for "database is invalidated" // and we should fail with RECOVERABLE_ERR. if (rv == NS_ERROR_NOT_AVAILABLE) { mResultCode = NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR; } else { mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } } if (!mStartTime.IsNull()) { nsCOMPtr<mozIStorageProgressHandler> handler; rv = connection->RemoveProgressHandler(getter_AddRefs(handler)); NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "RemoveProgressHandler failed!"); #ifdef DEBUG if (NS_SUCCEEDED(rv)) { nsCOMPtr<nsISupports> handlerSupports(do_QueryInterface(handler)); nsCOMPtr<nsISupports> thisSupports = do_QueryInterface(static_cast<nsIRunnable*>(this)); NS_ASSERTION(thisSupports == handlerSupports, "Mismatch!"); } #endif mStartTime = TimeStamp(); } return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL); }
void SetRemovedSentinel() { // assign the null time stamp mStartTime = TimeStamp(); }
NS_IMETHODIMP AsyncConnectionHelper::Run() { if (NS_IsMainThread()) { if (mRequest->mAborted) { NS_ASSERTION(mRequest->mReadyState == nsIIDBRequest::DONE, "Wrong state!"); mError = true; mErrorCode = nsIIDBDatabaseException::UNKNOWN_ERR; } else { NS_ASSERTION(mRequest->mReadyState == nsIIDBRequest::LOADING, "Wrong state!"); mRequest->mReadyState = nsIIDBRequest::DONE; } // Call OnError if the database had an error or if the OnSuccess handler // has an error. if (mError || ((mErrorCode = OnSuccess(mRequest)) != OK)) { OnError(mRequest, mErrorCode); } if (mTransaction) { mTransaction->OnRequestFinished(); } mDatabase = nsnull; mTransaction = nsnull; mRequest = nsnull; return NS_OK; } nsresult rv = NS_OK; nsCOMPtr<mozIStorageConnection> connection; if (mTransaction) { rv = mTransaction->GetOrCreateConnection(getter_AddRefs(connection)); if (NS_SUCCEEDED(rv)) { NS_ASSERTION(connection, "This should never be null!"); } } else if (mDatabase) { rv = mDatabase->GetOrCreateConnection(getter_AddRefs(connection)); if (NS_SUCCEEDED(rv)) { NS_ASSERTION(connection, "This should never be null!"); } } NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "GetOrCreateConnection failed!"); if (connection) { rv = connection->SetProgressHandler(kProgressHandlerGranularity, this, getter_AddRefs(mOldProgressHandler)); NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "SetProgressHandler failed!"); if (NS_SUCCEEDED(rv)) { mStartTime = TimeStamp::Now(); } } if (NS_SUCCEEDED(rv)) { mErrorCode = DoDatabaseWork(connection); } else { mErrorCode = nsIIDBDatabaseException::UNKNOWN_ERR; } if (!mStartTime.IsNull()) { nsCOMPtr<mozIStorageProgressHandler> handler; rv = connection->RemoveProgressHandler(getter_AddRefs(handler)); NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "RemoveProgressHandler failed!"); #ifdef DEBUG if (NS_SUCCEEDED(rv)) { nsCOMPtr<nsISupports> handlerSupports(do_QueryInterface(handler)); nsCOMPtr<nsISupports> thisSupports = do_QueryInterface(static_cast<nsIRunnable*>(this)); NS_ASSERTION(thisSupports == handlerSupports, "Mismatch!"); } #endif mStartTime = TimeStamp(); } if (mErrorCode != NOREPLY) { mError = mErrorCode != OK; return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL); } return NS_OK; }