Bug 1347963 - part 4 - make nsInputStreamPump use RecursiveMutex; r=mcmanus
authorNathan Froyd <froydnj@mozilla.com>
Tue, 18 Apr 2017 12:20:04 -0400
changeset 422425 b9bd9b93f78693726cdb7ccfa7364c1e40c93f49
parent 422424 a9be4c2f9c2a8e4451e710879bd640fc685af09b
child 422426 069e7b402e3df80b74a6174cb8e42ca7ffdbf2e9
push id1517
push userjlorenzo@mozilla.com
push dateThu, 14 Sep 2017 16:50:54 +0000
treeherdermozilla-release@3b41fd564418 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus
bugs1347963
milestone56.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 1347963 - part 4 - make nsInputStreamPump use RecursiveMutex; r=mcmanus Making nsInputStreamPump slightly faster with RecursiveMutex is a good thing.
netwerk/base/nsInputStreamPump.cpp
netwerk/base/nsInputStreamPump.h
--- a/netwerk/base/nsInputStreamPump.cpp
+++ b/netwerk/base/nsInputStreamPump.cpp
@@ -39,17 +39,17 @@ nsInputStreamPump::nsInputStreamPump()
     , mStreamLength(UINT64_MAX)
     , mStatus(NS_OK)
     , mSuspendCount(0)
     , mLoadFlags(LOAD_NORMAL)
     , mProcessingCallbacks(false)
     , mWaitingForInputStreamReady(false)
     , mCloseWhenDone(false)
     , mRetargeting(false)
-    , mMonitor("nsInputStreamPump")
+    , mMutex("nsInputStreamPump")
 {
 }
 
 nsInputStreamPump::~nsInputStreamPump()
 {
 }
 
 nsresult
