Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  SpinEventLoopUntil.h   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#ifndef xpcom_threads_SpinEventLoopUntil_h__
#define xpcom_threads_SpinEventLoopUntil_h__

#include "MainThreadUtils.h"
#include "mozilla/Maybe.h"
#include "mozilla/ProfilerLabels.h"
#include "mozilla/ProfilerMarkers.h"
#include "mozilla/StaticMutex.h"
#include "nsString.h"
#include "nsThreadUtils.h"
#include "xpcpublic.h"

class nsIThread;

// A wrapper for nested event loops.
//
// This function is intended to make code more obvious (do you remember
// what NS_ProcessNextEvent(nullptr, true) means?) and slightly more
// efficient, as people often pass nullptr or NS_GetCurrentThread to
// NS_ProcessNextEvent, which results in needless querying of the current
// thread every time through the loop.
//
// You should use this function in preference to NS_ProcessNextEvent inside
// a loop unless one of the following is true:
//
// * You need to pass `false` to NS_ProcessNextEvent; or
// * You need to do unusual things around the call to NS_ProcessNextEvent,
//   such as unlocking mutexes that you are holding.
//
// If you *do* need to call NS_ProcessNextEvent manually, please do call
// NS_GetCurrentThread() outside of your loop and pass the returned pointer
// into NS_ProcessNextEvent for a tiny efficiency win.
namespace mozilla {

// You should normally not need to deal with this template parameter.  If
// you enjoy esoteric event loop details, read on.
//
// If you specify that NS_ProcessNextEvent wait for an event, it is possible
// for NS_ProcessNextEvent to return false, i.e. to indicate that an event
// was not processed.  This can only happen when the thread has been shut
// down by another thread, but is still attempting to process events outside
// of a nested event loop.
//
// This behavior is admittedly strange.  The scenario it deals with is the
// following:
//
// * The current thread has been shut down by some owner thread.
// * The current thread is spinning an event loop waiting for some condition
//   to become true.
// * Said condition is actually being fulfilled by another thread, so there
//   are timing issues in play.
//
// Thus, there is a small window where the current thread's event loop
// spinning can check the condition, find it false, and call
// NS_ProcessNextEvent to wait for another event.  But we don't actually
// want it to wait indefinitely, because there might not be any other events
// in the event loop, and the current thread can't accept dispatched events
// because it's being shut down.  Thus, actually blocking would hang the
// thread, which is bad.  The solution, then, is to detect such a scenario
// and not actually block inside NS_ProcessNextEvent.
//
// But this is a problem, because we want to return the status of
// NS_ProcessNextEvent to the caller of SpinEventLoopUntil if possible.  In
// the above scenario, however, we'd stop spinning prematurely and cause
// all sorts of havoc.  We therefore have this template parameter to
// control whether errors are ignored or passed out to the caller of
// SpinEventLoopUntil.  The latter is the default; if you find yourself
// wanting to use the former, you should think long and hard before doing
// so, and write a comment like this defending your choice.

enum class ProcessFailureBehavior {
  IgnoreAndContinue,
  ReportToCaller,
};

// SpinEventLoopUntil is a dangerous operation that can result in hangs.
// In particular during shutdown we want to know if we are hanging
// inside a nested event loop on the main thread.
// This is a helper annotation class to keep track of this.
struct MOZ_STACK_CLASS AutoNestedEventLoopAnnotation {
  explicit AutoNestedEventLoopAnnotation(const nsACString& aEntry)
      : mPrev(nullptr) {
    if (NS_IsMainThread()) {
      StaticMutexAutoLock lock(sStackMutex);
      mPrev = sCurrent;
      sCurrent = this;
      if (mPrev) {
        mStack = mPrev->mStack + "|"_ns + aEntry;
      } else {
        mStack = aEntry;
      }
      AnnotateXPCOMSpinEventLoopStack(mStack);
    }
  }

  ~AutoNestedEventLoopAnnotation() {
    if (NS_IsMainThread()) {
      StaticMutexAutoLock lock(sStackMutex);
      MOZ_ASSERT(sCurrent == this);
      sCurrent = mPrev;
      if (mPrev) {
        AnnotateXPCOMSpinEventLoopStack(mPrev->mStack);
      } else {
        AnnotateXPCOMSpinEventLoopStack(""_ns);
      }
    }
  }

  static void CopyCurrentStack(nsCString& aNestedSpinStack) {
    // We need to copy this behind a mutex as the
    // memory for our instances is stack-bound and
    // can go away at any time.
    StaticMutexAutoLock lock(sStackMutex);
    if (sCurrent) {
      aNestedSpinStack = sCurrent->mStack;
    } else {
      aNestedSpinStack = "(no nested event loop active)"_ns;
    }
  }

 private:
  AutoNestedEventLoopAnnotation(const AutoNestedEventLoopAnnotation&) = delete;
  AutoNestedEventLoopAnnotation& operator=(
      const AutoNestedEventLoopAnnotation&) = delete;

  // The declarations of these statics live in nsThreadManager.cpp.
  static AutoNestedEventLoopAnnotation* sCurrent MOZ_GUARDED_BY(sStackMutex);
  static StaticMutex sStackMutex;

  // We need this to avoid the inclusion of nsExceptionHandler.h here
  // which can include windows.h which disturbs some dom/media/gtest.
  // The implementation lives in nsThreadManager.cpp.
  static void AnnotateXPCOMSpinEventLoopStack(const nsACString& aStack);

  AutoNestedEventLoopAnnotation* mPrev MOZ_GUARDED_BY(sStackMutex);
  nsCString mStack MOZ_GUARDED_BY(sStackMutex);
};

// Please see the above notes for the Behavior template parameter.
//
// aVeryGoodReasonToDoThis is usually a literal string unique to each
//   caller that can be recognized in the XPCOMSpinEventLoopStack
//   annotation.
// aPredicate is the condition we wait for.
// aThread can be used to specify a thread, see the above introduction.
//   It defaults to the current thread.
template <
    ProcessFailureBehavior Behavior = ProcessFailureBehavior::ReportToCaller,
    typename Pred>
bool SpinEventLoopUntil(const nsACString& aVeryGoodReasonToDoThis,
                        Pred&& aPredicate, nsIThread* aThread = nullptr) {
  // Prepare the annotations
  AutoNestedEventLoopAnnotation annotation(aVeryGoodReasonToDoThis);
  AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE(
      "SpinEventLoopUntil", OTHER, aVeryGoodReasonToDoThis);
  AUTO_PROFILER_MARKER_TEXT("SpinEventLoop", OTHER, MarkerStack::Capture(),
                            aVeryGoodReasonToDoThis);

  nsIThread* thread = aThread ? aThread : NS_GetCurrentThread();

  // From a latency perspective, spinning the event loop is like leaving script
  // and returning to the event loop. Tell the watchdog we stopped running
  // script (until we return).
  mozilla::Maybe<xpc::AutoScriptActivity> asa;
  if (NS_IsMainThread()) {
    asa.emplace(false);
  }

  while (!aPredicate()) {
    bool didSomething = NS_ProcessNextEvent(thread, true);

    if (Behavior == ProcessFailureBehavior::IgnoreAndContinue) {
      // Don't care what happened, continue on.
      continue;
    } else if (!didSomething) {
      return false;
    }
  }

  return true;
}

}  // namespace mozilla

#endif  // xpcom_threads_SpinEventLoopUntil_h__

96%


¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge