michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "base/basictypes.h" michael@0: michael@0: #include "AsyncConnectionHelper.h" michael@0: michael@0: #include "mozilla/dom/quota/QuotaManager.h" michael@0: #include "mozilla/storage.h" michael@0: #include "nsComponentManagerUtils.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsProxyRelease.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsWrapperCacheInlines.h" michael@0: michael@0: #include "IDBEvents.h" michael@0: #include "IDBTransaction.h" michael@0: #include "IndexedDatabaseManager.h" michael@0: #include "ProfilerHelpers.h" michael@0: #include "ReportInternalError.h" michael@0: #include "TransactionThreadPool.h" michael@0: michael@0: #include "ipc/IndexedDBChild.h" michael@0: #include "ipc/IndexedDBParent.h" michael@0: michael@0: using namespace mozilla; michael@0: USING_INDEXEDDB_NAMESPACE michael@0: using mozilla::dom::quota::QuotaManager; michael@0: michael@0: namespace { michael@0: michael@0: IDBTransaction* gCurrentTransaction = nullptr; michael@0: michael@0: const uint32_t kProgressHandlerGranularity = 1000; michael@0: michael@0: class MOZ_STACK_CLASS TransactionPoolEventTarget : public StackBasedEventTarget michael@0: { michael@0: public: michael@0: NS_DECL_NSIEVENTTARGET michael@0: michael@0: TransactionPoolEventTarget(IDBTransaction* aTransaction) michael@0: : mTransaction(aTransaction) michael@0: { } michael@0: michael@0: private: michael@0: IDBTransaction* mTransaction; michael@0: }; michael@0: michael@0: // This inline is just so that we always clear aBuffers appropriately even if michael@0: // something fails. michael@0: inline michael@0: nsresult michael@0: ConvertCloneReadInfosToArrayInternal( michael@0: JSContext* aCx, michael@0: nsTArray& aReadInfos, michael@0: JS::MutableHandle aResult) michael@0: { michael@0: JS::Rooted array(aCx, JS_NewArrayObject(aCx, 0)); michael@0: if (!array) { michael@0: IDB_WARNING("Failed to make array!"); michael@0: return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; michael@0: } michael@0: michael@0: if (!aReadInfos.IsEmpty()) { michael@0: if (!JS_SetArrayLength(aCx, array, uint32_t(aReadInfos.Length()))) { michael@0: IDB_WARNING("Failed to set array length!"); michael@0: return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; michael@0: } michael@0: michael@0: for (uint32_t index = 0, count = aReadInfos.Length(); index < count; michael@0: index++) { michael@0: StructuredCloneReadInfo& readInfo = aReadInfos[index]; michael@0: michael@0: JS::Rooted val(aCx); michael@0: if (!IDBObjectStore::DeserializeValue(aCx, readInfo, &val)) { michael@0: NS_WARNING("Failed to decode!"); michael@0: return NS_ERROR_DOM_DATA_CLONE_ERR; michael@0: } michael@0: michael@0: if (!JS_SetElement(aCx, array, index, val)) { michael@0: IDB_WARNING("Failed to set array element!"); michael@0: return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; michael@0: } michael@0: } michael@0: } michael@0: michael@0: aResult.setObject(*array); michael@0: return NS_OK; michael@0: } michael@0: michael@0: } // anonymous namespace michael@0: michael@0: HelperBase::~HelperBase() michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: IDBRequest* request; michael@0: mRequest.forget(&request); michael@0: michael@0: if (request) { michael@0: nsCOMPtr mainThread; michael@0: NS_GetMainThread(getter_AddRefs(mainThread)); michael@0: NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread!"); michael@0: michael@0: if (mainThread) { michael@0: NS_ProxyRelease(mainThread, static_cast(request)); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: HelperBase::WrapNative(JSContext* aCx, michael@0: nsISupports* aNative, michael@0: JS::MutableHandle aResult) michael@0: { michael@0: NS_ASSERTION(aCx, "Null context!"); michael@0: NS_ASSERTION(aNative, "Null pointer!"); michael@0: NS_ASSERTION(aResult.address(), "Null pointer!"); michael@0: NS_ASSERTION(mRequest, "Null request!"); michael@0: michael@0: nsresult rv = nsContentUtils::WrapNative(aCx, aNative, aResult); michael@0: IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: HelperBase::ReleaseMainThreadObjects() michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: mRequest = nullptr; michael@0: } michael@0: michael@0: AsyncConnectionHelper::AsyncConnectionHelper(IDBDatabase* aDatabase, michael@0: IDBRequest* aRequest) michael@0: : HelperBase(aRequest), michael@0: mDatabase(aDatabase), michael@0: mResultCode(NS_OK), michael@0: mDispatched(false) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: } michael@0: michael@0: AsyncConnectionHelper::AsyncConnectionHelper(IDBTransaction* aTransaction, michael@0: IDBRequest* aRequest) michael@0: : HelperBase(aRequest), michael@0: mDatabase(aTransaction->mDatabase), michael@0: mTransaction(aTransaction), michael@0: mResultCode(NS_OK), michael@0: mDispatched(false) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: } michael@0: michael@0: AsyncConnectionHelper::~AsyncConnectionHelper() michael@0: { michael@0: if (!NS_IsMainThread()) { michael@0: IDBDatabase* database; michael@0: mDatabase.forget(&database); michael@0: michael@0: IDBTransaction* transaction; michael@0: mTransaction.forget(&transaction); michael@0: michael@0: nsCOMPtr mainThread; michael@0: NS_GetMainThread(getter_AddRefs(mainThread)); michael@0: NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread!"); michael@0: michael@0: if (mainThread) { michael@0: if (database) { michael@0: NS_ProxyRelease(mainThread, static_cast(database)); michael@0: } michael@0: if (transaction) { michael@0: NS_ProxyRelease(mainThread, static_cast(transaction)); michael@0: } michael@0: } michael@0: } michael@0: michael@0: NS_ASSERTION(!mOldProgressHandler, "Should not have anything here!"); michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(AsyncConnectionHelper, nsIRunnable, michael@0: mozIStorageProgressHandler) michael@0: michael@0: NS_IMETHODIMP michael@0: AsyncConnectionHelper::Run() michael@0: { michael@0: if (NS_IsMainThread()) { michael@0: PROFILER_MAIN_THREAD_LABEL("IndexedDB", "AsyncConnectionHelper::Run"); michael@0: michael@0: if (mTransaction && michael@0: mTransaction->IsAborted()) { michael@0: // Always fire a "error" event with ABORT_ERR if the transaction was michael@0: // aborted, even if the request succeeded or failed with another error. michael@0: mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR; michael@0: } michael@0: michael@0: IDBTransaction* oldTransaction = gCurrentTransaction; michael@0: gCurrentTransaction = mTransaction; michael@0: michael@0: ChildProcessSendResult sendResult = michael@0: IndexedDatabaseManager::IsMainProcess() ? michael@0: MaybeSendResponseToChildProcess(mResultCode) : michael@0: Success_NotSent; michael@0: michael@0: switch (sendResult) { michael@0: case Success_Sent: { michael@0: if (mRequest) { michael@0: mRequest->NotifyHelperSentResultsToChildProcess(NS_OK); michael@0: } michael@0: break; michael@0: } michael@0: michael@0: case Success_NotSent: { michael@0: if (mRequest) { michael@0: nsresult rv = mRequest->NotifyHelperCompleted(this); michael@0: if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) { michael@0: mResultCode = rv; michael@0: } michael@0: michael@0: IDB_PROFILER_MARK("IndexedDB Request %llu: Running main thread " michael@0: "response (rv = %lu)", michael@0: "IDBRequest[%llu] MT Done", michael@0: mRequest->GetSerialNumber(), mResultCode); michael@0: } michael@0: michael@0: // Call OnError if the database had an error or if the OnSuccess michael@0: // handler has an error. michael@0: if (NS_FAILED(mResultCode) || michael@0: NS_FAILED((mResultCode = OnSuccess()))) { michael@0: OnError(); michael@0: } michael@0: break; michael@0: } michael@0: michael@0: case Success_ActorDisconnected: { michael@0: // Nothing needs to be done here. michael@0: break; michael@0: } michael@0: michael@0: case Error: { michael@0: IDB_WARNING("MaybeSendResultsToChildProcess failed!"); michael@0: mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; michael@0: if (mRequest) { michael@0: mRequest->NotifyHelperSentResultsToChildProcess(mResultCode); michael@0: } michael@0: break; michael@0: } michael@0: michael@0: default: michael@0: MOZ_CRASH("Unknown value for ChildProcessSendResult!"); michael@0: } michael@0: michael@0: NS_ASSERTION(gCurrentTransaction == mTransaction, "Should be unchanged!"); michael@0: gCurrentTransaction = oldTransaction; michael@0: michael@0: if (mDispatched && mTransaction) { michael@0: mTransaction->OnRequestFinished(); michael@0: } michael@0: michael@0: ReleaseMainThreadObjects(); michael@0: michael@0: NS_ASSERTION(!(mDatabase || mTransaction || mRequest), "Subclass didn't " michael@0: "call AsyncConnectionHelper::ReleaseMainThreadObjects!"); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); michael@0: michael@0: PROFILER_LABEL("IndexedDB", "AsyncConnectionHelper::Run"); michael@0: michael@0: IDB_PROFILER_MARK_IF(mRequest, michael@0: "IndexedDB Request %llu: Beginning database work", michael@0: "IDBRequest[%llu] DT Start", michael@0: mRequest->GetSerialNumber()); michael@0: michael@0: nsresult rv = NS_OK; michael@0: nsCOMPtr connection; michael@0: michael@0: if (mTransaction) { michael@0: rv = mTransaction->GetOrCreateConnection(getter_AddRefs(connection)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: NS_ASSERTION(connection, "This should never be null!"); michael@0: } michael@0: } michael@0: michael@0: bool setProgressHandler = false; michael@0: if (connection) { michael@0: rv = connection->SetProgressHandler(kProgressHandlerGranularity, this, michael@0: getter_AddRefs(mOldProgressHandler)); michael@0: NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "SetProgressHandler failed!"); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: setProgressHandler = true; michael@0: } michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(rv)) { michael@0: bool hasSavepoint = false; michael@0: if (mDatabase) { michael@0: QuotaManager::SetCurrentWindow(mDatabase->GetOwner()); michael@0: michael@0: // Make the first savepoint. michael@0: if (mTransaction) { michael@0: if (!(hasSavepoint = mTransaction->StartSavepoint())) { michael@0: NS_WARNING("Failed to make savepoint!"); michael@0: } michael@0: } michael@0: } michael@0: michael@0: mResultCode = DoDatabaseWork(connection); michael@0: michael@0: if (mDatabase) { michael@0: // Release or roll back the savepoint depending on the error code. michael@0: if (hasSavepoint) { michael@0: NS_ASSERTION(mTransaction, "Huh?!"); michael@0: if (NS_SUCCEEDED(mResultCode)) { michael@0: mTransaction->ReleaseSavepoint(); michael@0: } michael@0: else { michael@0: mTransaction->RollbackSavepoint(); michael@0: } michael@0: } michael@0: michael@0: // Don't unset this until we're sure that all SQLite activity has michael@0: // completed! michael@0: QuotaManager::SetCurrentWindow(nullptr); michael@0: } michael@0: } michael@0: else { michael@0: // NS_ERROR_NOT_AVAILABLE is our special code for "database is invalidated" michael@0: // and we should fail with RECOVERABLE_ERR. michael@0: if (rv == NS_ERROR_NOT_AVAILABLE) { michael@0: mResultCode = NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR; michael@0: } michael@0: else { michael@0: IDB_REPORT_INTERNAL_ERR(); michael@0: mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; michael@0: } michael@0: } michael@0: michael@0: if (setProgressHandler) { michael@0: nsCOMPtr handler; michael@0: rv = connection->RemoveProgressHandler(getter_AddRefs(handler)); michael@0: NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "RemoveProgressHandler failed!"); michael@0: #ifdef DEBUG michael@0: if (NS_SUCCEEDED(rv)) { michael@0: NS_ASSERTION(SameCOMIdentity(handler, static_cast(this)), michael@0: "Mismatch!"); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: IDB_PROFILER_MARK_IF(mRequest, michael@0: "IndexedDB Request %llu: Finished database work " michael@0: "(rv = %lu)", michael@0: "IDBRequest[%llu] DT Done", mRequest->GetSerialNumber(), michael@0: mResultCode); michael@0: michael@0: return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: AsyncConnectionHelper::OnProgress(mozIStorageConnection* aConnection, michael@0: bool* _retval) michael@0: { michael@0: if (mDatabase && mDatabase->IsInvalidated()) { michael@0: // Someone is trying to delete the database file. Exit lightningfast! michael@0: *_retval = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (mOldProgressHandler) { michael@0: return mOldProgressHandler->OnProgress(aConnection, _retval); michael@0: } michael@0: michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: AsyncConnectionHelper::Dispatch(nsIEventTarget* aTarget) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: nsresult rv = Init(); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: rv = aTarget->Dispatch(this, NS_DISPATCH_NORMAL); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (mTransaction) { michael@0: mTransaction->OnNewRequest(); michael@0: } michael@0: michael@0: mDispatched = true; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: AsyncConnectionHelper::DispatchToTransactionPool() michael@0: { michael@0: NS_ASSERTION(mTransaction, "Only ok to call this with a transaction!"); michael@0: TransactionPoolEventTarget target(mTransaction); michael@0: return Dispatch(&target); michael@0: } michael@0: michael@0: // static michael@0: void michael@0: AsyncConnectionHelper::SetCurrentTransaction(IDBTransaction* aTransaction) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: NS_ASSERTION(!aTransaction || !gCurrentTransaction, michael@0: "Stepping on another transaction!"); michael@0: michael@0: gCurrentTransaction = aTransaction; michael@0: } michael@0: michael@0: // static michael@0: IDBTransaction* michael@0: AsyncConnectionHelper::GetCurrentTransaction() michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: return gCurrentTransaction; michael@0: } michael@0: michael@0: nsresult michael@0: AsyncConnectionHelper::Init() michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: already_AddRefed michael@0: AsyncConnectionHelper::CreateSuccessEvent(mozilla::dom::EventTarget* aOwner) michael@0: { michael@0: return CreateGenericEvent(mRequest, NS_LITERAL_STRING(SUCCESS_EVT_STR), michael@0: eDoesNotBubble, eNotCancelable); michael@0: } michael@0: michael@0: nsresult michael@0: AsyncConnectionHelper::OnSuccess() michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: NS_ASSERTION(mRequest, "Null request!"); michael@0: michael@0: PROFILER_MAIN_THREAD_LABEL("IndexedDB", "AsyncConnectionHelper::OnSuccess"); michael@0: michael@0: nsRefPtr event = CreateSuccessEvent(mRequest); michael@0: if (!event) { michael@0: IDB_WARNING("Failed to create event!"); michael@0: return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; michael@0: } michael@0: michael@0: bool dummy; michael@0: nsresult rv = mRequest->DispatchEvent(event, &dummy); michael@0: IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); michael@0: michael@0: WidgetEvent* internalEvent = event->GetInternalNSEvent(); michael@0: NS_ASSERTION(internalEvent, "This should never be null!"); michael@0: michael@0: NS_ASSERTION(!mTransaction || michael@0: mTransaction->IsOpen() || michael@0: mTransaction->IsAborted(), michael@0: "How else can this be closed?!"); michael@0: michael@0: if (internalEvent->mFlags.mExceptionHasBeenRisen && michael@0: mTransaction && michael@0: mTransaction->IsOpen()) { michael@0: rv = mTransaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: AsyncConnectionHelper::OnError() michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: NS_ASSERTION(mRequest, "Null request!"); michael@0: michael@0: PROFILER_MAIN_THREAD_LABEL("IndexedDB", "AsyncConnectionHelper::OnError"); michael@0: michael@0: // Make an error event and fire it at the target. michael@0: nsRefPtr event = michael@0: CreateGenericEvent(mRequest, NS_LITERAL_STRING(ERROR_EVT_STR), eDoesBubble, michael@0: eCancelable); michael@0: if (!event) { michael@0: NS_ERROR("Failed to create event!"); michael@0: return; michael@0: } michael@0: michael@0: bool doDefault; michael@0: nsresult rv = mRequest->DispatchEvent(event, &doDefault); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: NS_ASSERTION(!mTransaction || michael@0: mTransaction->IsOpen() || michael@0: mTransaction->IsAborted(), michael@0: "How else can this be closed?!"); michael@0: michael@0: WidgetEvent* internalEvent = event->GetInternalNSEvent(); michael@0: NS_ASSERTION(internalEvent, "This should never be null!"); michael@0: michael@0: if (internalEvent->mFlags.mExceptionHasBeenRisen && michael@0: mTransaction && michael@0: mTransaction->IsOpen() && michael@0: NS_FAILED(mTransaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR))) { michael@0: NS_WARNING("Failed to abort transaction!"); michael@0: } michael@0: michael@0: if (doDefault && michael@0: mTransaction && michael@0: mTransaction->IsOpen() && michael@0: NS_FAILED(mTransaction->Abort(mRequest))) { michael@0: NS_WARNING("Failed to abort transaction!"); michael@0: } michael@0: } michael@0: else { michael@0: NS_WARNING("DispatchEvent failed!"); michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: AsyncConnectionHelper::GetSuccessResult(JSContext* aCx, michael@0: JS::MutableHandle aVal) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: aVal.setUndefined(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: AsyncConnectionHelper::ReleaseMainThreadObjects() michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: michael@0: mDatabase = nullptr; michael@0: mTransaction = nullptr; michael@0: michael@0: HelperBase::ReleaseMainThreadObjects(); michael@0: } michael@0: michael@0: AsyncConnectionHelper::ChildProcessSendResult michael@0: AsyncConnectionHelper::MaybeSendResponseToChildProcess(nsresult aResultCode) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); michael@0: NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); michael@0: michael@0: // If there's no request, there could never have been an actor, and so there michael@0: // is nothing to do. michael@0: if (!mRequest) { michael@0: return Success_NotSent; michael@0: } michael@0: michael@0: IDBTransaction* trans = GetCurrentTransaction(); michael@0: // We may not have a transaction, e.g. for deleteDatabase michael@0: if (!trans) { michael@0: return Success_NotSent; michael@0: } michael@0: michael@0: // Are we shutting down the child? michael@0: IndexedDBDatabaseParent* dbActor = trans->Database()->GetActorParent(); michael@0: if (dbActor && dbActor->IsDisconnected()) { michael@0: return Success_ActorDisconnected; michael@0: } michael@0: michael@0: IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); michael@0: if (!actor) { michael@0: return Success_NotSent; michael@0: } michael@0: michael@0: IDB_PROFILER_MARK("IndexedDB Request %llu: Sending response to child " michael@0: "process (rv = %lu)", michael@0: "IDBRequest[%llu] MT Done", michael@0: mRequest->GetSerialNumber(), aResultCode); michael@0: michael@0: return SendResponseToChildProcess(aResultCode); michael@0: } michael@0: michael@0: nsresult michael@0: AsyncConnectionHelper::OnParentProcessRequestComplete( michael@0: const ResponseValue& aResponseValue) michael@0: { michael@0: NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); michael@0: michael@0: if (aResponseValue.type() == ResponseValue::Tnsresult) { michael@0: NS_ASSERTION(NS_FAILED(aResponseValue.get_nsresult()), "Huh?"); michael@0: SetError(aResponseValue.get_nsresult()); michael@0: } michael@0: else { michael@0: nsresult rv = UnpackResponseFromParentProcess(aResponseValue); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: michael@0: return Run(); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: AsyncConnectionHelper::ConvertToArrayAndCleanup( michael@0: JSContext* aCx, michael@0: nsTArray& aReadInfos, michael@0: JS::MutableHandle aResult) michael@0: { michael@0: NS_ASSERTION(aCx, "Null context!"); michael@0: NS_ASSERTION(aResult.address(), "Null pointer!"); michael@0: michael@0: nsresult rv = ConvertCloneReadInfosToArrayInternal(aCx, aReadInfos, aResult); michael@0: michael@0: for (uint32_t index = 0; index < aReadInfos.Length(); index++) { michael@0: aReadInfos[index].mCloneBuffer.clear(); michael@0: } michael@0: aReadInfos.Clear(); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP_(MozExternalRefCountType) michael@0: StackBasedEventTarget::AddRef() michael@0: { michael@0: NS_NOTREACHED("Don't call me!"); michael@0: return 2; michael@0: } michael@0: michael@0: NS_IMETHODIMP_(MozExternalRefCountType) michael@0: StackBasedEventTarget::Release() michael@0: { michael@0: NS_NOTREACHED("Don't call me!"); michael@0: return 1; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: StackBasedEventTarget::QueryInterface(REFNSIID aIID, michael@0: void** aInstancePtr) michael@0: { michael@0: NS_NOTREACHED("Don't call me!"); michael@0: return NS_NOINTERFACE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ImmediateRunEventTarget::Dispatch(nsIRunnable* aRunnable, michael@0: uint32_t aFlags) michael@0: { michael@0: NS_ASSERTION(aRunnable, "Null pointer!"); michael@0: michael@0: nsCOMPtr runnable(aRunnable); michael@0: DebugOnly rv = michael@0: runnable->Run(); michael@0: MOZ_ASSERT(NS_SUCCEEDED(rv)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ImmediateRunEventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread) michael@0: { michael@0: *aIsOnCurrentThread = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TransactionPoolEventTarget::Dispatch(nsIRunnable* aRunnable, michael@0: uint32_t aFlags) michael@0: { michael@0: NS_ASSERTION(aRunnable, "Null pointer!"); michael@0: NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "Unsupported!"); michael@0: michael@0: TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate(); michael@0: NS_ENSURE_TRUE(pool, NS_ERROR_UNEXPECTED); michael@0: michael@0: nsresult rv = pool->Dispatch(mTransaction, aRunnable, false, nullptr); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TransactionPoolEventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread) michael@0: { michael@0: *aIsOnCurrentThread = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: NoDispatchEventTarget::Dispatch(nsIRunnable* aRunnable, michael@0: uint32_t aFlags) michael@0: { michael@0: nsCOMPtr runnable = aRunnable; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: NoDispatchEventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread) michael@0: { michael@0: *aIsOnCurrentThread = true; michael@0: return NS_OK; michael@0: }