Bug 1024388: Allow JAR channels to retarget to a different thread. r=bz,jduell
authorKyle Huey <khuey@kylehuey.com>
Tue, 17 Jun 2014 09:39:23 -0700
changeset 189136 97fa54d04c484f91ca409f3e44173f0adac8ffdb
parent 189135 9a02ba6359bb572cc382ff33cd486e10d1accc42
child 189137 16ff50091d32fa55b1aeae765d30ab4e8cbee9bc
push id26977
push userkwierso@gmail.com
push dateWed, 18 Jun 2014 01:21:03 +0000
treeherdermozilla-central@73679988dd7f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, jduell
bugs1024388
milestone33.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 1024388: Allow JAR channels to retarget to a different thread. r=bz,jduell
modules/libjar/nsJARChannel.cpp
modules/libjar/nsJARChannel.h
netwerk/base/public/nsIThreadRetargetableRequest.idl
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -219,16 +219,18 @@ nsJARChannel::~nsJARChannel()
 NS_IMPL_ISUPPORTS_INHERITED(nsJARChannel,
                             nsHashPropertyBag,
                             nsIRequest,
                             nsIChannel,
                             nsIStreamListener,
                             nsIRequestObserver,
                             nsIDownloadObserver,
                             nsIRemoteOpenFileListener,
+                            nsIThreadRetargetableRequest,
+                            nsIThreadRetargetableStreamListener,
                             nsIJARChannel)
 
 nsresult 
 nsJARChannel::Init(nsIURI *uri)
 {
     nsresult rv;
     mJarURI = do_QueryInterface(uri, &rv);
     if (NS_FAILED(rv))
@@ -429,16 +431,30 @@ nsJARChannel::NotifyError(nsresult aErro
     MOZ_ASSERT(NS_FAILED(aError));
 
     mStatus = aError;
 
     OnStartRequest(nullptr, nullptr);
     OnStopRequest(nullptr, nullptr, aError);
 }
 
+void
+nsJARChannel::FireOnProgress(uint64_t aProgress)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mProgressSink);
+
+  if (mLoadFlags & LOAD_BACKGROUND) {
+    return;
+  }
+
+  mProgressSink->OnProgress(this, nullptr, aProgress,
+                            uint64_t(mContentLength));
+}
+
 //-----------------------------------------------------------------------------
 // nsIRequest
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsJARChannel::GetName(nsACString &result)
 {
     return mJarURI->GetSpec(result);
@@ -967,17 +983,21 @@ nsJARChannel::OnRemoteFileOpenComplete(n
 // nsIStreamListener
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsJARChannel::OnStartRequest(nsIRequest *req, nsISupports *ctx)
 {
     LOG(("nsJARChannel::OnStartRequest [this=%x %s]\n", this, mSpec.get()));
 
-    return mListener->OnStartRequest(this, mListenerContext);
+    mRequest = req;
+    nsresult rv = mListener->OnStartRequest(this, mListenerContext);
+    mRequest = nullptr;
+
+    return rv;
 }
 
 NS_IMETHODIMP
 nsJARChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status)
 {
     LOG(("nsJARChannel::OnStopRequest [this=%x %s status=%x]\n",
         this, mSpec.get(), status));
 
@@ -1015,14 +1035,49 @@ nsJARChannel::OnDataAvailable(nsIRequest
 
     nsresult rv;
 
     rv = mListener->OnDataAvailable(this, mListenerContext, stream, offset, count);
 
     // simply report progress here instead of hooking ourselves up as a
     // nsITransportEventSink implementation.
     // XXX do the 64-bit stuff for real
-    if (mProgressSink && NS_SUCCEEDED(rv) && !(mLoadFlags & LOAD_BACKGROUND))
-        mProgressSink->OnProgress(this, nullptr, offset + count,
-                                  uint64_t(mContentLength));
+    if (mProgressSink && NS_SUCCEEDED(rv)) {
+        if (NS_IsMainThread()) {
+            FireOnProgress(offset + count);
+        } else {
+            nsCOMPtr<nsIRunnable> runnable =
+              NS_NewRunnableMethodWithArg<uint64_t>(this,
+                                                    &nsJARChannel::FireOnProgress,
+                                                    offset + count);
+            NS_DispatchToMainThread(runnable);
+        }
+    }
 
     return rv; // let the pump cancel on failure
 }
+
+NS_IMETHODIMP
+nsJARChannel::RetargetDeliveryTo(nsIEventTarget* aEventTarget)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIThreadRetargetableRequest> request = do_QueryInterface(mRequest);
+  if (!request) {
+    return NS_ERROR_NO_INTERFACE;
+  }
+
+  return request->RetargetDeliveryTo(aEventTarget);
+}
+
+NS_IMETHODIMP
+nsJARChannel::CheckListenerChain()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIThreadRetargetableStreamListener> listener =
+    do_QueryInterface(mListener);
+  if (!listener) {
+    return NS_ERROR_NO_INTERFACE;
+  }
+
+  return listener->CheckListenerChain();
+}
--- a/modules/libjar/nsJARChannel.h
+++ b/modules/libjar/nsJARChannel.h
@@ -11,54 +11,63 @@
 #include "nsIInputStreamPump.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIProgressEventSink.h"
 #include "nsIStreamListener.h"
 #include "nsIRemoteOpenFileListener.h"
 #include "nsIZipReader.h"
 #include "nsIDownloader.h"
 #include "nsILoadGroup.h"