@@ -94,17 +94,17 @@ CallPeekFunc(nsIInputStream *aInStream, 
   data->mFunc(data->mClosure,
               reinterpret_cast<const uint8_t*>(aFromSegment), aCount);
   return NS_BINDING_ABORTED;
 }
 
 nsresult
 nsInputStreamPump::PeekStream(PeekSegmentFun callback, void* closure)
 {
-  ReentrantMonitorAutoEnter mon(mMonitor);
+  RecursiveMutexAutoLock lock(mMutex);
 
   NS_ASSERTION(mAsyncStream, "PeekStream called without stream");
 
   nsresult rv = CreateBufferedStreamIfNeeded();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // See if the pipe is closed by checking the return of Available.
   uint64_t dummy64;
@@ -118,17 +118,17 @@ nsInputStreamPump::PeekStream(PeekSegmen
                                        &data,
                                        nsIOService::gDefaultSegmentSize,
                                        &dummy);
 }
 
 nsresult
 nsInputStreamPump::EnsureWaiting()
 {
-    mMonitor.AssertCurrentThreadIn();
+    mMutex.AssertCurrentThreadIn();
 
     // no need to worry about multiple threads... an input stream pump lives
     // on only one thread at a time.
     MOZ_ASSERT(mAsyncStream);
     if (!mWaitingForInputStreamReady && !mProcessingCallbacks) {
         // Ensure OnStateStop is called on the main thread.
         if (mState == STATE_STOP) {
             nsCOMPtr<nsIEventTarget> mainThread = mLabeledMainThreadTarget
@@ -167,46 +167,46 @@ NS_IMPL_ISUPPORTS(nsInputStreamPump,
 
 //-----------------------------------------------------------------------------
 // nsInputStreamPump::nsIRequest
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsInputStreamPump::GetName(nsACString &result)
 {
-    ReentrantMonitorAutoEnter mon(mMonitor);
+    RecursiveMutexAutoLock lock(mMutex);
 
     result.Truncate();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsInputStreamPump::IsPending(bool *result)
 {
-    ReentrantMonitorAutoEnter mon(mMonitor);
+    RecursiveMutexAutoLock lock(mMutex);
 
     *result = (mState != STATE_IDLE);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsInputStreamPump::GetStatus(nsresult *status)
 {
-    ReentrantMonitorAutoEnter mon(mMonitor);
+    RecursiveMutexAutoLock lock(mMutex);
 
     *status = mStatus;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsInputStreamPump::Cancel(nsresult status)
 {
     MOZ_ASSERT(NS_IsMainThread());
 
-    ReentrantMonitorAutoEnter mon(mMonitor);
+    RecursiveMutexAutoLock lock(mMutex);
 
     LOG(("nsInputStreamPump::Cancel [this=%p status=%" PRIx32 "]\n",
         this, static_cast<uint32_t>(status)));
 
     if (NS_FAILED(mStatus)) {
         LOG(("  already canceled\n"));
         return NS_OK;
     }
@@ -225,72 +225,72 @@ nsInputStreamPump::Cancel(nsresult statu
         // on a closed stream works and will dispatch an event immediately.
     }
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsInputStreamPump::Suspend()
 {
-    ReentrantMonitorAutoEnter mon(mMonitor);
+    RecursiveMutexAutoLock lock(mMutex);
 
     LOG(("nsInputStreamPump::Suspend [this=%p]\n", this));
     NS_ENSURE_TRUE(mState != STATE_IDLE, NS_ERROR_UNEXPECTED);
     ++mSuspendCount;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsInputStreamPump::Resume()
 {
-    ReentrantMonitorAutoEnter mon(mMonitor);
+    RecursiveMutexAutoLock lock(mMutex);
 
     LOG(("nsInputStreamPump::Resume [this=%p]\n", this));
     NS_ENSURE_TRUE(mSuspendCount > 0, NS_ERROR_UNEXPECTED);
     NS_ENSURE_TRUE(mState != STATE_IDLE, NS_ERROR_UNEXPECTED);
 
     // There is a brief in-between state when we null out mAsyncStream in
     // OnStateStop() before calling OnStopRequest, and only afterwards set
     // STATE_IDLE, which we need to handle gracefully.
     if (--mSuspendCount == 0 && mAsyncStream)
         EnsureWaiting();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsInputStreamPump::GetLoadFlags(nsLoadFlags *aLoadFlags)
 {
-    ReentrantMonitorAutoEnter mon(mMonitor);
+    RecursiveMutexAutoLock lock(mMutex);
 
     *aLoadFlags = mLoadFlags;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsInputStreamPump::SetLoadFlags(nsLoadFlags aLoadFlags)
 {
-    ReentrantMonitorAutoEnter mon(mMonitor);
+    RecursiveMutexAutoLock lock(mMutex);
 
     mLoadFlags = aLoadFlags;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsInputStreamPump::GetLoadGroup(nsILoadGroup **aLoadGroup)
 {
-    ReentrantMonitorAutoEnter mon(mMonitor);
+    RecursiveMutexAutoLock lock(mMutex);
 
     NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsInputStreamPump::SetLoadGroup(nsILoadGroup *aLoadGroup)
 {
-    ReentrantMonitorAutoEnter mon(mMonitor);
+    RecursiveMutexAutoLock lock(mMutex);
 
     mLoadGroup = aLoadGroup;
     return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsInputStreamPump::nsIInputStreamPump implementation
 //-----------------------------------------------------------------------------
@@ -313,17 +313,17 @@ nsInputStreamPump::Init(nsIInputStream *
     mLabeledMainThreadTarget = mainThreadTarget;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsInputStreamPump::AsyncRead(nsIStreamListener *listener, nsISupports *ctxt)
 {
-    ReentrantMonitorAutoEnter mon(mMonitor);
+    RecursiveMutexAutoLock lock(mMutex);
 
     NS_ENSURE_TRUE(mState == STATE_IDLE, NS_ERROR_IN_PROGRESS);
     NS_ENSURE_ARG_POINTER(listener);
     MOZ_ASSERT(NS_IsMainThread(), "nsInputStreamPump should be read from the "
                                   "main thread only.");
 
     //
     // OK, we need to use the stream transport service if
@@ -412,22 +412,22 @@ nsInputStreamPump::OnInputStreamReady(ns
 
     // this function has been called from a PLEvent, so we can safely call
     // any listener or progress sink methods directly from here.
 
     for (;;) {
         // There should only be one iteration of this loop happening at a time.
         // To prevent AsyncWait() (called during callbacks or on other threads)
         // from creating a parallel OnInputStreamReady(), we use:
-        // -- a monitor; and
+        // -- a mutex; and
         // -- a boolean mProcessingCallbacks to detect parallel loops
-        //    when exiting the monitor for callbacks.
-        ReentrantMonitorAutoEnter lock(mMonitor);
+        //    when exiting the mutex for callbacks.
+        RecursiveMutexAutoLock lock(mMutex);
 
-        // Prevent parallel execution during callbacks, while out of monitor.
+        // Prevent parallel execution during callbacks, while out of mutex.
         if (mProcessingCallbacks) {
             MOZ_ASSERT(!mProcessingCallbacks);
             break;
         }
         mProcessingCallbacks = true;
         if (mSuspendCount || mState == STATE_IDLE) {
             mWaitingForInputStreamReady = false;
             mProcessingCallbacks = false;
@@ -506,17 +506,17 @@ nsInputStreamPump::OnInputStreamReady(ns
         mState = nextState;
     }
     return NS_OK;
 }
 
 uint32_t
 nsInputStreamPump::OnStateStart()
 {
-    mMonitor.AssertCurrentThreadIn();
+    mMutex.AssertCurrentThreadIn();
 
     AUTO_PROFILER_LABEL("nsInputStreamPump::OnStateStart", NETWORK);
 
     LOG(("  OnStateStart [this=%p]\n", this));
 
     nsresult rv;
 
     // need to check the reason why the stream is ready.  this is required
@@ -525,36 +525,35 @@ nsInputStreamPump::OnStateStart()
     if (NS_SUCCEEDED(mStatus)) {
         uint64_t avail;
         rv = mAsyncStream->Available(&avail);
         if (NS_FAILED(rv) && rv != NS_BASE_STREAM_CLOSED)
             mStatus = rv;
     }
 
     {
-        // Note: Must exit monitor for call to OnStartRequest to avoid
+        // Note: Must exit mutex for call to OnStartRequest to avoid
         // deadlocks when calls to RetargetDeliveryTo for multiple
         // nsInputStreamPumps are needed (e.g. nsHttpChannel).
-        mMonitor.Exit();
+        RecursiveMutexAutoUnlock unlock(mMutex);
         rv = mListener->OnStartRequest(this, mListenerContext);
-        mMonitor.Enter();
     }
 
     // an error returned from OnStartRequest should cause us to abort; however,
     // we must not stomp on mStatus if already canceled.
     if (NS_FAILED(rv) && NS_SUCCEEDED(mStatus))
         mStatus = rv;
 
     return NS_SUCCEEDED(mStatus) ? STATE_TRANSFER : STATE_STOP;
 }
 
 uint32_t
 nsInputStreamPump::OnStateTransfer()
 {
-    mMonitor.AssertCurrentThreadIn();
+    mMutex.AssertCurrentThreadIn();
 
     AUTO_PROFILER_LABEL("nsInputStreamPump::OnStateTransfer", NETWORK);
 
     LOG(("  OnStateTransfer [this=%p]\n", this));
 
     // if canceled, go directly to STATE_STOP...
     if (NS_FAILED(mStatus))
         return STATE_STOP;
@@ -604,24 +603,23 @@ nsInputStreamPump::OnStateTransfer()
             uint32_t odaAvail =
                 avail > UINT32_MAX ?
                 UINT32_MAX : uint32_t(avail);
 
             LOG(("  calling OnDataAvailable [offset=%" PRIu64 " count=%" PRIu64 "(%u)]\n",
                 mStreamOffset, avail, odaAvail));
 
             {
-                // Note: Must exit monitor for call to OnStartRequest to avoid
+                // Note: Must exit mutex for call to OnStartRequest to avoid
                 // deadlocks when calls to RetargetDeliveryTo for multiple
                 // nsInputStreamPumps are needed (e.g. nsHttpChannel).
-                mMonitor.Exit();
+                RecursiveMutexAutoUnlock unlock(mMutex);
                 rv = mListener->OnDataAvailable(this, mListenerContext,
                                                 mBufferedStream, mStreamOffset,
                                                 odaAvail);
-                mMonitor.Enter();
             }
 
             // don't enter this code if ODA failed or called Cancel
             if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(mStatus)) {
                 // test to see if this ODA failed to consume data
                 if (seekable) {
                     // NOTE: if Tell fails, which can happen if the stream is
                     // now closed, then we assume that everything was read.
@@ -667,29 +665,29 @@ nsInputStreamPump::OnStateTransfer()
         }
     }
     return STATE_STOP;
 }
 
 nsresult
 nsInputStreamPump::CallOnStateStop()
 {
-    ReentrantMonitorAutoEnter mon(mMonitor);
+    RecursiveMutexAutoLock lock(mMutex);
 
     MOZ_ASSERT(NS_IsMainThread(),
                "CallOnStateStop should only be called on the main thread.");
 
     mState = OnStateStop();
     return NS_OK;
 }
 
 uint32_t
 nsInputStreamPump::OnStateStop()
 {
-    mMonitor.AssertCurrentThreadIn();
+    mMutex.AssertCurrentThreadIn();
 
     if (!NS_IsMainThread()) {
         // Hopefully temporary hack: OnStateStop should only run on the main
         // thread, but we're seeing some rare off-main-thread calls. For now
         // just redispatch to the main thread in release builds, and crash in
         // debug builds.
         MOZ_ASSERT(NS_IsMainThread(),
                    "OnStateStop should only be called on the main thread.");
@@ -720,22 +718,21 @@ nsInputStreamPump::OnStateStop()
     else if (mCloseWhenDone)
         mAsyncStream->Close();
 
     mAsyncStream = nullptr;
     mBufferedStream = nullptr;
     mTargetThread = nullptr;
     mIsPending = false;
     {
-        // Note: Must exit monitor for call to OnStartRequest to avoid
+        // Note: Must exit mutex for call to OnStartRequest to avoid
         // deadlocks when calls to RetargetDeliveryTo for multiple
         // nsInputStreamPumps are needed (e.g. nsHttpChannel).
-        mMonitor.Exit();
+        RecursiveMutexAutoUnlock unlock(mMutex);
         mListener->OnStopRequest(this, mListenerContext, mStatus);
-        mMonitor.Enter();
     }
     mListener = nullptr;
     mListenerContext = nullptr;
 
     if (mLoadGroup)
         mLoadGroup->RemoveRequest(this, nullptr, mStatus);
 
     return STATE_IDLE;
@@ -765,17 +762,17 @@ nsInputStreamPump::CreateBufferedStreamI
 
 //-----------------------------------------------------------------------------
 // nsIThreadRetargetableRequest
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsInputStreamPump::RetargetDeliveryTo(nsIEventTarget* aNewTarget)
 {
-    ReentrantMonitorAutoEnter mon(mMonitor);
+    RecursiveMutexAutoLock lock(mMutex);
 
     NS_ENSURE_ARG(aNewTarget);
     NS_ENSURE_TRUE(mState == STATE_START || mState == STATE_TRANSFER,
                    NS_ERROR_UNEXPECTED);
 
     // If canceled, do not retarget. Return with canceled status.
     if (NS_FAILED(mStatus)) {
         return mStatus;
--- a/netwerk/base/nsInputStreamPump.h
+++ b/netwerk/base/nsInputStreamPump.h
@@ -6,30 +6,31 @@
 #ifndef nsInputStreamPump_h__
 #define nsInputStreamPump_h__
 
 #include "nsIInputStreamPump.h"
 #include "nsIAsyncInputStream.h"
 #include "nsIThreadRetargetableRequest.h"
 #include "nsCOMPtr.h"
 #include "mozilla/Attributes.h"
-#include "mozilla/ReentrantMonitor.h"
+#include "mozilla/RecursiveMutex.h"
 
 class nsIInputStream;
 class nsILoadGroup;
 class nsIStreamListener;
 
 class nsInputStreamPump final : public nsIInputStreamPump
                               , public nsIInputStreamCallback
                               , public nsIThreadRetargetableRequest
 {
     ~nsInputStreamPump();
 
 public:
-    typedef mozilla::ReentrantMonitorAutoEnter ReentrantMonitorAutoEnter;
+    typedef mozilla::RecursiveMutexAutoLock RecursiveMutexAutoLock;
+    typedef mozilla::RecursiveMutexAutoUnlock RecursiveMutexAutoUnlock;
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIREQUEST
     NS_DECL_NSIINPUTSTREAMPUMP
     NS_DECL_NSIINPUTSTREAMCALLBACK
     NS_DECL_NSITHREADRETARGETABLEREQUEST
 
     nsInputStreamPump();
 
@@ -98,12 +99,12 @@ protected:
     // True while in OnInputStreamReady, calling OnStateStart, OnStateTransfer
     // and OnStateStop. Used to prevent calls to AsyncWait during callbacks.
     bool                          mProcessingCallbacks;
     // True if waiting on the "input stream ready" callback.
     bool                          mWaitingForInputStreamReady;
     bool                          mCloseWhenDone;
     bool                          mRetargeting;
     // Protects state/member var accesses across multiple threads.
-    mozilla::ReentrantMonitor     mMonitor;
+    mozilla::RecursiveMutex       mMutex;
 };
 
 #endif // !nsInputStreamChannel_h__