Bug 1405286: Part 1 - Allow retrieving the delivery target from retargetable requests. r?dragana draft
authorKris Maglione <maglione.k@gmail.com>
Sat, 14 Oct 2017 18:30:38 -0700
changeset 680557 a2571644a61a3457956a659173e776237ed93ede
parent 680521 039963b038304d3d4ced3315c181bc74c5c798bd
child 680558 c0e8ab1c9368b546a98019ca70086630680b85e7
push id84532
push usermaglione.k@gmail.com
push dateSun, 15 Oct 2017 03:07:18 +0000
reviewersdragana
bugs1405286
milestone58.0a1
Bug 1405286: Part 1 - Allow retrieving the delivery target from retargetable requests. r?dragana After data delivery for a request has been retargeted, there's no reliable way to get the appropriate event target to re-dispatch data events after asynchronous processing. While it's technically possible to retrieve the current thread from OnDataAvailable callbacks and re-use that for later dispatch, that approach has some issues: 1) It's not currently possible to reliably map the current thread to the thread pool that owns it. That means that if data delivery is being targetted to a thread pool, attempts to redispatch events to the previous delivery thread might lead to long delays when one thread in a pool is blocked. 2) If a filter wishes to dispatch data events to the wrapped listeners before it's recieved any data (as extensions StreamFilters sometimes do), there's no way to determine the proper event target without waiting for initial data to be received. Simply returning the correct event target from the request solves both of these problems. MozReview-Commit-ID: CJxq7O4399R
modules/libjar/nsJARChannel.cpp
netwerk/base/nsBaseChannel.cpp
netwerk/base/nsIThreadRetargetableRequest.idl
netwerk/base/nsInputStreamPump.cpp
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/InterceptedHttpChannel.cpp
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/websocket/BaseWebSocketChannel.cpp
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -1170,16 +1170,29 @@ nsJARChannel::RetargetDeliveryTo(nsIEven
   if (!request) {
     return NS_ERROR_NO_INTERFACE;
   }
 
   return request->RetargetDeliveryTo(aEventTarget);
 }
 
 NS_IMETHODIMP
+nsJARChannel::GetDeliveryTarget(nsIEventTarget** aEventTarget)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIThreadRetargetableRequest> request = do_QueryInterface(mRequest);
+  if (!request) {
+    return NS_ERROR_NO_INTERFACE;
+  }
+
+  return request->GetDeliveryTarget(aEventTarget);
+}
+
+NS_IMETHODIMP
 nsJARChannel::CheckListenerChain()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIThreadRetargetableStreamListener> listener =
     do_QueryInterface(mListener);
   if (!listener) {
     return NS_ERROR_NO_INTERFACE;
--- a/netwerk/base/nsBaseChannel.cpp
+++ b/netwerk/base/nsBaseChannel.cpp
@@ -970,16 +970,30 @@ nsBaseChannel::RetargetDeliveryTo(nsIEve
   }
 
   NS_ENSURE_TRUE(req, NS_ERROR_NOT_IMPLEMENTED);
 
   return req->RetargetDeliveryTo(aEventTarget);
 }
 
 NS_IMETHODIMP
+nsBaseChannel::GetDeliveryTarget(nsIEventTarget** aEventTarget)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_INITIALIZED);
+
+  nsCOMPtr<nsIThreadRetargetableRequest> req;
+    req = do_QueryInterface(mRequest);
+
+  NS_ENSURE_TRUE(req, NS_ERROR_NOT_IMPLEMENTED);
+  return req->GetDeliveryTarget(aEventTarget);
+}
+
+NS_IMETHODIMP
 nsBaseChannel::CheckListenerChain()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!mAllowThreadRetargeting) {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
--- a/netwerk/base/nsIThreadRetargetableRequest.idl
+++ b/netwerk/base/nsIThreadRetargetableRequest.idl
@@ -27,9 +27,11 @@ interface nsIThreadRetargetableRequest :
    * @param aNewTarget New event target, e.g. thread or threadpool.
    *
    * Note: no return value is given. If the retargeting cannot be handled,
    * normal delivery to the main thread will continue. As such, listeners
    * should be ready to deal with OnDataAvailable on either the main thread or
    * the new target thread.
    */
   void retargetDeliveryTo(in nsIEventTarget aNewTarget);
+
+  readonly attribute nsIEventTarget deliveryTarget;
 };
