NS_IMETHODIMP
STSThreadPoolListener::OnThreadCreated()
{
    if (IsNuwaProcess()) {
        NuwaMarkCurrentThread(nullptr, nullptr);
    }
    return NS_OK;
}
Beispiel #2
0
void
ProcessLink::SendMessage(Message *msg)
{
    mChan->AssertWorkerThread();
    mChan->mMonitor->AssertCurrentThreadOwns();

#ifdef MOZ_NUWA_PROCESS
    // Parent to child: check whether we are sending some unexpected message to
    // the Nuwa process.
    if (mIsToNuwaProcess && mozilla::dom::ContentParent::IsNuwaReady()) {
        switch (msg->type()) {
        case mozilla::dom::PNuwa::Msg_Fork__ID:
        case mozilla::dom::PNuwa::Reply_AddNewProcess__ID:
        case mozilla::dom::PContent::Msg_NotifyPhoneStateChange__ID:
        case mozilla::dom::PContent::Msg_ActivateA11y__ID:
        case mozilla::hal_sandbox::PHal::Msg_NotifyNetworkChange__ID:
        case GOODBYE_MESSAGE_TYPE:
            break;
        default:
#ifdef DEBUG
            MOZ_CRASH();
#else
            // In optimized build, message will be dropped.
            printf_stderr("Sending message to frozen Nuwa");
            return;
#endif
        }
    }

#if defined(DEBUG)
    // Nuwa to parent: check whether we are currently blocked.
    if (IsNuwaProcess() && mIsBlocked) {
        char* jsstack = PrintJSStack();
        printf_stderr("Fatal error: sending a message to the chrome process"
                      "with a blocked IPC channel from \n%s",
                      jsstack ? jsstack : "<no JS stack>");
        JS_smprintf_free(jsstack);
        MOZ_CRASH();
    }
#endif
#endif

    mIOLoop->PostTask(
        FROM_HERE,
        NewRunnableMethod(mTransport, &Transport::Send, msg));
}
static void
ConnectImageBridgeInChildProcess(Transport* aTransport,
                                 ProcessId aOtherPid)
{
  // Bind the IPC channel to the image bridge thread.
  sImageBridgeChildSingleton->Open(aTransport, aOtherPid,
                                   XRE_GetIOMessageLoop(),
                                   ipc::ChildSide);
#ifdef MOZ_NUWA_PROCESS
  if (IsNuwaProcess()) {
    sImageBridgeChildThread
      ->message_loop()->PostTask(FROM_HERE,
                                 NewRunnableFunction(NuwaMarkCurrentThread,
                                                     (void (*)(void *))nullptr,
                                                     (void *)nullptr));
  }
#endif
}
nsresult
nsStreamTransportService::Init()
{
    mPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
    NS_ENSURE_STATE(mPool);

    // Configure the pool
    mPool->SetName(NS_LITERAL_CSTRING("StreamTrans"));
    mPool->SetThreadLimit(25);
    mPool->SetIdleThreadLimit(1);
    mPool->SetIdleThreadTimeout(PR_SecondsToInterval(30));
#ifdef MOZ_NUWA_PROCESS
    if (IsNuwaProcess()) {
	mPool->SetListener(new STSThreadPoolListener());
    }
#endif

    nsCOMPtr<nsIObserverService> obsSvc =
        mozilla::services::GetObserverService();
    if (obsSvc)
        obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
    return NS_OK;
}
Beispiel #5
0
bool
NuwaChild::RecvFork()
{
#ifdef MOZ_NUWA_PROCESS
  if (!IsNuwaProcess()) {
    NS_ERROR(
      nsPrintfCString(
        "Terminating child process %d for unauthorized IPC message: "
          "RecvFork(%d)", getpid()).get());
    return false;
  }

  nsCOMPtr<nsIRunnable> runnable =
    NS_NewRunnableFunction(&NuwaFork);
  MOZ_ASSERT(runnable);
  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));

  return true;
#else
  NS_ERROR("NuwaChild::RecvFork() not implemented!");
  return false;
