Bug 1347963 - part 4 - make nsInputStreamPump use RecursiveMutex; r=mcmanus
authorNathan Froyd <froydnj@mozilla.com>
Tue, 18 Apr 2017 12:20:04 -0400
changeset 616051 b9bd9b93f78693726cdb7ccfa7364c1e40c93f49
parent 616050 a9be4c2f9c2a8e4451e710879bd640fc685af09b
child 616052 069e7b402e3df80b74a6174cb8e42ca7ffdbf2e9
push id70554
push userbmo:mcooper@mozilla.com
push dateWed, 26 Jul 2017 17:18:29 +0000
reviewersmcmanus
bugs1347963
milestone56.0a1
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__