+#include "nsIThreadRetargetableRequest.h"
+#include "nsIThreadRetargetableStreamListener.h"
 #include "nsHashPropertyBag.h"
 #include "nsIFile.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "prlog.h"
 
 class nsJARInputThunk;
 
 //-----------------------------------------------------------------------------
 
 class nsJARChannel : public nsIJARChannel
                    , public nsIDownloadObserver
                    , public nsIStreamListener
                    , public nsIRemoteOpenFileListener
+                   , public nsIThreadRetargetableRequest
+                   , public nsIThreadRetargetableStreamListener
                    , public nsHashPropertyBag
 {
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIREQUEST
     NS_DECL_NSICHANNEL
     NS_DECL_NSIJARCHANNEL
     NS_DECL_NSIDOWNLOADOBSERVER
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSISTREAMLISTENER
     NS_DECL_NSIREMOTEOPENFILELISTENER
+    NS_DECL_NSITHREADRETARGETABLEREQUEST
+    NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
 
     nsJARChannel();
-    virtual ~nsJARChannel();
 
     nsresult Init(nsIURI *uri);
 
 private:
+    virtual ~nsJARChannel();
+
     nsresult CreateJarInput(nsIZipReaderCache *, nsJARInputThunk **);
     nsresult LookupFile();
     nsresult OpenLocalFile();
     void NotifyError(nsresult aError);
 
+    void FireOnProgress(uint64_t aProgress);
+
 #if defined(PR_LOGGING)
     nsCString                       mSpec;
 #endif
 
     bool                            mOpened;
 
     nsCOMPtr<nsIJARURI>             mJarURI;
     nsCOMPtr<nsIURI>                mOriginalURI;
@@ -80,15 +89,18 @@ private:
     uint32_t                        mLoadFlags;
     nsresult                        mStatus;
     bool                            mIsPending;
     bool                            mIsUnsafe;
     bool                            mOpeningRemote;
 
     nsCOMPtr<nsIStreamListener>     mDownloader;
     nsCOMPtr<nsIInputStreamPump>    mPump;
+    // mRequest is only non-null during OnStartRequest, so we'll have a pointer
+    // to the request if we get called back via RetargetDeliveryTo.
+    nsCOMPtr<nsIRequest>            mRequest;
     nsCOMPtr<nsIFile>               mJarFile;
     nsCOMPtr<nsIURI>                mJarBaseURI;
     nsCString                       mJarEntry;
     nsCString                       mInnerJarEntry;
 };
 
 #endif // nsJARChannel_h__
--- a/netwerk/base/public/nsIThreadRetargetableRequest.idl
+++ b/netwerk/base/public/nsIThreadRetargetableRequest.idl
@@ -15,23 +15,21 @@ interface nsIEventTarget;
  * data off the main thread.
  */
 [uuid(27b84c48-5a73-4ba4-a8a4-8b5e649a145e)]
 interface nsIThreadRetargetableRequest : nsISupports
 {
   /**
    * Called to retarget delivery of OnDataAvailable to another thread. Should
    * only be called before AsyncOpen for nsIWebsocketChannels, or during
-   * OnStartRequest for nsIHttpChannels.
-   * Note: For nsIHttpChannels, OnStartRequest and OnStopRequest will still be
+   * OnStartRequest for nsIChannels.
+   * Note: For nsIChannels, OnStartRequest and OnStopRequest will still be
    * delivered on the main thread.
    *
    * @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);
 };
-
-