#endif
}
Beispiel #6
0
void 
ProcessLink::Open(mozilla::ipc::Transport* aTransport, MessageLoop *aIOLoop, Side aSide)
{
    NS_PRECONDITION(aTransport, "need transport layer");

    // FIXME need to check for valid channel

    mTransport = aTransport;

    // FIXME figure out whether we're in parent or child, grab IO loop
    // appropriately
    bool needOpen = true;
    if(aIOLoop) {
        // We're a child or using the new arguments.  Either way, we
        // need an open.
        needOpen = true;
        mChan->mSide = (aSide == UnknownSide) ? ChildSide : aSide;
    } else {
        NS_PRECONDITION(aSide == UnknownSide, "expected default side arg");

        // parent
        mChan->mSide = ParentSide;
        needOpen = false;
        aIOLoop = XRE_GetIOMessageLoop();
    }

    mIOLoop = aIOLoop;

    NS_ASSERTION(mIOLoop, "need an IO loop");
    NS_ASSERTION(mChan->mWorkerLoop, "need a worker loop");

    {
        MonitorAutoLock lock(*mChan->mMonitor);

        if (needOpen) {
            // Transport::Connect() has not been called.  Call it so
            // we start polling our pipe and processing outgoing
            // messages.
            mIOLoop->PostTask(
                FROM_HERE,
                NewRunnableMethod(this, &ProcessLink::OnChannelOpened));
        } else {
            // Transport::Connect() has already been called.  Take
            // over the channel from the previous listener and process
            // any queued messages.
            mIOLoop->PostTask(
                FROM_HERE,
                NewRunnableMethod(this, &ProcessLink::OnTakeConnectedChannel));
        }

#ifdef MOZ_NUWA_PROCESS
        if (IsNuwaProcess() &&
            Preferences::GetBool("dom.ipc.processPrelaunch.testMode")) {
            // The pref value is turned on in a deadlock test against the Nuwa
            // process. The sleep here makes it easy to trigger the deadlock
            // that an IPC channel is still opening but the worker loop is
            // already frozen.
            sleep(5);
        }
#endif

        // Should not wait here if something goes wrong with the channel.
        while (!mChan->Connected() && mChan->mChannelState != ChannelError) {
            mChan->mMonitor->Wait();
        }
    }
}
NS_IMETHODIMP
nsSocketTransportService::Run()
{
#ifdef MOZ_NUWA_PROCESS
    if (IsNuwaProcess()) {
        NuwaMarkCurrentThread(nullptr, nullptr);
    }
#endif

    SOCKET_LOG(("STS thread init %d sockets\n", gMaxCount));

    psm::InitializeSSLServerCertVerificationThreads();

    gSocketThread = PR_GetCurrentThread();

    {
        DebugMutexAutoLock 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
        {
            DebugMutexAutoLock 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;
}
void
ClosingService::ThreadFunc()
{
  PR_SetCurrentThreadName("Closing Service");
#ifdef MOZ_NUWA_PROCESS
  if (IsNuwaProcess()) {
    NuwaMarkCurrentThread(nullptr, nullptr);
  }
#endif

  for (;;) {
    PRFileDesc *fd;
    {
      mozilla::MonitorAutoLock mon(mMonitor);
      while (!mShutdown && (mQueue.Length() == 0)) {
        mon.Wait();
      }

      if (mShutdown) {
        // If we are in shutdown leak the rest of the sockets.
        for (uint32_t i = 0; i < mQueue.Length(); i++) {
          fd = mQueue[i];
          // If the ClosingService layer is the first layer above
          // PR_NSPR_IO_LAYER we are not going to leak anything, but PR_Close
          // will not be called.
          PR_Free(fd);
        }
        mQueue.Clear();
        return;
      }

      fd = mQueue[0];
      mQueue.RemoveElementAt(0);
    }
    // Leave lock before closing socket. It can block for a long time and in
    // case we accidentally attach this layer twice this would cause deadlock.

    bool tcp = (PR_GetDescType(PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER)) ==
                PR_DESC_SOCKET_TCP);

    PRIntervalTime closeStarted = PR_IntervalNow();
    fd->methods->close(fd);

    // Post telemetry.
    if (tcp) {
      SendPRCloseTelemetry(closeStarted,
        Telemetry::PRCLOSE_TCP_BLOCKING_TIME_NORMAL,
        Telemetry::PRCLOSE_TCP_BLOCKING_TIME_SHUTDOWN,
        Telemetry::PRCLOSE_TCP_BLOCKING_TIME_CONNECTIVITY_CHANGE,
        Telemetry::PRCLOSE_TCP_BLOCKING_TIME_LINK_CHANGE,
        Telemetry::PRCLOSE_TCP_BLOCKING_TIME_OFFLINE);
    } else {
      SendPRCloseTelemetry(closeStarted,
        Telemetry::PRCLOSE_UDP_BLOCKING_TIME_NORMAL,
        Telemetry::PRCLOSE_UDP_BLOCKING_TIME_SHUTDOWN,
        Telemetry::PRCLOSE_UDP_BLOCKING_TIME_CONNECTIVITY_CHANGE,
        Telemetry::PRCLOSE_UDP_BLOCKING_TIME_LINK_CHANGE,
        Telemetry::PRCLOSE_UDP_BLOCKING_TIME_OFFLINE);
    }
  }
}
Beispiel #9
0
void
ThreadMain(void*)
{
  PR_SetCurrentThreadName("Hang Monitor");

#ifdef MOZ_NUWA_PROCESS
  if (IsNuwaProcess()) {
    NuwaMarkCurrentThread(nullptr, nullptr);
  }
#endif

  MonitorAutoLock lock(*gMonitor);

  // In order to avoid issues with the hang monitor incorrectly triggering
  // during a general system stop such as sleeping, the monitor thread must
  // run twice to trigger hang protection.
  PRIntervalTime lastTimestamp = 0;
  int waitCount = 0;

#ifdef REPORT_CHROME_HANGS
  Telemetry::ProcessedStack stack;
  int32_t systemUptime = -1;
  int32_t firefoxUptime = -1;
  UniquePtr<HangAnnotations> annotations;
#endif

  while (true) {
    if (gShutdown) {
      return; // Exit the thread
    }

    // avoid rereading the volatile value in this loop
    PRIntervalTime timestamp = gTimestamp;

    PRIntervalTime now = PR_IntervalNow();

    if (timestamp != PR_INTERVAL_NO_WAIT &&
        now < timestamp) {
      // 32-bit overflow, reset for another waiting period
      timestamp = 1; // lowest legal PRInterval value
    }

    if (timestamp != PR_INTERVAL_NO_WAIT &&
        timestamp == lastTimestamp &&
        gTimeout > 0) {
      ++waitCount;
#ifdef REPORT_CHROME_HANGS
      // Capture the chrome-hang stack + Firefox & system uptimes after
      // the minimum hang duration has been reached (not when the hang ends)
      if (waitCount == 2) {
        GetChromeHangReport(stack, systemUptime, firefoxUptime);
        annotations = ChromeHangAnnotatorCallout();
      }
#else
      // This is the crash-on-hang feature.
      // See bug 867313 for the quirk in the waitCount comparison
      if (waitCount >= 2) {
        int32_t delay =
          int32_t(PR_IntervalToSeconds(now - timestamp));
        if (delay >= gTimeout) {
          MonitorAutoUnlock unlock(*gMonitor);
          Crash();
        }
      }
#endif
    } else {
#ifdef REPORT_CHROME_HANGS
      if (waitCount >= 2) {
        uint32_t hangDuration = PR_IntervalToSeconds(now - lastTimestamp);
        Telemetry::RecordChromeHang(hangDuration, stack, systemUptime,
                                    firefoxUptime, Move(annotations));
        stack.Clear();
      }
#endif
      lastTimestamp = timestamp;
      waitCount = 0;
    }

    PRIntervalTime timeout;
    if (gTimeout <= 0) {
      timeout = PR_INTERVAL_NO_TIMEOUT;
    } else {
      timeout = PR_MillisecondsToInterval(gTimeout * 500);
    }
    lock.Wait(timeout);
  }
}