void nsThreadManager::Shutdown() { NS_ASSERTION(NS_IsMainThread(), "shutdown not called from main thread"); // Prevent further access to the thread manager (no more new threads!) // // XXX What happens if shutdown happens before NewThread completes? // Fortunately, NewThread is only called on the main thread for now. // mInitialized = PR_FALSE; // Empty the main thread event queue before we begin shutting down threads. NS_ProcessPendingEvents(mMainThread); // We gather the threads from the hashtable into a list, so that we avoid // holding the hashtable lock while calling nsIThread::Shutdown. nsThreadArray threads; { nsAutoLock lock(mLock); mThreadsByPRThread.Enumerate(AppendAndRemoveThread, &threads); } // It's tempting to walk the list of threads here and tell them each to stop // accepting new events, but that could lead to badness if one of those // threads is stuck waiting for a response from another thread. To do it // right, we'd need some way to interrupt the threads. // // Instead, we process events on the current thread while waiting for threads // to shutdown. This means that we have to preserve a mostly functioning // world until such time as the threads exit. // Shutdown all threads that require it (join with threads that we created). for (PRUint32 i = 0; i < threads.Length(); ++i) { nsThread *thread = threads[i]; if (thread->ShutdownRequired()) thread->Shutdown(); } // In case there are any more events somehow... NS_ProcessPendingEvents(mMainThread); // There are no more background threads at this point. // Clear the table of threads. { nsAutoLock lock(mLock); mThreadsByPRThread.Clear(); } // Release main thread object. mMainThread = nsnull; // Remove the TLS entry for the main thread. PR_SetThreadPrivate(mCurThreadIndex, nsnull); // We don't need this lock anymore. PR_DestroyLock(mLock); mLock = nsnull; }
nsresult FileService::Cleanup() { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); nsIThread* thread = NS_GetCurrentThread(); while (mFileStorageInfos.Count()) { if (!NS_ProcessNextEvent(thread)) { NS_ERROR("Failed to process next event!"); break; } } // Make sure the service is still accessible while any generated callbacks // are processed. nsresult rv = NS_ProcessPendingEvents(thread); NS_ENSURE_SUCCESS(rv, rv); if (!mCompleteCallbacks.IsEmpty()) { // Run all callbacks manually now. for (PRUint32 index = 0; index < mCompleteCallbacks.Length(); index++) { mCompleteCallbacks[index].mCallback->Run(); } mCompleteCallbacks.Clear(); // And make sure they get processed. rv = NS_ProcessPendingEvents(thread); NS_ENSURE_SUCCESS(rv, rv); } return NS_OK; }
NS_IMETHODIMP nsSocketTransportService::Run() { LOG(("STS thread init\n")); gSocketThread = PR_GetCurrentThread(); // add thread event to poll list (mThreadEvent may be NULL) mPollList[0].fd = mThreadEvent; mPollList[0].in_flags = PR_POLL_READ; mPollList[0].out_flags = 0; nsIThread *thread = NS_GetCurrentThread(); // hook ourselves up to observe event processing for this thread nsCOMPtr<nsIThreadInternal> threadInt = do_QueryInterface(thread); threadInt->SetObserver(this); for (;;) { // process all pending events NS_ProcessPendingEvents(thread); // now that our event queue is empty, check to see if we should exit { nsAutoLock lock(mLock); if (mShuttingDown) break; } // wait for and process the next pending event NS_ProcessNextEvent(thread); } LOG(("STS shutting down thread\n")); // detach any sockets PRInt32 i; for (i=mActiveCount-1; i>=0; --i) DetachSocket(&mActiveList[i]); for (i=mIdleCount-1; i>=0; --i) DetachSocket(&mIdleList[i]); // Final pass over the event queue. This makes sure that events posted by // socket detach handlers get processed. NS_ProcessPendingEvents(thread); gSocketThread = nsnull; LOG(("STS thread exit\n")); return NS_OK; }
int main(int argc, char** argv) { ScopedXPCOM xpcom("ThreadUtils"); NS_ENSURE_FALSE(xpcom.failed(), 1); memset(gRunnableExecuted, false, MAX_TESTS * sizeof(bool)); // Scope the smart ptrs so that the runnables need to hold on to whatever they need { nsRefPtr<nsFoo> foo = new nsFoo(); nsRefPtr<nsBar> bar = new nsBar(); // This pointer will be freed at the end of the block // Do not dereference this pointer in the runnable method! nsFoo * rawFoo = new nsFoo(); // Read only string. Dereferencing in runnable method to check this works. char* message = (char*)"Test message"; NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar1)); NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar2)); NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> > (bar, &nsBar::DoBar3, foo)); NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> > (bar, &nsBar::DoBar4, foo)); NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<nsFoo*>(bar, &nsBar::DoBar5, rawFoo)); NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<char*>(bar, &nsBar::DoBar6, message)); #ifdef HAVE_STDCALL NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar1std)); NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar2std)); NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> > (bar, &nsBar::DoBar3std, foo)); NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< nsRefPtr<nsFoo> > (bar, &nsBar::DoBar4std, foo)); NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<nsFoo*>(bar, &nsBar::DoBar5std, rawFoo)); NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<char*>(bar, &nsBar::DoBar6std, message)); #endif delete rawFoo; } // Spin the event loop NS_ProcessPendingEvents(nullptr); int result = 0; for (uint32_t i = 0; i < MAX_TESTS; i++) { if (gRunnableExecuted[i]) { passed("Test %d passed",i); } else { fail("Error in test %d", i); result = 1; } } return result; }
static JSBool FlushEventQueue(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { nsJSSh* shell; if (!GetJSShGlobal(cx, obj, &shell)) return JS_FALSE; NS_ProcessPendingEvents(nsnull); return JS_TRUE; }
NS_IMETHODIMP nsBaseAppShell::Run(void) { NS_ENSURE_STATE(!mRunning); // should not call Run twice mRunning = true; nsIThread *thread = NS_GetCurrentThread(); MessageLoop::current()->Run(); NS_ProcessPendingEvents(thread); mRunning = false; return NS_OK; }
// Called by nsAppShell's native event callback void nsBaseAppShell::NativeEventCallback() { int32_t hasPending = PR_ATOMIC_SET(&mNativeEventPending, 0); if (hasPending == 0) return; // If DoProcessNextNativeEvent is on the stack, then we assume that we can // just unwind and let nsThread::ProcessNextEvent process the next event. // However, if we are called from a nested native event loop (maybe via some // plug-in or library function), then go ahead and process Gecko events now. if (mEventloopNestingState == eEventloopXPCOM) { mEventloopNestingState = eEventloopOther; // XXX there is a tiny risk we will never get a new NativeEventCallback, // XXX see discussion in bug 389931. return; } // nsBaseAppShell::Run is not being used to pump events, so this may be // our only opportunity to process pending gecko events. nsIThread *thread = NS_GetCurrentThread(); bool prevBlockNativeEvent = mBlockNativeEvent; if (mEventloopNestingState == eEventloopOther) { if (!NS_HasPendingEvents(thread)) return; // We're in a nested native event loop and have some gecko events to // process. While doing that we block processing native events from the // appshell - instead, we want to get back to the nested native event // loop ASAP (bug 420148). mBlockNativeEvent = true; } ++mEventloopNestingLevel; EventloopNestingState prevVal = mEventloopNestingState; NS_ProcessPendingEvents(thread, THREAD_EVENT_STARVATION_LIMIT); mProcessedGeckoEvents = true; mEventloopNestingState = prevVal; mBlockNativeEvent = prevBlockNativeEvent; // Continue processing pending events later (we don't want to starve the // embedders event loop). if (NS_HasPendingEvents(thread)) DoProcessMoreGeckoEvents(); --mEventloopNestingLevel; }
NS_IMETHODIMP nsBaseAppShell::Run(void) { NS_ENSURE_STATE(!mRunning); // should not call Run twice mRunning = PR_TRUE; nsIThread *thread = NS_GetCurrentThread(); #ifdef MOZ_IPC MessageLoop::current()->Run(); #else while (!mExiting) NS_ProcessNextEvent(thread); #endif NS_ProcessPendingEvents(thread); mRunning = PR_FALSE; return NS_OK; }
template <uint32_t K> static bool test_random() { srand(K); error = false; for (uint32_t j = 0; j < iterations; ++j) { Tracker<K> tracker; uint32_t i = 0; for (i = 0; i < ops; ++i) { if ((rand() & 0xF) == 0) { // Simulate work that takes time if (logging) { printf("SLEEPING for %dms (%d)\n", sleepPeriodMS, PR_IntervalNow()); } PR_Sleep(PR_MillisecondsToInterval(sleepPeriodMS)); // Process pending timer events NS_ProcessPendingEvents(nullptr); } tracker.DoRandomOperation(); } } return !error; }
nsresult nsMsgCopy::DoCopy(nsIFile *aDiskFile, nsIMsgFolder *dstFolder, nsIMsgDBHdr *aMsgToReplace, bool aIsDraft, nsIMsgWindow *msgWindow, nsIMsgSend *aMsgSendObj) { nsresult rv = NS_OK; // Check sanity if ((!aDiskFile) || (!dstFolder)) return NS_ERROR_INVALID_ARG; //Call copyservice with dstFolder, disk file, and txnManager if(NS_SUCCEEDED(rv)) { nsRefPtr<CopyListener> copyListener = new CopyListener(); if (!copyListener) return NS_ERROR_OUT_OF_MEMORY; copyListener->SetMsgComposeAndSendObject(aMsgSendObj); nsCOMPtr<nsIThread> thread; if (aIsDraft) { nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(dstFolder); nsCOMPtr<nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv); if (NS_FAILED(rv)) return rv; bool shutdownInProgress = false; rv = accountManager->GetShutdownInProgress(&shutdownInProgress); if (NS_SUCCEEDED(rv) && shutdownInProgress && imapFolder) { // set the following only when we were in the middle of shutdown // process copyListener->mCopyInProgress = true; thread = do_GetCurrentThread(); } } nsCOMPtr<nsIMsgCopyService> copyService = do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = copyService->CopyFileMessage(aDiskFile, dstFolder, aMsgToReplace, aIsDraft, aIsDraft ? 0 : nsMsgMessageFlags::Read, EmptyCString(), copyListener, msgWindow); // copyListener->mCopyInProgress can only be set when we are in the // middle of the shutdown process while (copyListener->mCopyInProgress) { PR_CEnterMonitor(copyListener); PR_CWait(copyListener, PR_MicrosecondsToInterval(1000UL)); PR_CExitMonitor(copyListener); if (thread) NS_ProcessPendingEvents(thread); } } return rv; }
nsresult ShutdownXPCOM(nsIServiceManager* servMgr) { // Make sure the hang monitor is enabled for shutdown. HangMonitor::NotifyActivity(); NS_ENSURE_STATE(NS_IsMainThread()); nsresult rv; nsCOMPtr<nsISimpleEnumerator> moduleLoaders; // Notify observers of xpcom shutting down { // Block it so that the COMPtr will get deleted before we hit // servicemanager shutdown nsCOMPtr<nsIThread> thread = do_GetCurrentThread(); NS_ENSURE_STATE(thread); nsRefPtr<nsObserverService> observerService; CallGetService("@mozilla.org/observer-service;1", (nsObserverService**) getter_AddRefs(observerService)); if (observerService) { (void) observerService-> NotifyObservers(nullptr, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, nullptr); nsCOMPtr<nsIServiceManager> mgr; rv = NS_GetServiceManager(getter_AddRefs(mgr)); if (NS_SUCCEEDED(rv)) { (void) observerService-> NotifyObservers(mgr, NS_XPCOM_SHUTDOWN_OBSERVER_ID, nullptr); } } NS_ProcessPendingEvents(thread); mozilla::scache::StartupCache::DeleteSingleton(); if (observerService) (void) observerService-> NotifyObservers(nullptr, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, nullptr); nsCycleCollector_shutdownThreads(); NS_ProcessPendingEvents(thread); // Shutdown the timer thread and all timers that might still be alive before // shutting down the component manager nsTimerImpl::Shutdown(); NS_ProcessPendingEvents(thread); // Shutdown all remaining threads. This method does not return until // all threads created using the thread manager (with the exception of // the main thread) have exited. nsThreadManager::get()->Shutdown(); NS_ProcessPendingEvents(thread); HangMonitor::NotifyActivity(); // We save the "xpcom-shutdown-loaders" observers to notify after // the observerservice is gone. if (observerService) { observerService-> EnumerateObservers(NS_XPCOM_SHUTDOWN_LOADERS_OBSERVER_ID, getter_AddRefs(moduleLoaders)); observerService->Shutdown(); } } // Free ClearOnShutdown()'ed smart pointers. This needs to happen *after* // we've finished notifying observers of XPCOM shutdown, because shutdown // observers themselves might call ClearOnShutdown(). mozilla::KillClearOnShutdown(); // XPCOM is officially in shutdown mode NOW // Set this only after the observers have been notified as this // will cause servicemanager to become inaccessible. mozilla::services::Shutdown(); #ifdef DEBUG_dougt fprintf(stderr, "* * * * XPCOM shutdown. Access will be denied * * * * \n"); #endif // We may have AddRef'd for the caller of NS_InitXPCOM, so release it // here again: NS_IF_RELEASE(servMgr); // Shutdown global servicemanager if (nsComponentManagerImpl::gComponentManager) { nsComponentManagerImpl::gComponentManager->FreeServices(); } // Release the directory service NS_IF_RELEASE(nsDirectoryService::gService); SAMPLE_MARKER("Shutdown xpcom"); mozilla::PoisonWrite(); nsCycleCollector_shutdown(); if (moduleLoaders) { bool more; nsCOMPtr<nsISupports> el; while (NS_SUCCEEDED(moduleLoaders->HasMoreElements(&more)) && more) { moduleLoaders->GetNext(getter_AddRefs(el)); // Don't worry about weak-reference observers here: there is // no reason for weak-ref observers to register for // xpcom-shutdown-loaders nsCOMPtr<nsIObserver> obs(do_QueryInterface(el)); if (obs) (void) obs->Observe(nullptr, NS_XPCOM_SHUTDOWN_LOADERS_OBSERVER_ID, nullptr); } moduleLoaders = nullptr; } // Shutdown nsLocalFile string conversion NS_ShutdownLocalFile(); #ifdef XP_UNIX NS_ShutdownNativeCharsetUtils(); #endif // Shutdown xpcom. This will release all loaders and cause others holding // a refcount to the component manager to release it. if (nsComponentManagerImpl::gComponentManager) { rv = (nsComponentManagerImpl::gComponentManager)->Shutdown(); NS_ASSERTION(NS_SUCCEEDED(rv), "Component Manager shutdown failed."); } else NS_WARNING("Component Manager was never created ..."); // Release our own singletons // Do this _after_ shutting down the component manager, because the // JS component loader will use XPConnect to call nsIModule::canUnload, // and that will spin up the InterfaceInfoManager again -- bad mojo xptiInterfaceInfoManager::FreeInterfaceInfoManager(); // Finally, release the component manager last because it unloads the // libraries: if (nsComponentManagerImpl::gComponentManager) { nsrefcnt cnt; NS_RELEASE2(nsComponentManagerImpl::gComponentManager, cnt); NS_ASSERTION(cnt == 0, "Component Manager being held past XPCOM shutdown."); } nsComponentManagerImpl::gComponentManager = nullptr; nsCategoryManager::Destroy(); NS_PurgeAtomTable(); NS_IF_RELEASE(gDebug); if (sIOThread) { delete sIOThread; sIOThread = nullptr; } if (sMessageLoop) { delete sMessageLoop; sMessageLoop = nullptr; } if (sCommandLineWasInitialized) { CommandLine::Terminate(); sCommandLineWasInitialized = false; } if (sExitManager) { delete sExitManager; sExitManager = nullptr; } Omnijar::CleanUp(); HangMonitor::Shutdown(); eventtracer::Shutdown(); NS_LogTerm(); return NS_OK; }
bool DBusWatcher::Poll() { int res = TEMP_FAILURE_RETRY(poll(mPollData.Elements(), mPollData.Length(), -1)); NS_ENSURE_TRUE(res > 0, false); bool continueThread = true; nsTArray<pollfd>::size_type i = 0; while (i < mPollData.Length()) { if (mPollData[i].revents == POLLIN) { if (mPollData[i].fd == mControlFdR.get()) { char data; res = TEMP_FAILURE_RETRY(read(mControlFdR.get(), &data, sizeof(data))); NS_ENSURE_TRUE(res > 0, false); switch (data) { case DBUS_EVENT_LOOP_EXIT: continueThread = false; break; case DBUS_EVENT_LOOP_ADD: HandleWatchAdd(); break; case DBUS_EVENT_LOOP_REMOVE: HandleWatchRemove(); // don't increment i, or we'll skip one element continue; case DBUS_EVENT_LOOP_WAKEUP: NS_ProcessPendingEvents(NS_GetCurrentThread(), PR_INTERVAL_NO_TIMEOUT); break; default: #if DEBUG nsCString warning("unknown command "); warning.AppendInt(data); NS_WARNING(warning.get()); #endif break; } } else { short events = mPollData[i].revents; mPollData[i].revents = 0; dbus_watch_handle(mWatchData[i], UnixEventsToDBusFlags(events)); DBusDispatchStatus dbusDispatchStatus; do { dbusDispatchStatus = dbus_connection_dispatch(GetConnection()); } while (dbusDispatchStatus == DBUS_DISPATCH_DATA_REMAINS); // Break at this point since we don't know if the operation // was destructive break; } } ++i; } return continueThread; }
// this is used for Send without UI nsresult nsMapiHook::BlindSendMail (unsigned long aSession, nsIMsgCompFields * aCompFields) { nsresult rv = NS_OK ; if (!IsBlindSendAllowed()) return NS_ERROR_FAILURE; /** create nsIMsgComposeParams obj and other fields to populate it **/ nsCOMPtr<nsIDOMWindowInternal> hiddenWindow; // get parent window nsCOMPtr<nsIAppShellService> appService = do_GetService( "@mozilla.org/appshell/appShellService;1", &rv); if (NS_FAILED(rv)|| (!appService) ) return rv ; rv = appService->GetHiddenDOMWindow(getter_AddRefs(hiddenWindow)); if ( NS_FAILED(rv) ) return rv ; // smtp password and Logged in used IdKey from MapiConfig (session obj) nsMAPIConfiguration * pMapiConfig = nsMAPIConfiguration::GetMAPIConfiguration() ; if (!pMapiConfig) return NS_ERROR_FAILURE ; // get the singelton obj PRUnichar * password = pMapiConfig->GetPassword(aSession) ; // password nsCAutoString smtpPassword; LossyCopyUTF16toASCII(password, smtpPassword); // Id key nsCString MsgIdKey; pMapiConfig->GetIdKey(aSession, MsgIdKey); // get the MsgIdentity for the above key using AccountManager nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService (NS_MSGACCOUNTMANAGER_CONTRACTID) ; if (NS_FAILED(rv) || (!accountManager) ) return rv ; nsCOMPtr <nsIMsgIdentity> pMsgId ; rv = accountManager->GetIdentity (MsgIdKey, getter_AddRefs(pMsgId)) ; if (NS_FAILED(rv) ) return rv ; // create a send listener to get back the send status nsCOMPtr <nsIMsgSendListener> sendListener ; rv = nsMAPISendListener::CreateMAPISendListener(getter_AddRefs(sendListener)) ; if (NS_FAILED(rv) || (!sendListener) ) return rv; // create the compose params object nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams (do_CreateInstance(NS_MSGCOMPOSEPARAMS_CONTRACTID, &rv)); if (NS_FAILED(rv) || (!pMsgComposeParams) ) return rv ; // populate the compose params PRBool forcePlainText; aCompFields->GetForcePlainText(&forcePlainText); pMsgComposeParams->SetType(nsIMsgCompType::New); pMsgComposeParams->SetFormat(forcePlainText ? nsIMsgCompFormat::PlainText : nsIMsgCompFormat::HTML); pMsgComposeParams->SetIdentity(pMsgId); pMsgComposeParams->SetComposeFields(aCompFields); pMsgComposeParams->SetSendListener(sendListener) ; pMsgComposeParams->SetSmtpPassword(smtpPassword.get()); // create the nsIMsgCompose object to send the object nsCOMPtr<nsIMsgCompose> pMsgCompose (do_CreateInstance(NS_MSGCOMPOSE_CONTRACTID, &rv)); if (NS_FAILED(rv) || (!pMsgCompose) ) return rv ; /** initialize nsIMsgCompose, Send the message, wait for send completion response **/ rv = pMsgCompose->Initialize(hiddenWindow, pMsgComposeParams) ; if (NS_FAILED(rv)) return rv ; return pMsgCompose->SendMsg(nsIMsgSend::nsMsgDeliverNow, pMsgId, nsnull, nsnull, nsnull) ; if (NS_FAILED(rv)) return rv ; // assign to interface pointer from nsCOMPtr to facilitate typecast below nsIMsgSendListener * pSendListener = sendListener ; // we need to wait here to make sure that we return only after send is completed // so we will have a event loop here which will process the events till the Send IsDone. nsIThread *thread = NS_GetCurrentThread(); while ( !((nsMAPISendListener *) pSendListener)->IsDone() ) { PR_CEnterMonitor(pSendListener); PR_CWait(pSendListener, PR_MicrosecondsToInterval(1000UL)); PR_CExitMonitor(pSendListener); NS_ProcessPendingEvents(thread); } return rv ; }
NS_IMETHODIMP nsSocketTransportService::Run() { SOCKET_LOG(("STS thread init %d sockets\n", gMaxCount)); psm::InitializeSSLServerCertVerificationThreads(); gSocketThread = PR_GetCurrentThread(); { MutexAutoLock lock(mLock); mPollableEvent.reset(new PollableEvent()); // // NOTE: per bug 190000, this failure could be caused by Zone-Alarm // or similar software. // // NOTE: per bug 191739, this failure could also be caused by lack // of a loopback device on Windows and OS/2 platforms (it creates // a loopback socket pair on these platforms to implement a pollable // event object). if we can't create a pollable event, then we'll // have to "busy wait" to implement the socket event queue :-( // if (!mPollableEvent->Valid()) { mPollableEvent = nullptr; NS_WARNING("running socket transport thread without a pollable event"); SOCKET_LOG(("running socket transport thread without a pollable event")); } mPollList[0].fd = mPollableEvent ? mPollableEvent->PollableFD() : nullptr; mPollList[0].in_flags = PR_POLL_READ | PR_POLL_EXCEPT; mPollList[0].out_flags = 0; } mRawThread = NS_GetCurrentThread(); // hook ourselves up to observe event processing for this thread nsCOMPtr<nsIThreadInternal> threadInt = do_QueryInterface(mRawThread); threadInt->SetObserver(this); // make sure the pseudo random number generator is seeded on this thread srand(static_cast<unsigned>(PR_Now())); // For the calculation of the duration of the last cycle (i.e. the last for-loop // iteration before shutdown). TimeStamp startOfCycleForLastCycleCalc; int numberOfPendingEventsLastCycle; // For measuring of the poll iteration duration without time spent blocked // in poll(). TimeStamp pollCycleStart; // Time blocked in poll(). TimeDuration singlePollDuration; // For calculating the time needed for a new element to run. TimeStamp startOfIteration; TimeStamp startOfNextIteration; int numberOfPendingEvents; // If there is too many pending events queued, we will run some poll() // between them and the following variable is cumulative time spent // blocking in poll(). TimeDuration pollDuration; for (;;) { bool pendingEvents = false; numberOfPendingEvents = 0; numberOfPendingEventsLastCycle = 0; if (mTelemetryEnabledPref) { startOfCycleForLastCycleCalc = TimeStamp::NowLoRes(); startOfNextIteration = TimeStamp::NowLoRes(); } pollDuration = 0; do { if (mTelemetryEnabledPref) { pollCycleStart = TimeStamp::NowLoRes(); } DoPollIteration(&singlePollDuration); if (mTelemetryEnabledPref && !pollCycleStart.IsNull()) { Telemetry::Accumulate(Telemetry::STS_POLL_BLOCK_TIME, singlePollDuration.ToMilliseconds()); Telemetry::AccumulateTimeDelta( Telemetry::STS_POLL_CYCLE, pollCycleStart + singlePollDuration, TimeStamp::NowLoRes()); pollDuration += singlePollDuration; } mRawThread->HasPendingEvents(&pendingEvents); if (pendingEvents) { if (!mServingPendingQueue) { nsresult rv = Dispatch(NewRunnableMethod(this, &nsSocketTransportService::MarkTheLastElementOfPendingQueue), nsIEventTarget::DISPATCH_NORMAL); if (NS_FAILED(rv)) { NS_WARNING("Could not dispatch a new event on the " "socket thread."); } else { mServingPendingQueue = true; } if (mTelemetryEnabledPref) { startOfIteration = startOfNextIteration; // Everything that comes after this point will // be served in the next iteration. If no even // arrives, startOfNextIteration will be reset at the // beginning of each for-loop. startOfNextIteration = TimeStamp::NowLoRes(); } } TimeStamp eventQueueStart = TimeStamp::NowLoRes(); do { NS_ProcessNextEvent(mRawThread); numberOfPendingEvents++; pendingEvents = false; mRawThread->HasPendingEvents(&pendingEvents); } while (pendingEvents && mServingPendingQueue && ((TimeStamp::NowLoRes() - eventQueueStart).ToMilliseconds() < mMaxTimePerPollIter)); if (mTelemetryEnabledPref && !mServingPendingQueue && !startOfIteration.IsNull()) { Telemetry::AccumulateTimeDelta( Telemetry::STS_POLL_AND_EVENTS_CYCLE, startOfIteration + pollDuration, TimeStamp::NowLoRes()); Telemetry::Accumulate( Telemetry::STS_NUMBER_OF_PENDING_EVENTS, numberOfPendingEvents); numberOfPendingEventsLastCycle += numberOfPendingEvents; numberOfPendingEvents = 0; pollDuration = 0; } } } while (pendingEvents); bool goingOffline = false; // now that our event queue is empty, check to see if we should exit { MutexAutoLock lock(mLock); if (mShuttingDown) { if (mTelemetryEnabledPref && !startOfCycleForLastCycleCalc.IsNull()) { Telemetry::Accumulate( Telemetry::STS_NUMBER_OF_PENDING_EVENTS_IN_THE_LAST_CYCLE, numberOfPendingEventsLastCycle); Telemetry::AccumulateTimeDelta( Telemetry::STS_POLL_AND_EVENT_THE_LAST_CYCLE, startOfCycleForLastCycleCalc, TimeStamp::NowLoRes()); } break; } if (mGoingOffline) { mGoingOffline = false; goingOffline = true; } } // Avoid potential deadlock if (goingOffline) Reset(true); } SOCKET_LOG(("STS shutting down thread\n")); // detach all sockets, including locals Reset(false); // Final pass over the event queue. This makes sure that events posted by // socket detach handlers get processed. NS_ProcessPendingEvents(mRawThread); gSocketThread = nullptr; psm::StopSSLServerCertVerificationThreads(); SOCKET_LOG(("STS thread exit\n")); return NS_OK; }
NS_IMETHOD Run() { MOZ_ASSERT(!NS_IsMainThread()); bool exitThread = false; while (!exitThread) { int res = TEMP_FAILURE_RETRY(poll(mConnection->mPollData.Elements(), mConnection->mPollData.Length(), -1)); NS_ENSURE_TRUE(res > 0, NS_OK); nsTArray<pollfd>::size_type i = 0; while (i < mConnection->mPollData.Length()) { if (mConnection->mPollData[i].revents == POLLIN) { if (mConnection->mPollData[i].fd == mConnection->mControlFdR.get()) { char data; res = TEMP_FAILURE_RETRY(read(mConnection->mControlFdR.get(), &data, sizeof(data))); NS_ENSURE_TRUE(res > 0, NS_OK); switch (data) { case DBUS_EVENT_LOOP_EXIT: exitThread = true; break; case DBUS_EVENT_LOOP_ADD: HandleWatchAdd(mConnection); break; case DBUS_EVENT_LOOP_REMOVE: HandleWatchRemove(mConnection); // don't increment i, or we'll skip one element continue; case DBUS_EVENT_LOOP_WAKEUP: NS_ProcessPendingEvents(NS_GetCurrentThread(), PR_INTERVAL_NO_TIMEOUT); break; default: #if DEBUG nsCString warning("unknown command "); warning.AppendInt(data); NS_WARNING(warning.get()); #endif break; } } else { short events = mConnection->mPollData[i].revents; unsigned int flags = UnixEventsToDBusFlags(events); dbus_watch_handle(mConnection->mWatchData[i], flags); mConnection->mPollData[i].revents = 0; // Break at this point since we don't know if the operation // was destructive break; } while (dbus_connection_dispatch(mConnection->GetConnection()) == DBUS_DISPATCH_DATA_REMAINS) {} } ++i; } } return NS_OK; }
nsresult ShutdownXPCOM(nsIServiceManager* aServMgr) { // Make sure the hang monitor is enabled for shutdown. HangMonitor::NotifyActivity(); if (!NS_IsMainThread()) { NS_RUNTIMEABORT("Shutdown on wrong thread"); } nsresult rv; nsCOMPtr<nsISimpleEnumerator> moduleLoaders; // Notify observers of xpcom shutting down { // Block it so that the COMPtr will get deleted before we hit // servicemanager shutdown nsCOMPtr<nsIThread> thread = do_GetCurrentThread(); if (NS_WARN_IF(!thread)) { return NS_ERROR_UNEXPECTED; } RefPtr<nsObserverService> observerService; CallGetService("@mozilla.org/observer-service;1", (nsObserverService**)getter_AddRefs(observerService)); if (observerService) { observerService->NotifyObservers(nullptr, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, nullptr); nsCOMPtr<nsIServiceManager> mgr; rv = NS_GetServiceManager(getter_AddRefs(mgr)); if (NS_SUCCEEDED(rv)) { observerService->NotifyObservers(mgr, NS_XPCOM_SHUTDOWN_OBSERVER_ID, nullptr); } } // This must happen after the shutdown of media and widgets, which // are triggered by the NS_XPCOM_SHUTDOWN_OBSERVER_ID notification. NS_ProcessPendingEvents(thread); gfxPlatform::ShutdownLayersIPC(); mozilla::scache::StartupCache::DeleteSingleton(); if (observerService) observerService->NotifyObservers(nullptr, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, nullptr); gXPCOMThreadsShutDown = true; NS_ProcessPendingEvents(thread); // Shutdown the timer thread and all timers that might still be alive before // shutting down the component manager nsTimerImpl::Shutdown(); NS_ProcessPendingEvents(thread); // Shutdown all remaining threads. This method does not return until // all threads created using the thread manager (with the exception of // the main thread) have exited. nsThreadManager::get()->Shutdown(); NS_ProcessPendingEvents(thread); HangMonitor::NotifyActivity(); // Late-write checks needs to find the profile directory, so it has to // be initialized before mozilla::services::Shutdown or (because of // xpcshell tests replacing the service) modules being unloaded. mozilla::InitLateWriteChecks(); // We save the "xpcom-shutdown-loaders" observers to notify after // the observerservice is gone. if (observerService) { observerService->EnumerateObservers(NS_XPCOM_SHUTDOWN_LOADERS_OBSERVER_ID, getter_AddRefs(moduleLoaders)); observerService->Shutdown(); } } // Free ClearOnShutdown()'ed smart pointers. This needs to happen *after* // we've finished notifying observers of XPCOM shutdown, because shutdown // observers themselves might call ClearOnShutdown(). mozilla::KillClearOnShutdown(); // XPCOM is officially in shutdown mode NOW // Set this only after the observers have been notified as this // will cause servicemanager to become inaccessible. mozilla::services::Shutdown(); #ifdef DEBUG_dougt fprintf(stderr, "* * * * XPCOM shutdown. Access will be denied * * * * \n"); #endif // We may have AddRef'd for the caller of NS_InitXPCOM, so release it // here again: NS_IF_RELEASE(aServMgr); // Shutdown global servicemanager if (nsComponentManagerImpl::gComponentManager) { nsComponentManagerImpl::gComponentManager->FreeServices(); } // Release the directory service NS_IF_RELEASE(nsDirectoryService::gService); free(gGREBinPath); gGREBinPath = nullptr; if (moduleLoaders) { bool more; nsCOMPtr<nsISupports> el; while (NS_SUCCEEDED(moduleLoaders->HasMoreElements(&more)) && more) { moduleLoaders->GetNext(getter_AddRefs(el)); // Don't worry about weak-reference observers here: there is // no reason for weak-ref observers to register for // xpcom-shutdown-loaders // FIXME: This can cause harmless writes from sqlite committing // log files. We have to ignore them before we can move // the mozilla::PoisonWrite call before this point. See bug // 834945 for the details. nsCOMPtr<nsIObserver> obs(do_QueryInterface(el)); if (obs) { obs->Observe(nullptr, NS_XPCOM_SHUTDOWN_LOADERS_OBSERVER_ID, nullptr); } } moduleLoaders = nullptr; } nsCycleCollector_shutdown(); layers::AsyncTransactionTrackersHolder::Finalize(); PROFILER_MARKER("Shutdown xpcom"); // If we are doing any shutdown checks, poison writes. if (gShutdownChecks != SCM_NOTHING) { #ifdef XP_MACOSX mozilla::OnlyReportDirtyWrites(); #endif /* XP_MACOSX */ mozilla::BeginLateWriteChecks(); } // Shutdown nsLocalFile string conversion NS_ShutdownLocalFile(); #ifdef XP_UNIX NS_ShutdownNativeCharsetUtils(); #endif #if defined(XP_WIN) // This exit(0) call is intended to be temporary, to get shutdown leak // checking working on Linux. // On Windows XP debug, there are intermittent failures in // dom/media/tests/mochitest/test_peerConnection_basicH264Video.html // if we don't exit early in a child process. See bug 1073310. if (XRE_IsContentProcess() && !IsVistaOrLater()) { NS_WARNING("Exiting child process early!"); exit(0); } #endif // Shutdown xpcom. This will release all loaders and cause others holding // a refcount to the component manager to release it. if (nsComponentManagerImpl::gComponentManager) { rv = (nsComponentManagerImpl::gComponentManager)->Shutdown(); NS_ASSERTION(NS_SUCCEEDED(rv), "Component Manager shutdown failed."); } else { NS_WARNING("Component Manager was never created ..."); } #ifdef MOZ_ENABLE_PROFILER_SPS // In optimized builds we don't do shutdown collections by default, so // uncollected (garbage) objects may keep the nsXPConnect singleton alive, // and its XPCJSRuntime along with it. However, we still destroy various // bits of state in JS_ShutDown(), so we need to make sure the profiler // can't access them when it shuts down. This call nulls out the // JS pseudo-stack's internal reference to the main thread JSRuntime, // duplicating the call in XPCJSRuntime::~XPCJSRuntime() in case that // never fired. if (PseudoStack* stack = mozilla_get_pseudo_stack()) { stack->sampleRuntime(nullptr); } #endif // Shut down the JS engine. JS_ShutDown(); // Release our own singletons // Do this _after_ shutting down the component manager, because the // JS component loader will use XPConnect to call nsIModule::canUnload, // and that will spin up the InterfaceInfoManager again -- bad mojo XPTInterfaceInfoManager::FreeInterfaceInfoManager(); // Finally, release the component manager last because it unloads the // libraries: if (nsComponentManagerImpl::gComponentManager) { nsrefcnt cnt; NS_RELEASE2(nsComponentManagerImpl::gComponentManager, cnt); NS_ASSERTION(cnt == 0, "Component Manager being held past XPCOM shutdown."); } nsComponentManagerImpl::gComponentManager = nullptr; nsCategoryManager::Destroy(); NS_PurgeAtomTable(); NS_IF_RELEASE(gDebug); delete sIOThread; sIOThread = nullptr; delete sMessageLoop; sMessageLoop = nullptr; if (sCommandLineWasInitialized) { CommandLine::Terminate(); sCommandLineWasInitialized = false; } delete sExitManager; sExitManager = nullptr; Omnijar::CleanUp(); HangMonitor::Shutdown(); delete sMainHangMonitor; sMainHangMonitor = nullptr; BackgroundHangMonitor::Shutdown(); profiler_shutdown(); NS_LogTerm(); #if defined(MOZ_WIDGET_GONK) // This exit(0) call is intended to be temporary, to get shutdown leak // checking working on Linux. // On debug B2G, the child process crashes very late. Instead, just // give up so at least we exit cleanly. See bug 1071866. if (XRE_IsContentProcess()) { NS_WARNING("Exiting child process early!"); exit(0); } #endif return NS_OK; }
static void join_waiter() { NS_ProcessPendingEvents(PeerConnectionCtx::gMainThread); }
int main(int argc, char **argv) { nsresult rv; { nsCOMPtr<nsIServiceManager> servMan; NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servMan); NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); if (registrar) registrar->AutoRegister(nsnull); printf("*** getting ipc service\n"); nsCOMPtr<ipcIService> ipcServ(do_GetService(IPC_SERVICE_CONTRACTID, &rv)); RETURN_IF_FAILED(rv, "do_GetService(ipcServ)"); NS_ADDREF(gIpcServ = ipcServ); if (argc > 1) { printf("*** using client name [%s]\n", argv[1]); gIpcServ->AddName(argv[1]); } ipcServ->DefineTarget(kTestTargetID, new myIpcMessageObserver(), PR_TRUE); const char data[] = "01 this is a really long message.\n" "02 this is a really long message.\n" "03 this is a really long message.\n" "04 this is a really long message.\n" "05 this is a really long message.\n" "06 this is a really long message.\n" "07 this is a really long message.\n" "08 this is a really long message.\n" "09 this is a really long message.\n" "10 this is a really long message.\n" "11 this is a really long message.\n" "12 this is a really long message.\n" "13 this is a really long message.\n" "14 this is a really long message.\n" "15 this is a really long message.\n" "16 this is a really long message.\n" "17 this is a really long message.\n" "18 this is a really long message.\n" "19 this is a really long message.\n" "20 this is a really long message.\n" "21 this is a really long message.\n" "22 this is a really long message.\n" "23 this is a really long message.\n" "24 this is a really long message.\n" "25 this is a really long message.\n" "26 this is a really long message.\n" "27 this is a really long message.\n" "28 this is a really long message.\n" "29 this is a really long message.\n" "30 this is a really long message.\n" "31 this is a really long message.\n" "32 this is a really long message.\n" "33 this is a really long message.\n" "34 this is a really long message.\n" "35 this is a really long message.\n" "36 this is a really long message.\n" "37 this is a really long message.\n" "38 this is a really long message.\n" "39 this is a really long message.\n" "40 this is a really long message.\n" "41 this is a really long message.\n" "42 this is a really long message.\n" "43 this is a really long message.\n" "44 this is a really long message.\n" "45 this is a really long message.\n" "46 this is a really long message.\n" "47 this is a really long message.\n" "48 this is a really long message.\n" "49 this is a really long message.\n" "50 this is a really long message.\n" "51 this is a really long message.\n" "52 this is a really long message.\n" "53 this is a really long message.\n" "54 this is a really long message.\n" "55 this is a really long message.\n" "56 this is a really long message.\n" "57 this is a really long message.\n" "58 this is a really long message.\n" "59 this is a really long message.\n" "60 this is a really long message.\n"; SendMsg(ipcServ, 0, kTestTargetID, data, sizeof(data), PR_TRUE); // PRUint32 queryID; // nsCOMPtr<ipcIClientQueryHandler> handler(new myIpcClientQueryHandler()); // ipcServ->QueryClientByName("foopy", handler, PR_FALSE, &queryID); PRUint32 foopyID; nsresult foopyRv = ipcServ->ResolveClientName("foopy", &foopyID); printf("*** query for 'foopy' returned [rv=%x id=%u]\n", foopyRv, foopyID); if (NS_SUCCEEDED(foopyRv)) { const char hello[] = "hello friend!"; SendMsg(ipcServ, foopyID, kTestTargetID, hello, sizeof(hello)); } // // test lock service // nsCOMPtr<ipcILockService> lockService = do_GetService(IPC_LOCKSERVICE_CONTRACTID, &rv); RETURN_IF_FAILED(rv, "do_GetService(ipcLockServ)"); NS_ADDREF(gIpcLockServ = lockService); //nsCOMPtr<ipcILockNotify> notify(new myIpcLockNotify()); gIpcLockServ->AcquireLock("blah", PR_TRUE); rv = gIpcLockServ->AcquireLock("foo", PR_TRUE); printf("*** sync AcquireLock returned [rv=%x]\n", rv); nsCOMPtr<nsIThread> thread = do_GetCurrentThread(); while (gKeepRunning) NS_ProcessNextEvent(thread); NS_RELEASE(gIpcServ); printf("*** processing remaining events\n"); // process any remaining events NS_ProcessPendingEvents(thread); printf("*** done\n"); } // this scopes the nsCOMPtrs // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM rv = NS_ShutdownXPCOM(nsnull); NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); return 0; }