Beispiel #1
0
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;
}
Beispiel #5
0
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;
}
Beispiel #8
0
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;
}
Beispiel #12
0
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;
  }
Beispiel #16
0
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;
}