--- a/netwerk/base/nsInputStreamPump.cpp
+++ b/netwerk/base/nsInputStreamPump.cpp
@@ -770,8 +770,18 @@ nsInputStreamPump::RetargetDeliveryTo(ns
         }
     }
     LOG(("nsInputStreamPump::RetargetDeliveryTo [this=%p aNewTarget=%p] "
          "%s listener [%p] rv[%" PRIx32 "]",
          this, aNewTarget, (mTargetThread == aNewTarget ? "success" : "failure"),
          (nsIStreamListener*)mListener, static_cast<uint32_t>(rv)));
     return rv;
 }
+
+NS_IMETHODIMP
+nsInputStreamPump::GetDeliveryTarget(nsIEventTarget** aNewTarget)
+{
+    RecursiveMutexAutoLock lock(mMutex);
+
+    nsCOMPtr<nsIEventTarget> target = mTargetThread;
+    target.forget(aNewTarget);
+    return NS_OK;
+}
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -3381,16 +3381,29 @@ HttpChannelChild::RetargetDeliveryTo(nsI
     MutexAutoLock lock(mEventTargetMutex);
     mODATarget = aNewTarget;
   }
 
   mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::success;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+HttpChannelChild::GetDeliveryTarget(nsIEventTarget** aEventTarget)
+{
+  MutexAutoLock lock(mEventTargetMutex);
+
+  nsCOMPtr<nsIEventTarget> target = mODATarget;
+  if (!mODATarget) {
+    target = GetCurrentThreadEventTarget();
+  }
+  target.forget(aEventTarget);
+  return NS_OK;
+}
+
 void
 HttpChannelChild::ResetInterception()
 {
   NS_ENSURE_TRUE_VOID(gNeckoChild != nullptr);
 
   if (mInterceptListener) {
     mInterceptListener->Cleanup();
   }
--- a/netwerk/protocol/http/InterceptedHttpChannel.cpp
+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp
@@ -1074,16 +1074,25 @@ InterceptedHttpChannel::RetargetDelivery
   if (!mPump) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   return mPump->RetargetDeliveryTo(aNewTarget);
 }
 
 NS_IMETHODIMP
+InterceptedHttpChannel::GetDeliveryTarget(nsIEventTarget** aEventTarget)
+{
+  if (!mPump) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+  return mPump->GetDeliveryTarget(aEventTarget);
+}
+
+NS_IMETHODIMP
 InterceptedHttpChannel::CheckListenerChain()
 {
   MOZ_ASSERT(NS_IsMainThread());
   nsresult rv = NS_OK;
   nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
   do_QueryInterface(mListener, &rv);
   if (retargetableListener) {
     rv = retargetableListener->CheckListenerChain();
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -7745,16 +7745,29 @@ nsHttpChannel::RetargetDeliveryTo(nsIEve
             nsCOMPtr<nsIEventTarget> main = GetMainThreadEventTarget();
             NS_ENSURE_TRUE(main, NS_ERROR_UNEXPECTED);
             rv = retargetableCachePump->RetargetDeliveryTo(main);
         }
     }
     return rv;
 }
 
+
+NS_IMETHODIMP
+nsHttpChannel::GetDeliveryTarget(nsIEventTarget** aEventTarget)
+{
+    if (mCachePump) {
+        return mCachePump->GetDeliveryTarget(aEventTarget);
+    }
+    if (mTransactionPump) {
+        return mTransactionPump->GetDeliveryTarget(aEventTarget);
+    }
+    return NS_ERROR_NOT_AVAILABLE;
+}
+
 //-----------------------------------------------------------------------------
 // nsHttpChannel::nsThreadRetargetableStreamListener
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsHttpChannel::CheckListenerChain()
 {
     NS_ASSERTION(NS_IsMainThread(), "Should be on main thread!");
--- a/netwerk/protocol/websocket/BaseWebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/BaseWebSocketChannel.cpp
@@ -354,16 +354,29 @@ BaseWebSocketChannel::RetargetDeliveryTo
   MOZ_ASSERT(!mTargetThread, "Delivery target should be set once, before AsyncOpen");
   MOZ_ASSERT(!mWasOpened, "Should not be called after AsyncOpen!");
 
   mTargetThread = do_QueryInterface(aTargetThread);
   MOZ_ASSERT(mTargetThread);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+BaseWebSocketChannel::GetDeliveryTarget(nsIEventTarget** aTargetThread)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIEventTarget> target = mTargetThread;
+  if (!target) {
+    target = GetCurrentThreadEventTarget();
+  }
+  target.forget(aTargetThread);
+  return NS_OK;
+}
+
 BaseWebSocketChannel::ListenerAndContextContainer::ListenerAndContextContainer(
                                                nsIWebSocketListener* aListener,
                                                nsISupports* aContext)
   : mListener(aListener)
   , mContext(aContext)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mListener);