Bug 1182516 - Add Chaos Mode environment variable MOZ_CHAOSMODE. r=roc
authorBenoit Girard <b56girard@gmail.com>
Tue, 14 Jul 2015 17:29:23 -0400
changeset 284762 fe2800b80350314ab5cdab826f69f2837a4c3fd6
parent 284761 9f7b5a358a7692659af7f79829d5d31f63894d25
child 284763 f54e7f247cf2586f5e51b04f133f87f4eafc7816
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1182516
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1182516 - Add Chaos Mode environment variable MOZ_CHAOSMODE. r=roc
mfbt/ChaosMode.cpp
mfbt/ChaosMode.h
netwerk/base/nsSocketTransportService2.cpp
netwerk/protocol/http/nsHttpConnection.cpp
netwerk/protocol/http/nsHttpConnectionMgr.cpp
toolkit/xre/nsAppRunner.cpp
xpcom/threads/TimerThread.cpp
xpcom/threads/nsEventQueue.cpp
xpcom/threads/nsThread.cpp
--- a/mfbt/ChaosMode.cpp
+++ b/mfbt/ChaosMode.cpp
@@ -2,14 +2,16 @@
 /* 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/. */
 
 #include "mozilla/ChaosMode.h"
 
 namespace mozilla {
+
 namespace detail {
 
 Atomic<uint32_t> gChaosModeCounter(0);
+ChaosFeature gChaosFeatures = None;
 
 } /* namespace detail */
 } /* namespace mozilla */
