Backed out changeset 203ad2fab9aa (bug 1378342)
authorSebastian Hengst <archaeopteryx@coole-files.de>
Tue, 29 Aug 2017 09:17:15 +0200
changeset 426978 3c5a1bc02ad95ab418269054aae119cfa77fa7e5
parent 426977 101500f732af4bd440c3da45ef4a23c9694d3a16
child 426979 591f78a8d99d548de1a96fad78c4022454cce4a6
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1378342
milestone57.0a1
backs out203ad2fab9aad74fa6349d7fe54aaa5977ae78ca
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
Backed out changeset 203ad2fab9aa (bug 1378342)
dom/abort/AbortController.cpp
dom/abort/AbortController.h
dom/abort/AbortSignal.cpp
dom/abort/AbortSignal.h
dom/abort/tests/file_abort_controller.html
dom/webidl/AbortController.webidl
--- a/dom/abort/AbortController.cpp
+++ b/dom/abort/AbortController.cpp
@@ -7,17 +7,18 @@
 #include "AbortController.h"
 #include "AbortSignal.h"
 #include "mozilla/dom/AbortControllerBinding.h"
 #include "WorkerPrivate.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AbortController, mGlobal, mSignal)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AbortController, mGlobal, mSignal,
+                                      mFollowingSignal)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(AbortController)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(AbortController)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AbortController)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
@@ -89,10 +90,38 @@ AbortController::Abort()
 
   mAborted = true;
 
   if (mSignal) {
     mSignal->Abort();
   }
 }
 
+void
+AbortController::Follow(AbortSignal& aSignal)
+{
+  AbortSignal::Follower::Follow(&aSignal);
+}
+
+void
+AbortController::Unfollow(AbortSignal& aSignal)
+{
+  if (mFollowingSignal != &aSignal) {
+    return;
+  }
+
+  AbortSignal::Follower::Unfollow();
+}
+
+AbortSignal*
+AbortController::Following() const
+{
+  return mFollowingSignal;
+}
+
+void
+AbortController::Aborted()
+{
+  Abort();
+}
+
 } // dom namespace
 } // mozilla namespace
--- a/dom/abort/AbortController.h
+++ b/dom/abort/AbortController.h
@@ -3,29 +3,26 @@
 /* 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/. */
 
 #ifndef mozilla_dom_AbortController_h
 #define mozilla_dom_AbortController_h
 
 #include "mozilla/dom/BindingDeclarations.h"
-#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/AbortSignal.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 
-class nsIGlobalObject;
-
 namespace mozilla {
 namespace dom {
 
-class AbortSignal;
-
 class AbortController final : public nsISupports
                             , public nsWrapperCache
+                            , public AbortSignal::Follower
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AbortController)
 
   static bool
   IsEnabled(JSContext* aCx, JSObject* aGlobal);
 
@@ -41,16 +38,29 @@ public:
   GetParentObject() const;
 
   AbortSignal*
   Signal();
 
   void
   Abort();
 
+  void
+  Follow(AbortSignal& aSignal);
+
+  void
+  Unfollow(AbortSignal& aSignal);
+
+  AbortSignal*
+  Following() const;
+
+  // AbortSignal::Follower
+
+  void Aborted() override;
+
 private:
   ~AbortController() = default;
 
   nsCOMPtr<nsIGlobalObject> mGlobal;
   RefPtr<AbortSignal> mSignal;
 
   bool mAborted;
 };
--- a/dom/abort/AbortSignal.cpp
+++ b/dom/abort/AbortSignal.cpp
@@ -62,16 +62,18 @@ AbortSignal::Abort()
   for (uint32_t i = 0; i < mFollowers.Length(); ++i) {
     mFollowers[i]->Aborted();
   }
 
   EventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
 
+  // TODO which kind of event should we dispatch here?
+
   RefPtr<Event> event =
     Event::Constructor(this, NS_LITERAL_STRING("abort"), init);
   event->SetTrusted(true);
 
   bool dummy;
   DispatchEvent(event, &dummy);
 }
 
