gboolean purpleDNS::Resolve(PurpleDnsQueryData *query_data, PurpleDnsQueryResolvedCallback resolved_cb, PurpleDnsQueryFailedCallback failed_cb) { NS_ENSURE_TRUE(!NS_IsOffline(), false); nsCString host(purple_dnsquery_get_host(query_data)); LOG(("Resolving with moz: %s", host.get())); NS_ENSURE_TRUE(sRequests, false); nsCOMPtr<nsIDNSService> dns = do_GetService("@mozilla.org/network/dns-service;1"); nsCOMPtr<nsIDNSRecord> record; nsCOMPtr<nsICancelable> cancelable; nsCOMPtr<nsIThread> thread = do_GetMainThread(); nsCOMPtr<purpleDNSRequest> listener; listener = new purpleDNSRequest(); listener->mAccountId = purpleAccountScoper::GetCurrentAccountId(); listener->query_data = query_data; listener->resolved_cb = resolved_cb; listener->failed_cb = failed_cb; nsresult rv = dns->AsyncResolve(host, 0, listener, thread, getter_AddRefs(listener->asyncResolv)); NS_ENSURE_SUCCESS(rv, false);// The request wasn't handled. sRequests->AppendObject(listener); return true; // We handle the request, libpurple shouldn't try to do it. }
TemporaryRef<gfx::DataSourceSurface> GetDataSurfaceSafe() { nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); MOZ_ASSERT(mainThread); SyncRunnable::DispatchToThread(mainThread, this, false); return mDataSourceSurface.forget(); }
void CrashReporterParent::FinalizeChildData() { MOZ_ASSERT(mInitialized); if (NS_IsMainThread()) { // Inline, this is the main thread. Get this done. NotifyCrashService(); return; } nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); class NotifyOnMainThread : public nsRunnable { public: explicit NotifyOnMainThread(CrashReporterParent* aCR) : mCR(aCR) { } NS_IMETHOD Run() { mCR->NotifyCrashService(); return NS_OK; } private: CrashReporterParent* mCR; }; SyncRunnable::DispatchToThread(mainThread, new NotifyOnMainThread(this)); }
nsresult nsInputStreamPump::EnsureWaiting() { mMonitor.AssertCurrentThreadIn(); // no need to worry about multiple threads... an input stream pump lives // on only one thread at a time. MOZ_ASSERT(mAsyncStream); if (!mWaitingForInputStreamReady && !mProcessingCallbacks) { // Ensure OnStateStop is called on the main thread. if (mState == STATE_STOP) { nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); if (mTargetThread != mainThread) { mTargetThread = do_QueryInterface(mainThread); } } MOZ_ASSERT(mTargetThread); nsresult rv = mAsyncStream->AsyncWait(this, 0, 0, mTargetThread); if (NS_FAILED(rv)) { NS_ERROR("AsyncWait failed"); return rv; } // Any retargeting during STATE_START or START_TRANSFER is complete // after the call to AsyncWait; next callback wil be on mTargetThread. mRetargeting = false; mWaitingForInputStreamReady = true; } return NS_OK; }
void CacheFileChunk::WaitForUpdate(CacheFileChunkListener *aCallback) { mFile->AssertOwnsLock(); LOG(("CacheFileChunk::WaitForUpdate() [this=%p, listener=%p]", this, aCallback)); MOZ_ASSERT(mFile->mOutput); MOZ_ASSERT(IsReady()); #ifdef DEBUG for (uint32_t i = 0 ; i < mUpdateListeners.Length() ; i++) { MOZ_ASSERT(mUpdateListeners[i]->mCallback != aCallback); } #endif ChunkListenerItem *item = new ChunkListenerItem(); item->mTarget = CacheFileIOManager::IOTarget(); if (!item->mTarget) { LOG(("CacheFileChunk::WaitForUpdate() - Cannot get Cache I/O thread! Using " "main thread for callback.")); item->mTarget = do_GetMainThread(); } item->mCallback = aCallback; MOZ_ASSERT(item->mTarget); item->mCallback = aCallback; mUpdateListeners.AppendElement(item); }
GMPParent* GeckoMediaPluginServiceParent::ClonePlugin(const GMPParent* aOriginal) { MOZ_ASSERT(aOriginal); // The GMPParent inherits from IToplevelProtocol, which must be created // on the main thread to be threadsafe. See Bug 1035653. nsRefPtr<CreateGMPParentTask> task(new CreateGMPParentTask()); if (!NS_IsMainThread()) { nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); MOZ_ASSERT(mainThread); mozilla::SyncRunnable::DispatchToThread(mainThread, task); } nsRefPtr<GMPParent> gmp = task->GetParent(); nsresult rv = gmp->CloneFrom(aOriginal); if (NS_FAILED(rv)) { NS_WARNING("Can't Create GMPParent"); return nullptr; } MutexAutoLock lock(mMutex); mPlugins.AppendElement(gmp); return gmp.get(); }
void PDMFactory::EnsureInit() const { { StaticMutexAutoLock mon(sMonitor); if (sInstance) { // Quick exit if we already have an instance. return; } if (NS_IsMainThread()) { // On the main thread and holding the lock -> Create instance. sInstance = new PDMFactoryImpl(); ClearOnShutdown(&sInstance); return; } } // Not on the main thread -> Sync-dispatch creation to main thread. nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction([]() { StaticMutexAutoLock mon(sMonitor); if (!sInstance) { sInstance = new PDMFactoryImpl(); ClearOnShutdown(&sInstance); } }); SyncRunnable::DispatchToThread(mainThread, runnable); }
void GeckoMediaPluginServiceParent::AddOnGMPThread(const nsAString& aDirectory) { MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread); LOGD(("%s::%s: %s", __CLASS__, __FUNCTION__, NS_LossyConvertUTF16toASCII(aDirectory).get())); nsCOMPtr<nsIFile> directory; nsresult rv = NS_NewLocalFile(aDirectory, false, getter_AddRefs(directory)); if (NS_WARN_IF(NS_FAILED(rv))) { return; } // The GMPParent inherits from IToplevelProtocol, which must be created // on the main thread to be threadsafe. See Bug 1035653. nsRefPtr<CreateGMPParentTask> task(new CreateGMPParentTask()); nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); MOZ_ASSERT(mainThread); mozilla::SyncRunnable::DispatchToThread(mainThread, task); nsRefPtr<GMPParent> gmp = task->GetParent(); rv = gmp ? gmp->Init(this, directory) : NS_ERROR_NOT_AVAILABLE; if (NS_FAILED(rv)) { NS_WARNING("Can't Create GMPParent"); return; } { MutexAutoLock lock(mMutex); mPlugins.AppendElement(gmp); } NS_DispatchToMainThread(new NotifyObserversTask("gmp-path-added"), NS_DISPATCH_NORMAL); }
void FileBlockCache::Close() { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); MonitorAutoLock mon(mDataMonitor); mIsOpen = false; if (mThread) { // We must shut down the thread in another runnable. This is called // while we're shutting down the media cache, and nsIThread::Shutdown() // can cause events to run before it completes, which could end up // opening more streams, while the media cache is shutting down and // releasing memory etc! Also note we close mFD in the destructor so // as to not disturb any IO that's currently running. nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); if (mainThread) { nsCOMPtr<nsIRunnable> event = new ShutdownThreadEvent(mThread); mainThread->Dispatch(event.forget(), NS_DISPATCH_NORMAL); } else { // we're on Mainthread already, *and* the event queues are already // shut down, so no events should occur - certainly not creations of // new streams. mThread->Shutdown(); } } }
bool WorkerRunnable::DispatchInternal() { nsRefPtr<WorkerRunnable> runnable(this); if (mBehavior == WorkerThreadModifyBusyCount || mBehavior == WorkerThreadUnchangedBusyCount) { if (IsDebuggerRunnable()) { return NS_SUCCEEDED(mWorkerPrivate->DispatchDebuggerRunnable(runnable.forget())); } else { return NS_SUCCEEDED(mWorkerPrivate->Dispatch(runnable.forget())); } } MOZ_ASSERT(mBehavior == ParentThreadUnchangedBusyCount); if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) { return NS_SUCCEEDED(parent->Dispatch(runnable.forget())); } nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); MOZ_ASSERT(mainThread); return NS_SUCCEEDED(mainThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL)); }
void CacheFileOutputStream::NotifyListener() { mFile->AssertOwnsLock(); LOG(("CacheFileOutputStream::NotifyListener() [this=%p]", this)); MOZ_ASSERT(mCallback); if (!mCallbackTarget) { mCallbackTarget = CacheFileIOManager::IOTarget(); if (!mCallbackTarget) { LOG(("CacheFileOutputStream::NotifyListener() - Cannot get Cache I/O " "thread! Using main thread for callback.")); mCallbackTarget = do_GetMainThread(); } } nsCOMPtr<nsIOutputStreamCallback> asyncCallback = NS_NewOutputStreamReadyEvent(mCallback, mCallbackTarget); mCallback = nullptr; mCallbackTarget = nullptr; asyncCallback->OnOutputStreamReady(this); }
void ReadbackManagerD3D11::ProcessTasks() { HANDLE handles[] = { mTaskSemaphore, mShutdownEvent }; while (true) { DWORD result = ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); if (result != WAIT_OBJECT_0) { return; } ::EnterCriticalSection(&mTaskMutex); if (mPendingReadbackTasks.Length() == 0) { NS_RUNTIMEABORT("Trying to read from an empty array, bad bad bad"); } ReadbackTask *nextReadbackTask = mPendingReadbackTasks[0].forget(); mPendingReadbackTasks.RemoveElementAt(0); ::LeaveCriticalSection(&mTaskMutex); // We want to block here until the texture contents are available, the // easiest thing is to simply map and unmap. D3D10_MAPPED_TEXTURE2D mappedTex; nextReadbackTask->mReadbackTexture->Map(0, D3D10_MAP_READ, 0, &mappedTex); nextReadbackTask->mReadbackTexture->Unmap(0); // We can only send the update to the sink on the main thread, so post an // event there to do so. Ownership of the task is passed from // mPendingReadbackTasks to ReadbackResultWriter here. nsCOMPtr<nsIThread> thread = do_GetMainThread(); thread->Dispatch(new ReadbackResultWriterD3D11(nextReadbackTask), nsIEventTarget::DISPATCH_NORMAL); } }
void DecodedStream::Start(int64_t aStartTime, const MediaInfo& aInfo) { AssertOwnerThread(); MOZ_ASSERT(mStartTime.isNothing(), "playback already started."); mStartTime.emplace(aStartTime); mInfo = aInfo; mPlaying = true; ConnectListener(); class R : public Runnable { typedef MozPromiseHolder<GenericPromise> Promise; public: R(PlaybackInfoInit&& aInit, Promise&& aPromise, OutputStreamManager* aManager) : mInit(Move(aInit)), mOutputStreamManager(aManager) { mPromise = Move(aPromise); } NS_IMETHOD Run() override { MOZ_ASSERT(NS_IsMainThread()); // No need to create a source stream when there are no output streams. This // happens when RemoveOutput() is called immediately after StartPlayback(). if (!mOutputStreamManager->Graph()) { // Resolve the promise to indicate the end of playback. mPromise.Resolve(true, __func__); return NS_OK; } mData = MakeUnique<DecodedStreamData>( mOutputStreamManager, Move(mInit), Move(mPromise)); return NS_OK; } UniquePtr<DecodedStreamData> ReleaseData() { return Move(mData); } private: PlaybackInfoInit mInit; Promise mPromise; RefPtr<OutputStreamManager> mOutputStreamManager; UniquePtr<DecodedStreamData> mData; }; MozPromiseHolder<GenericPromise> promise; mFinishPromise = promise.Ensure(__func__); PlaybackInfoInit init { aStartTime, aInfo }; nsCOMPtr<nsIRunnable> r = new R(Move(init), Move(promise), mOutputStreamManager); nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); SyncRunnable::DispatchToThread(mainThread, r); mData = static_cast<R*>(r.get())->ReleaseData(); if (mData) { mData->SetPlaying(mPlaying); SendData(); } }
~nsWyciwygAsyncEvent() { nsCOMPtr<nsIThread> thread = do_GetMainThread(); NS_WARN_IF_FALSE(thread, "Couldn't get the main thread!"); if (thread) { nsIWyciwygChannel *chan = static_cast<nsIWyciwygChannel *>(mChannel); mozilla::unused << mChannel.forget(); NS_ProxyRelease(thread, chan); } }
JavaXPCOMInstance::~JavaXPCOMInstance() { nsresult rv = NS_OK; // Need to release these objects on the main thread. nsCOMPtr<nsIThread> thread = do_GetMainThread(); if (thread) { rv = NS_ProxyRelease(thread, mInstance); rv |= NS_ProxyRelease(thread, mIInfo); } NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to release using NS_ProxyRelease"); }
bool CrashReporterParent::GenerateChildData(const AnnotationTable* processNotes) { MOZ_ASSERT(mInitialized); nsAutoCString type; switch (mProcessType) { case GeckoProcessType_Content: type = NS_LITERAL_CSTRING("content"); break; case GeckoProcessType_Plugin: case GeckoProcessType_GMPlugin: type = NS_LITERAL_CSTRING("plugin"); break; default: NS_ERROR("unknown process type"); break; } mNotes.Put(NS_LITERAL_CSTRING("ProcessType"), type); char startTime[32]; sprintf(startTime, "%lld", static_cast<long long>(mStartTime)); mNotes.Put(NS_LITERAL_CSTRING("StartupTime"), nsDependentCString(startTime)); if (!mAppNotes.IsEmpty()) mNotes.Put(NS_LITERAL_CSTRING("Notes"), mAppNotes); bool ret = CrashReporter::AppendExtraData(mChildDumpID, mNotes); if (ret && processNotes) ret = CrashReporter::AppendExtraData(mChildDumpID, *processNotes); if (!ret) NS_WARNING("problem appending child data to .extra"); nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); class NotifyOnMainThread : public nsRunnable { public: NotifyOnMainThread(CrashReporterParent* aCR) : mCR(aCR) { } NS_IMETHOD Run() { mCR->NotifyCrashService(); return NS_OK; } private: CrashReporterParent* mCR; }; SyncRunnable::DispatchToThread(mainThread, new NotifyOnMainThread(this)); return ret; }
void HRTFDatabaseLoader::ProxyRelease() { nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); if (MOZ_LIKELY(mainThread)) { RefPtr<ProxyReleaseEvent> event = new ProxyReleaseEvent(this); DebugOnly<nsresult> rv = mainThread->Dispatch(event, NS_DISPATCH_NORMAL); MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to dispatch release event"); } else { // Should be in XPCOM shutdown. MOZ_ASSERT(NS_IsMainThread(), "Main thread is not available for dispatch."); MainThreadRelease(); } }
ManagerId::~ManagerId() { // If we're already on the main thread, then default destruction is fine if (NS_IsMainThread()) { return; } // Otherwise we need to proxy to main thread to do the release // The PBackground worker thread shouldn't be running after the main thread // is stopped. So main thread is guaranteed to exist here. nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); MOZ_ASSERT(mainThread); NS_ProxyRelease(mainThread, mPrincipal.forget().take()); }
nsHTTPListener::~nsHTTPListener() { if (mResponsibleForDoneSignal) send_done_signal(); if (mCondition) PR_DestroyCondVar(mCondition); if (mLock) PR_DestroyLock(mLock); if (mLoader) { nsCOMPtr<nsIThread> mainThread(do_GetMainThread()); NS_ProxyRelease(mainThread, mLoader); } }
nsrefcnt nsXPCWrappedJS::Release(void) { NS_PRECONDITION(0 != mRefCnt, "dup release"); if (mMainThreadOnly && !NS_IsMainThread()) { // We'd like to abort here, but this can happen if someone uses a proxy // for the nsXPCWrappedJS. nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); // If we can't get the main thread anymore we just leak, but this really // shouldn't happen. NS_ASSERTION(mainThread, "Can't get main thread, leaking nsXPCWrappedJS!"); if (mainThread) { NS_ProxyRelease(mainThread, static_cast<nsIXPConnectWrappedJS*>(this)); } return mRefCnt; } // need to take the map lock here to prevent GetNewOrUsed from trying // to reuse a wrapper on one thread while it's being destroyed on another XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance(); XPCAutoLock lock(rt->GetMapLock()); do_decrement: nsrefcnt cnt = NS_AtomicDecrementRefcnt(mRefCnt); NS_LOG_RELEASE(this, cnt, "nsXPCWrappedJS"); if (0 == cnt) { delete this; // also unlinks us from chain return 0; } if (1 == cnt) { if (IsValid()) RemoveFromRootSet(rt->GetMapLock()); // If we are not the root wrapper or if we are not being used from a // weak reference, then this extra ref is not needed and we can let // ourself be deleted. // Note: HasWeakReferences() could only return true for the root. if (!HasWeakReferences()) goto do_decrement; } return cnt; }
/** * Free all used memory and close stream. */ NS_IMETHODIMP nsGIOInputStream::Close() { if (mStream) { g_object_unref(mStream); mStream = nullptr; } if (mHandle) { g_object_unref(mHandle); mHandle = nullptr; } if (mDirList) { // Destroy the list of GIOFileInfo objects... g_list_foreach(mDirList, (GFunc) g_object_unref, nullptr); g_list_free(mDirList); mDirList = nullptr; mDirListPtr = nullptr; } if (mChannel) { nsresult rv = NS_OK; nsCOMPtr<nsIThread> thread = do_GetMainThread(); if (thread) rv = NS_ProxyRelease(thread, mChannel); NS_ASSERTION(thread && NS_SUCCEEDED(rv), "leaking channel reference"); mChannel = nullptr; (void) rv; } mSpec.Truncate(); // free memory // Prevent future reads from re-opening the handle. if (NS_SUCCEEDED(mStatus)) mStatus = NS_BASE_STREAM_CLOSED; return NS_OK; }
JavaXPCOMInstance::~JavaXPCOMInstance() { nsresult rv = NS_OK; #ifdef VBOX nsCOMPtr<nsIEventQueue> eq = do_GetMainThreadQueue(); rv = NS_ProxyRelease(eq.get(), mInstance); rv |= NS_ProxyRelease(eq.get(), mIInfo); #else // Need to release these objects on the main thread. nsCOMPtr<nsIThread> thread = do_GetMainThread(); if (thread) { rv = NS_ProxyRelease(thread, mInstance); rv |= NS_ProxyRelease(thread, mIInfo); } #endif NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to release using NS_ProxyRelease"); }
NS_IMETHOD Run() { mDict->SyncLoad(); // Release the dictionary on the main thread mozPersonalDictionary *dict; mDict.forget(&dict); nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); if (mainThread) { NS_ProxyRelease(mainThread, static_cast<mozIPersonalDictionary *>(dict)); } else { // It's better to leak the dictionary than to release it on a wrong thread NS_WARNING("Cannot get main thread, leaking mozPersonalDictionary."); } return NS_OK; }
PGMPContentParent* GMPServiceChild::AllocPGMPContentParent(Transport* aTransport, ProcessId aOtherPid) { MOZ_ASSERT(!mContentParents.GetWeak(aOtherPid)); nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); MOZ_ASSERT(mainThread); nsRefPtr<GMPContentParent> parent = new GMPContentParent(); DebugOnly<bool> ok = parent->Open(aTransport, aOtherPid, XRE_GetIOMessageLoop(), mozilla::ipc::ParentSide); MOZ_ASSERT(ok); mContentParents.Put(aOtherPid, parent); return parent; }
// We store the records in files in the system temp dir. static nsresult GetGMPStorageDir(nsIFile** aTempDir, const nsString& aOrigin) { if (NS_WARN_IF(!aTempDir)) { return NS_ERROR_INVALID_ARG; } // Directory service is main thread only... nsRefPtr<GetTempDirTask> task = new GetTempDirTask(); nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); mozilla::SyncRunnable::DispatchToThread(mainThread, task); nsCOMPtr<nsIFile> tmpFile; nsresult rv = NS_NewLocalFile(task->mPath, false, getter_AddRefs(tmpFile)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } rv = tmpFile->AppendNative(nsDependentCString("mozilla-gmp-storage")); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // TODO: When aOrigin is the same node-id as the GMP sees in the child // process (a UUID or somesuch), we can just append it un-hashed here. // This should reduce the chance of hash collsions exposing data. nsAutoString nodeIdHash; nodeIdHash.AppendInt(HashString(static_cast<const char16_t*>(aOrigin.get()))); rv = tmpFile->Append(nodeIdHash); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700); if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) { return rv; } tmpFile.forget(aTempDir); return NS_OK; }
nsresult nsDNSPrefetch::Prefetch(uint16_t flags) { if (mHostname.IsEmpty()) return NS_ERROR_NOT_AVAILABLE; if (!sDNSService) return NS_ERROR_NOT_AVAILABLE; nsCOMPtr<nsICancelable> tmpOutstanding; if (mStoreTiming) mStartTimestamp = mozilla::TimeStamp::Now(); // If AsyncResolve fails, for example because prefetching is disabled, // then our timing will be useless. However, in such a case, // mEndTimestamp will be a null timestamp and callers should check // TimingsValid() before using the timing. nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); return sDNSService->AsyncResolve(mHostname, flags | nsIDNSService::RESOLVE_SPECULATE, this, mainThread, getter_AddRefs(tmpOutstanding)); }
NS_IMETHOD Run() override { nsresult res; MOZ_ASSERT(!NS_IsMainThread()); { mozilla::MonitorAutoLock mon(mDict->mMonitorSave); nsCOMPtr<nsIOutputStream> outStream; NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStream), mFile, PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE, 0664); // Get a buffered output stream 4096 bytes big, to optimize writes. nsCOMPtr<nsIOutputStream> bufferedOutputStream; res = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), outStream, 4096); if (NS_FAILED(res)) { return res; } uint32_t bytesWritten; nsAutoCString utf8Key; for (uint32_t i = 0; i < mDictWords.Length(); ++i) { CopyUTF16toUTF8(mDictWords[i], utf8Key); bufferedOutputStream->Write(utf8Key.get(), utf8Key.Length(), &bytesWritten); bufferedOutputStream->Write("\n", 1, &bytesWritten); } nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(bufferedOutputStream); NS_ASSERTION(safeStream, "expected a safe output stream!"); if (safeStream) { res = safeStream->Finish(); if (NS_FAILED(res)) { NS_WARNING("failed to save personal dictionary file! possible data loss"); } } // Save is done, reset the state variable and notify those who are waiting. mDict->mSavePending = false; mon.Notify(); // Leaving the block where 'mon' was declared will call the destructor // and unlock. } // Release the dictionary on the main thread. mozPersonalDictionary *dict; mDict.forget(&dict); nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); if (mainThread) { NS_ProxyRelease(mainThread, static_cast<mozIPersonalDictionary *>(dict)); } else { // It's better to leak the dictionary than to release it on a wrong thread. NS_WARNING("Cannot get main thread, leaking mozPersonalDictionary."); } return NS_OK; }
NS_IMETHODIMP nsProxyObjectManager::GetProxyForObject(nsIEventTarget* aTarget, REFNSIID aIID, nsISupports* aObj, PRInt32 proxyType, void** aProxyObject) { NS_ENSURE_ARG_POINTER(aObj); *aProxyObject = nsnull; // handle special values nsCOMPtr<nsIThread> thread; if (aTarget == NS_PROXY_TO_CURRENT_THREAD) { aTarget = NS_GetCurrentThread(); } else if (aTarget == NS_PROXY_TO_MAIN_THREAD) { thread = do_GetMainThread(); aTarget = thread.get(); } // check to see if the target is on our thread. If so, just return the // real object. if (!(proxyType & NS_PROXY_ASYNC) && !(proxyType & NS_PROXY_ALWAYS)) { PRBool result; aTarget->IsOnCurrentThread(&result); if (result) return aObj->QueryInterface(aIID, aProxyObject); } nsCOMPtr<nsISupports> realObj = do_QueryInterface(aObj); // Make sure the object passed in is not a proxy; if it is, be nice and // build the proxy for the real object. nsCOMPtr<nsProxyObject> po = do_QueryInterface(aObj); if (po) { realObj = po->GetRealObject(); } nsCOMPtr<nsISupports> realEQ = do_QueryInterface(aTarget); nsProxyEventKey rootKey(realObj, realEQ, proxyType); { nsAutoLock lock(mProxyCreationLock); nsProxyLockedRefPtr root = (nsProxyObject*) mProxyObjectMap.Get(&rootKey); if (root) return root->LockedFind(aIID, aProxyObject); } // don't lock while creating the nsProxyObject nsProxyObject *newRoot = new nsProxyObject(aTarget, proxyType, realObj); if (!newRoot) return NS_ERROR_OUT_OF_MEMORY; // lock again, and check for a race putting into mProxyObjectMap { nsAutoLock lock(mProxyCreationLock); nsProxyLockedRefPtr root = (nsProxyObject*) mProxyObjectMap.Get(&rootKey); if (root) { delete newRoot; return root->LockedFind(aIID, aProxyObject); } mProxyObjectMap.Put(&rootKey, newRoot); nsProxyLockedRefPtr kungFuDeathGrip(newRoot); return newRoot->LockedFind(aIID, aProxyObject); } }
TracerRunnable() { mTracerLock = new Mutex("TracerRunnable"); mTracerCondVar = new CondVar(*mTracerLock, "TracerRunnable"); mMainThread = do_GetMainThread(); }
/* static */ void CrashReporterHost::NotifyCrashService(GeckoProcessType aProcessType, const nsString& aChildDumpID, const AnnotationTable* aNotes) { if (!NS_IsMainThread()) { RefPtr<Runnable> runnable = NS_NewRunnableFunction( "ipc::CrashReporterHost::NotifyCrashService", [=]() -> void { CrashReporterHost::NotifyCrashService( aProcessType, aChildDumpID, aNotes); }); RefPtr<nsIThread> mainThread = do_GetMainThread(); SyncRunnable::DispatchToThread(mainThread, runnable); return; } MOZ_ASSERT(!aChildDumpID.IsEmpty()); nsCOMPtr<nsICrashService> crashService = do_GetService("@mozilla.org/crashservice;1"); if (!crashService) { return; } int32_t processType; int32_t crashType = nsICrashService::CRASH_TYPE_CRASH; nsCString telemetryKey; switch (aProcessType) { case GeckoProcessType_Content: processType = nsICrashService::PROCESS_TYPE_CONTENT; telemetryKey.AssignLiteral("content"); break; case GeckoProcessType_Plugin: { processType = nsICrashService::PROCESS_TYPE_PLUGIN; telemetryKey.AssignLiteral("plugin"); nsAutoCString val; if (aNotes->Get(NS_LITERAL_CSTRING("PluginHang"), &val) && val.EqualsLiteral("1")) { crashType = nsICrashService::CRASH_TYPE_HANG; telemetryKey.AssignLiteral("pluginhang"); } break; } case GeckoProcessType_GMPlugin: processType = nsICrashService::PROCESS_TYPE_GMPLUGIN; telemetryKey.AssignLiteral("gmplugin"); break; case GeckoProcessType_GPU: processType = nsICrashService::PROCESS_TYPE_GPU; telemetryKey.AssignLiteral("gpu"); break; default: NS_ERROR("unknown process type"); return; } nsCOMPtr<nsISupports> promise; crashService->AddCrash(processType, crashType, aChildDumpID, getter_AddRefs(promise)); Telemetry::Accumulate(Telemetry::SUBPROCESS_CRASHES_WITH_DUMP, telemetryKey, 1); }