--- a/mfbt/ChaosMode.h
+++ b/mfbt/ChaosMode.h
@@ -10,54 +10,55 @@
 #include "mozilla/Atomics.h"
 #include "mozilla/EnumSet.h"
 
 #include <stdint.h>
 #include <stdlib.h>
 
 namespace mozilla {
 
+enum ChaosFeature {
+  None = 0x0,
+  // Altering thread scheduling.
+  ThreadScheduling = 0x1,
+  // Altering network request scheduling.
+  NetworkScheduling = 0x2,
+  // Altering timer scheduling.
+  TimerScheduling = 0x4,
+  // Read and write less-than-requested amounts.
+  IOAmounts = 0x8,
+  // Iterate over hash tables in random order.
+  HashTableIteration = 0x10,
+  Any = 0xffffffff,
+};
+
 namespace detail {
 extern MFBT_DATA Atomic<uint32_t> gChaosModeCounter;
+extern MFBT_DATA ChaosFeature gChaosFeatures;
 } // namespace detail
 
 /**
  * When "chaos mode" is activated, code that makes implicitly nondeterministic
  * choices is encouraged to make random and extreme choices, to test more
  * code paths and uncover bugs.
  */
 class ChaosMode
 {
 public:
-  enum ChaosFeature {
-    None = 0x0,
-    // Altering thread scheduling.
-    ThreadScheduling = 0x1,
-    // Altering network request scheduling.
-    NetworkScheduling = 0x2,
-    // Altering timer scheduling.
-    TimerScheduling = 0x4,
-    // Read and write less-than-requested amounts.
-    IOAmounts = 0x8,
-    // Iterate over hash tables in random order.
-    HashTableIteration = 0x10,
-    Any = 0xffffffff,
-  };
+  static void SetChaosFeature(ChaosFeature aChaosFeature)
+  {
+    detail::gChaosFeatures = aChaosFeature;
+  }
 
-private:
-  // Change this to any non-None value to activate ChaosMode.
-  static const ChaosFeature sChaosFeatures = None;
-
-public:
   static bool isActive(ChaosFeature aFeature)
   {
     if (detail::gChaosModeCounter > 0) {
       return true;
     }
-    return sChaosFeatures & aFeature;
+    return detail::gChaosFeatures & aFeature;
   }
 
   /**
    * Increase the chaos mode activation level. An equivalent number of
    * calls to leaveChaosMode must be made in order to restore the original
    * chaos mode state. If the activation level is nonzero all chaos mode
    * features are activated.
    */
--- a/netwerk/base/nsSocketTransportService2.cpp
+++ b/netwerk/base/nsSocketTransportService2.cpp
@@ -270,17 +270,17 @@ nsSocketTransportService::AddToPollList(
         SOCKET_LOG(("  Active List size of %d met\n", mActiveCount));
         if (!GrowActiveList()) {
             NS_ERROR("too many active sockets");
             return NS_ERROR_OUT_OF_MEMORY;
         }
     }
     
     uint32_t newSocketIndex = mActiveCount;
-    if (ChaosMode::isActive(ChaosMode::NetworkScheduling)) {
+    if (ChaosMode::isActive(ChaosFeature::NetworkScheduling)) {
       newSocketIndex = ChaosMode::randomUint32LessThan(mActiveCount + 1);
       PodMove(mActiveList + newSocketIndex + 1, mActiveList + newSocketIndex,
               mActiveCount - newSocketIndex);
       PodMove(mPollList + newSocketIndex + 2, mPollList + newSocketIndex + 1,
               mActiveCount - newSocketIndex);
     }
     mActiveList[newSocketIndex] = *sock;
     mActiveCount++;
--- a/netwerk/protocol/http/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/nsHttpConnection.cpp
@@ -1621,17 +1621,17 @@ nsHttpConnection::OnWriteSegment(char *b
     if (count == 0) {
         // some WriteSegments implementations will erroneously call the reader
         // to provide 0 bytes worth of data.  we must protect against this case
         // or else we'd end up closing the socket prematurely.
         NS_ERROR("bad WriteSegments implementation");
         return NS_ERROR_FAILURE; // stop iterating
     }
 
-    if (ChaosMode::isActive(ChaosMode::IOAmounts) &&
+    if (ChaosMode::isActive(ChaosFeature::IOAmounts) &&
         ChaosMode::randomUint32LessThan(2)) {
         // read 1...count bytes
         count = ChaosMode::randomUint32LessThan(count) + 1;
     }
 
     nsresult rv = mSocketIn->Read(buf, count, countWritten);
     if (NS_FAILED(rv))
         mSocketInCondition = rv;
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -51,17 +51,17 @@ InsertTransactionSorted(nsTArray<nsHttpT
 {
     // insert into queue with smallest valued number first.  search in reverse
     // order under the assumption that many of the existing transactions will
     // have the same priority (usually 0).
 
     for (int32_t i=pendingQ.Length()-1; i>=0; --i) {
         nsHttpTransaction *t = pendingQ[i];
         if (trans->Priority() >= t->Priority()) {
-	  if (ChaosMode::isActive(ChaosMode::NetworkScheduling)) {
+	  if (ChaosMode::isActive(ChaosFeature::NetworkScheduling)) {
                 int32_t samePriorityCount;
                 for (samePriorityCount = 0; i - samePriorityCount >= 0; ++samePriorityCount) {
                     if (pendingQ[i - samePriorityCount]->Priority() != trans->Priority()) {
                         break;
                     }
                 }
                 // skip over 0...all of the elements with the same priority.
                 i -= ChaosMode::randomUint32LessThan(samePriorityCount + 1);
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -3118,17 +3118,27 @@ int
 XREMain::XRE_mainInit(bool* aExitFlag)
 {
   if (!aExitFlag)
     return 1;
   *aExitFlag = false;
 
   StartupTimeline::Record(StartupTimeline::MAIN);
 
-  if (ChaosMode::isActive(ChaosMode::Any)) {
+  if (PR_GetEnv("MOZ_CHAOSMODE")) {
+    ChaosFeature feature = ChaosFeature::Any;
+    long featureInt = strtol(PR_GetEnv("MOZ_CHAOSMODE"), nullptr, 16);
+    if (featureInt) {
+      // NOTE: MOZ_CHAOSMODE=0 or a non-hex value maps to Any feature.
+      feature = static_cast<ChaosFeature>(featureInt);
+    }
+    ChaosMode::SetChaosFeature(feature);
+  }
+
+  if (ChaosMode::isActive(ChaosFeature::Any)) {
     printf_stderr("*** You are running in chaos test mode. See ChaosMode.h. ***\n");
   }
 
   nsresult rv;
   ArgResult ar;
 
 #ifdef DEBUG
   if (PR_GetEnv("XRE_MAIN_BREAK"))
--- a/xpcom/threads/TimerThread.cpp
+++ b/xpcom/threads/TimerThread.cpp
@@ -231,17 +231,17 @@ TimerThread::Run()
     // Have to use PRIntervalTime here, since PR_WaitCondVar takes it
     PRIntervalTime waitFor;
     bool forceRunThisTimer = forceRunNextTimer;
     forceRunNextTimer = false;
 
     if (mSleeping) {
       // Sleep for 0.1 seconds while not firing timers.
       uint32_t milliseconds = 100;
-      if (ChaosMode::isActive(ChaosMode::TimerScheduling)) {
+      if (ChaosMode::isActive(ChaosFeature::TimerScheduling)) {
         milliseconds = ChaosMode::randomUint32LessThan(200);
       }
       waitFor = PR_MillisecondsToInterval(milliseconds);
     } else {
       waitFor = PR_INTERVAL_NO_TIMEOUT;
       TimeStamp now = TimeStamp::Now();
       mLastTimerEventLoopRun = now;
       nsTimerImpl* timer = nullptr;
@@ -315,17 +315,17 @@ TimerThread::Run()
         // is due now or overdue.
         //
         // Note that we can only sleep for integer values of a certain
         // resolution. We use halfMicrosecondsIntervalResolution, calculated
         // before, to do the optimal rounding (i.e., of how to decide what
         // interval is so small we should not wait at all).
         double microseconds = (timeout - now).ToMilliseconds() * 1000;
 
-        if (ChaosMode::isActive(ChaosMode::TimerScheduling)) {
+        if (ChaosMode::isActive(ChaosFeature::TimerScheduling)) {
           // The mean value of sFractions must be 1 to ensure that
           // the average of a long sequence of timeouts converges to the
           // actual sum of their times.
           static const float sFractions[] = {
             0.0f, 0.25f, 0.5f, 0.75f, 1.0f, 1.75f, 2.75f
           };
           microseconds *=
             sFractions[ChaosMode::randomUint32LessThan(ArrayLength(sFractions))];
--- a/xpcom/threads/nsEventQueue.cpp
+++ b/xpcom/threads/nsEventQueue.cpp
@@ -90,17 +90,17 @@ nsEventQueue::PutEvent(nsIRunnable* aRun
 }
 
 void
 nsEventQueue::PutEvent(already_AddRefed<nsIRunnable>&& aRunnable)
 {
   // Avoid calling AddRef+Release while holding our monitor.
   nsCOMPtr<nsIRunnable> event(aRunnable);
 
-  if (ChaosMode::isActive(ChaosMode::ThreadScheduling)) {
+  if (ChaosMode::isActive(ChaosFeature::ThreadScheduling)) {
     // With probability 0.5, yield so other threads have a chance to
     // dispatch events to this queue first.
     if (ChaosMode::randomUint32LessThan(2)) {
       PR_Sleep(PR_INTERVAL_NO_WAIT);
     }
   }
 
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -279,17 +279,17 @@ private:
   nsThreadShutdownContext* mShutdownContext;
 };
 
 //-----------------------------------------------------------------------------
 
 static void
 SetupCurrentThreadForChaosMode()
 {
-  if (!ChaosMode::isActive(ChaosMode::ThreadScheduling)) {
+  if (!ChaosMode::isActive(ChaosFeature::ThreadScheduling)) {
     return;
   }
 
 #ifdef XP_LINUX
   // PR_SetThreadPriority doesn't really work since priorities >
   // PR_PRIORITY_NORMAL can't be set by non-root users. Instead we'll just use
   // setpriority(2) to set random 'nice values'. In regular Linux this is only
   // a dynamic adjustment so it still doesn't really do what we want, but tools
@@ -921,17 +921,17 @@ nsThread::SetPriority(int32_t aPriority)
   } else if (mPriority < PRIORITY_NORMAL) {
     pri = PR_PRIORITY_HIGH;
   } else if (mPriority > PRIORITY_NORMAL) {
     pri = PR_PRIORITY_LOW;
   } else {
     pri = PR_PRIORITY_NORMAL;
   }
   // If chaos mode is active, retain the randomly chosen priority
-  if (!ChaosMode::isActive(ChaosMode::ThreadScheduling)) {
+  if (!ChaosMode::isActive(ChaosFeature::ThreadScheduling)) {
     PR_SetThreadPriority(mThread, pri);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsThread::AdjustPriority(int32_t aDelta)