@@ -86,29 +88,54 @@ AbortSignal::AddFollower(AbortSignal::Fo
 
 void
 AbortSignal::RemoveFollower(AbortSignal::Follower* aFollower)
 {
   MOZ_DIAGNOSTIC_ASSERT(aFollower);
   mFollowers.RemoveElement(aFollower);
 }
 
+bool
+AbortSignal::CanAcceptFollower(AbortSignal::Follower* aFollower) const
+{
+  MOZ_DIAGNOSTIC_ASSERT(aFollower);
+
+  if (!mController) {
+    return true;
+  }
+
+  if (aFollower == mController) {
+    return false;
+  }
+
+  AbortSignal* following = mController->Following();
+  if (!following) {
+    return true;
+  }
+
+  return following->CanAcceptFollower(aFollower);
+}
+
 // AbortSignal::Follower
 // ----------------------------------------------------------------------------
 
 AbortSignal::Follower::~Follower()
 {
   Unfollow();
 }
 
 void
 AbortSignal::Follower::Follow(AbortSignal* aSignal)
 {
   MOZ_DIAGNOSTIC_ASSERT(aSignal);
 
+  if (!aSignal->CanAcceptFollower(this)) {
+    return;
+  }
+
   Unfollow();
 
   mFollowingSignal = aSignal;
   aSignal->AddFollower(this);
 }
 
 void
 AbortSignal::Follower::Unfollow()
--- a/dom/abort/AbortSignal.h
+++ b/dom/abort/AbortSignal.h
@@ -54,16 +54,19 @@ public:
   IMPL_EVENT_HANDLER(abort);
 
   void
   AddFollower(Follower* aFollower);
 
   void
   RemoveFollower(Follower* aFollower);
 
+  bool
+  CanAcceptFollower(Follower* aFollower) const;
+
 private:
   ~AbortSignal() = default;
 
   RefPtr<AbortController> mController;
 
   // Raw pointers. Follower unregisters itself in the DTOR.
   nsTArray<Follower*> mFollowers;
 
--- a/dom/abort/tests/file_abort_controller.html
+++ b/dom/abort/tests/file_abort_controller.html
@@ -27,16 +27,59 @@ function testUpdateData() {
   is(ac.signal.aborted, false, "By default AbortSignal.aborted is false");
  
   ac.abort();
   is(ac.signal.aborted, true, "Signal is aborted");
  
   next();
 }
  
+function testFollowingOurself() {
+  // Let's follow ourself
+  var ac = new AbortController();
+  ac.follow(ac.signal);
+ 
+  ac.abort();
+  is(ac.signal.aborted, true, "Signal is aborted");
+ 
+  next();
+}
+ 
+function testFollowingOther() {
+  // Let's follow another one
+  var ac1 = new AbortController();
+  var ac2 = new AbortController();
+  ac1.follow(ac2.signal);
+ 
+  ac2.abort();
+ 
+  is(ac1.signal.aborted, true, "Signal is aborted");
+  is(ac2.signal.aborted, true, "Signal is aborted");
+ 
+  next();
+}
+
+function testFollowingLoop() {
+  // ac1 -> ac2 -> ac3 -> ac1
+  var ac1 = new AbortController();
+  var ac2 = new AbortController();
+  var ac3 = new AbortController();
+  ac1.follow(ac2.signal);
+  ac2.follow(ac3.signal);
+  ac3.follow(ac1.signal);
+ 
+  ac3.abort();
+ 
+  is(ac1.signal.aborted, true, "Signal is aborted");
+  is(ac2.signal.aborted, true, "Signal is aborted");
+  is(ac3.signal.aborted, true, "Signal is aborted");
+ 
+  next();
+}
+ 
 function testAbortEvent() {
   var ac = new AbortController();
   ac.signal.onabort = function(e) {
     is(e.type, "abort", "Abort received");
     next();
   }
   ac.abort();
 }
@@ -83,16 +126,21 @@ function testWorkerFetchAndAbort() {
   w.postMessage('testWorkerFetchAndAbort');
 }
 
 var steps = [
   // Simple stuff
   testWebIDL,
   testUpdateData,
 
+  // Following algorithm
+  testFollowingOurself,
+  testFollowingOther,
+  testFollowingLoop,
+
   // Event propagation
   testAbortEvent,
 
   // fetch + signaling
   testAbortedFetch,
   testFetchAndAbort,
   testWorkerAbortedFetch,
   testWorkerFetchAndAbort,
--- a/dom/webidl/AbortController.webidl
+++ b/dom/webidl/AbortController.webidl
@@ -8,9 +8,11 @@
  */
 
 [Constructor(), Exposed=(Window,Worker),
  Func="AbortController::IsEnabled"]
 interface AbortController {
   readonly attribute AbortSignal signal;
 
   void abort();
+  void follow(AbortSignal signal);
+  void unfollow(AbortSignal signal);
 };