Backout changeset 5abbf6fd5466 (Bug 830100) for sctp_unittest failure ON A CLOSED TREE r=ryanvm
authorRandell Jesup <rjesup@jesup.org>
Tue, 09 Apr 2013 17:35:20 -0400
changeset 128229 75406eaf8351f14a1ea0b99aff0c24604c10edd7
parent 128228 6ceb449263707fa1451ecbd5132782d4e03ab2cb
child 128230 bcaa26984f9a0e74923a899687ec472a4848234a
push id24523
push useremorley@mozilla.com
push dateWed, 10 Apr 2013 12:12:44 +0000
treeherdermozilla-central@ee5ca214e87c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersryanvm
bugs830100
milestone23.0a1
backs out5abbf6fd546681cfee512037c35f6a7d70a8efcd
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
Backout changeset 5abbf6fd5466 (Bug 830100) for sctp_unittest failure ON A CLOSED TREE r=ryanvm
media/mtransport/test/sctp_unittest.cpp
media/mtransport/test/transport_unittests.cpp
media/mtransport/transportflow.cpp
media/mtransport/transportflow.h
media/mtransport/transportlayer.cpp
media/mtransport/transportlayer.h
media/mtransport/transportlayerloopback.h
--- a/media/mtransport/test/sctp_unittest.cpp
+++ b/media/mtransport/test/sctp_unittest.cpp
@@ -119,29 +119,23 @@ class TransportTestPeer : public sigslot
 
   ~TransportTestPeer() {
     std::cerr << "Destroying sctp connection flow=" <<
         static_cast<void *>(flow_.get()) << std::endl;
     usrsctp_close(sctp_);
     usrsctp_deregister_address(static_cast<void *>(this));
 
     test_utils->sts_target()->Dispatch(WrapRunnable(this,
-                                                   &TransportTestPeer::Disconnect_s),
+                                                   &TransportTestPeer::DisconnectInt),
                                       NS_DISPATCH_SYNC);
 
     std::cerr << "~TransportTestPeer() completed" << std::endl;
   }
 
   void ConnectSocket(TransportTestPeer *peer) {
-    test_utils->sts_target()->Dispatch(WrapRunnable(
-        this, &TransportTestPeer::ConnectSocket_s, peer),
-                                       NS_DISPATCH_SYNC);
-  }
-
-  void ConnectSocket_s(TransportTestPeer *peer) {
     loopback_->Connect(peer->loopback_);
 
     ASSERT_EQ((nsresult)NS_OK, flow_->PushLayer(loopback_));
 
     flow_->SignalPacketReceived.connect(this, &TransportTestPeer::PacketReceived);
 
     // SCTP here!
     ASSERT_TRUE(sctp_);
@@ -151,17 +145,17 @@ class TransportTestPeer : public sigslot
     ASSERT_GE(0, r);
 
     std::cerr << "Calling usrsctp_connect()" << std::endl;
     r = usrsctp_connect(sctp_, reinterpret_cast<struct sockaddr *>(
         &remote_addr_), sizeof(remote_addr_));
     ASSERT_GE(0, r);
   }
 
-  void Disconnect_s() {
+  void DisconnectInt() {
     if (flow_) {
       flow_ = nullptr;
     }
   }
 
   void Disconnect() {
     loopback_->Disconnect();
   }
@@ -192,30 +186,20 @@ class TransportTestPeer : public sigslot
 
     ++sent_;
   }
 
   int sent() const { return sent_; }
   int received() const { return received_; }
   bool connected() const { return connected_; }
 
-  TransportResult SendPacket_s(const unsigned char* data, size_t len) {
+  TransportResult SendPacket(const unsigned char* data, size_t len) {
     return flow_->SendPacket(data, len);
   }
 
-  TransportResult SendPacket(const unsigned char* data, size_t len) {
-    TransportResult res;
-
-    test_utils->sts_target()->Dispatch(WrapRunnableRet(
-        this, &TransportTestPeer::SendPacket_s, data, len, &res),
-                                       NS_DISPATCH_SYNC);
-
-    return res;
-  }
-
   void PacketReceived(TransportFlow * flow, const unsigned char* data,
                       size_t len) {
     std::cerr << "Received " << len << " bytes" << std::endl;
 
     // Pass the data to SCTP
 
     usrsctp_conninput(static_cast<void *>(this), data, len, 0);
   }
--- a/media/mtransport/test/transport_unittests.cpp
+++ b/media/mtransport/test/transport_unittests.cpp
@@ -37,50 +37,20 @@
 #include "gtest/gtest.h"
 #include "gtest_utils.h"
 
 using namespace mozilla;
 MOZ_MTLOG_MODULE("mtransport")
 
 MtransportTestUtils *test_utils;
 
-// Layer class which can't be initialized.
-class TransportLayerDummy : public TransportLayer {
- public:
-  TransportLayerDummy(bool allow_init, bool *destroyed)
-      : allow_init_(allow_init),
-        destroyed_(destroyed) {
-    *destroyed_ = false;
-  }
-
-  virtual ~TransportLayerDummy() {
-    *destroyed_ = true;
-  }
-
-  virtual nsresult InitInternal() {
-    return allow_init_ ? NS_OK : NS_ERROR_FAILURE;
-  }
-
-  virtual TransportResult SendPacket(const unsigned char *data, size_t len) {
-    MOZ_CRASH();  // Should never be called.
-    return 0;
-  }
-
-  TRANSPORT_LAYER_ID("lossy")
-
- private:
-  bool allow_init_;
-  bool *destroyed_;
-};
-
 // Class to simulate various kinds of network lossage
 class TransportLayerLossy : public TransportLayer {
  public:
   TransportLayerLossy() : loss_mask_(0), packet_(0) {}
-  ~TransportLayerLossy () {}
 
   virtual TransportResult SendPacket(const unsigned char *data, size_t len) {
     MOZ_MTLOG(PR_LOG_NOTICE, LAYER_INFO << "SendPacket(" << len << ")");
 
     if (loss_mask_ & (1 << (packet_ % 32))) {
       MOZ_MTLOG(PR_LOG_NOTICE, "Dropping packet");
       ++packet_;
       return len;
@@ -162,36 +132,26 @@ class TransportTestPeer : public sigslot
   }
 
   ~TransportTestPeer() {
     test_utils->sts_target()->Dispatch(
       WrapRunnable(this, &TransportTestPeer::DestroyFlow),
       NS_DISPATCH_SYNC);
   }
 
-
   void DestroyFlow() {
-    if (flow_) {
-      loopback_->Disconnect();
-      flow_ = nullptr;
-    }
+    loopback_->Disconnect();
+    flow_ = nullptr;
     ice_ctx_ = nullptr;
   }
 
-  void DisconnectDestroyFlow() {
-    loopback_->Disconnect();
-    disconnect_all();  // Disconnect from the signals;
-     flow_ = nullptr;
-  }
-
   void SetDtlsAllowAll() {
     nsresult res = dtls_->SetVerificationAllowAll();
     ASSERT_TRUE(NS_SUCCEEDED(res));
   }
-
   void SetDtlsPeer(TransportTestPeer *peer, int digests, unsigned int damage) {
     unsigned int mask = 1;
 
     for (int i=0; i<digests; i++) {
       unsigned char fingerprint_to_set[TransportLayerDtls::kMaxDigestLength];
 
       memcpy(fingerprint_to_set,
              peer->fingerprint_,
@@ -206,38 +166,31 @@ class TransportTestPeer : public sigslot
 
       ASSERT_TRUE(NS_SUCCEEDED(res));
 
       mask <<= 1;
     }
   }
 
 
-  void ConnectSocket_s(TransportTestPeer *peer) {
+  void ConnectSocket(TransportTestPeer *peer) {
     nsresult res;
     res = loopback_->Init();
     ASSERT_EQ((nsresult)NS_OK, res);
 
     loopback_->Connect(peer->loopback_);
 
     ASSERT_EQ((nsresult)NS_OK, flow_->PushLayer(loopback_));
     ASSERT_EQ((nsresult)NS_OK, flow_->PushLayer(logging_));
     ASSERT_EQ((nsresult)NS_OK, flow_->PushLayer(lossy_));
     ASSERT_EQ((nsresult)NS_OK, flow_->PushLayer(dtls_));
 
     flow_->SignalPacketReceived.connect(this, &TransportTestPeer::PacketReceived);
   }
 
-  void ConnectSocket(TransportTestPeer *peer) {
-    RUN_ON_THREAD(test_utils->sts_target(),
-                  WrapRunnable(this, & TransportTestPeer::ConnectSocket_s,
-                               peer),
-                  NS_DISPATCH_SYNC);
-  }
-
   void InitIce() {
     nsresult res;
 
     // Attach our slots
     ice_ctx_->SignalGatheringCompleted.
         connect(this, &TransportTestPeer::GatheringComplete);
 
     char name[100];
@@ -325,16 +278,17 @@ class TransportTestPeer : public sigslot
     test_utils->sts_target()->Dispatch(
       WrapRunnableRet(peer_->ice_ctx_, &NrIceCtx::StartChecks, &res),
       NS_DISPATCH_SYNC);
     ASSERT_TRUE(NS_SUCCEEDED(res));
   }
 
   TransportResult SendPacket(const unsigned char* data, size_t len) {
     TransportResult ret;
+    
     test_utils->sts_target()->Dispatch(
       WrapRunnableRet(flow_, &TransportFlow::SendPacket, data, len, &ret),
       NS_DISPATCH_SYNC);
 
     return ret;
   }
 
 
@@ -349,32 +303,22 @@ class TransportTestPeer : public sigslot
     std::cerr << "Received " << len << " bytes" << std::endl;
     ++received_;
   }
 
   void SetLoss(uint32_t loss) {
     lossy_->SetLoss(loss);
   }
 
-  TransportLayer::State state() {
-    TransportLayer::State tstate;
-
-    RUN_ON_THREAD(test_utils->sts_target(),
-                  WrapRunnableRet(flow_, &TransportFlow::state, &tstate),
-                  NS_DISPATCH_SYNC);
-
-    return tstate;
-  }
-
   bool connected() {
-    return state() == TransportLayer::TS_OPEN;
+    return flow_->state() == TransportLayer::TS_OPEN;
   }
 
   bool failed() {
-    return state() == TransportLayer::TS_ERROR;
+    return flow_->state() == TransportLayer::TS_ERROR;
   }
 
   size_t received() { return received_; }
 
  private:
   std::string name_;
   nsCOMPtr<nsIEventTarget> target_;
   size_t received_;
@@ -406,21 +350,16 @@ class TransportTest : public ::testing::
     delete p1_;
     delete p2_;
 
     //    Can't detach these
     //    PR_Close(fds_[0]);
     //    PR_Close(fds_[1]);
   }
 
-  void DestroyPeerFlows() {
-    p1_->DisconnectDestroyFlow();
-    p2_->DisconnectDestroyFlow();
-  }
-
   void SetUp() {
     nsresult rv;
     target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
     ASSERT_TRUE(NS_SUCCEEDED(rv));
 
     p1_ = new TransportTestPeer(target_, "P1");
     p2_ = new TransportTestPeer(target_, "P2");
   }
@@ -497,22 +436,16 @@ TEST_F(TransportTest, TestNoDtlsVerifica
   ConnectSocketExpectFail();
 }
 
 TEST_F(TransportTest, TestConnect) {
   SetDtlsPeer();
   ConnectSocket();
 }
 
-TEST_F(TransportTest, TestConnectDestroyFlowsMainThread) {
-  SetDtlsPeer();
-  ConnectSocket();
-  DestroyPeerFlows();
-}
-
 TEST_F(TransportTest, TestConnectAllowAll) {
   SetDtlsAllowAll();
   ConnectSocket();
 }
 
 TEST_F(TransportTest, TestConnectBadDigest) {
   SetDtlsPeer(1, 1);
 
@@ -562,69 +495,16 @@ TEST_F(TransportTest, TestConnectIce) {
 }
 
 TEST_F(TransportTest, TestTransferIce) {
   SetDtlsPeer();
   ConnectIce();
   TransferTest(1);
 }
 
-TEST(PushTests, LayerFail) {
-  TransportFlow flow;
-  nsresult rv;
-  bool destroyed1, destroyed2;
-
-  rv = flow.PushLayer(new TransportLayerDummy(true, &destroyed1));
-  ASSERT_TRUE(NS_SUCCEEDED(rv));
-
-  rv = flow.PushLayer(new TransportLayerDummy(false, &destroyed2));
-  ASSERT_TRUE(NS_FAILED(rv));
-
-  ASSERT_EQ(TransportLayer::TS_ERROR, flow.state());
-  ASSERT_EQ(true, destroyed1);
-  ASSERT_EQ(true, destroyed2);
-
-  rv = flow.PushLayer(new TransportLayerDummy(true, &destroyed1));
-  ASSERT_TRUE(NS_FAILED(rv));
-  ASSERT_EQ(true, destroyed1);
-}
-
-
-TEST(PushTests, LayersFail) {
-  TransportFlow flow;
-  nsresult rv;
-  bool destroyed1, destroyed2, destroyed3;
-
-  rv = flow.PushLayer(new TransportLayerDummy(true, &destroyed1));
-  ASSERT_TRUE(NS_SUCCEEDED(rv));
-
-  nsAutoPtr<std::queue<TransportLayer *> > layers(
-      new std::queue<TransportLayer *>());
-
-  layers->push(new TransportLayerDummy(true, &destroyed2));
-  layers->push(new TransportLayerDummy(false, &destroyed3));
-
-  rv = flow.PushLayers(layers);
-  ASSERT_TRUE(NS_FAILED(rv));
-
-  ASSERT_EQ(TransportLayer::TS_ERROR, flow.state());
-  ASSERT_EQ(true, destroyed1);
-  ASSERT_EQ(true, destroyed2);
-  ASSERT_EQ(true, destroyed3);
-
-  layers = new std::queue<TransportLayer *>();
-  layers->push(new TransportLayerDummy(true, &destroyed2));
-  layers->push(new TransportLayerDummy(true, &destroyed3));
-  rv = flow.PushLayers(layers);
-
-  ASSERT_TRUE(NS_FAILED(rv));
-  ASSERT_EQ(true, destroyed2);
-  ASSERT_EQ(true, destroyed3);
-}
-
 }  // end namespace
 
 int main(int argc, char **argv)
 {
   test_utils = new MtransportTestUtils();
 
   NSS_NoDB_Init(nullptr);
   NSS_SetDomesticPolicy();
--- a/media/mtransport/transportflow.cpp
+++ b/media/mtransport/transportflow.cpp
@@ -5,155 +5,112 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Original author: ekr@rtfm.com
 #include <deque>
 
 #include <prlog.h>
 
 #include "logging.h"
-#include "runnable_utils.h"
 #include "transportflow.h"
 #include "transportlayer.h"
 
 namespace mozilla {
 
 MOZ_MTLOG_MODULE("mtransport")
 
-// There are some hacks here to allow destruction off of
-// the main thread.
 TransportFlow::~TransportFlow() {
-  // Make sure that if we are off the right thread, we have
-  // no more attached signals.
-  if (!CheckThreadInt()) {
-    MOZ_ASSERT(SignalStateChange.is_empty());
-    MOZ_ASSERT(SignalPacketReceived.is_empty());
-  }
-
-  // Push the destruction onto the STS thread. Note that there
-  // is still some possibility that someone is accessing this
-  // object simultaneously, but as long as smart pointer discipline
-  // is maintained, it shouldn't be possible to access and
-  // destroy it simultaneously. The conversion to an nsAutoPtr
-  // ensures automatic destruction of the queue at exit of
-  // DestroyFinal.
-  nsAutoPtr<std::deque<TransportLayer*> > layers_tmp(layers_.forget());
-  RUN_ON_THREAD(target_,
-                WrapRunnableNM(&TransportFlow::DestroyFinal, layers_tmp),
-                NS_DISPATCH_NORMAL);
-}
-
-void TransportFlow::DestroyFinal(nsAutoPtr<std::deque<TransportLayer *> > layers) {
-  ClearLayers(layers);
-}
-
-void TransportFlow::ClearLayers(std::queue<TransportLayer *>* layers) {
-  while (!layers->empty()) {
-    delete layers->front();
-    layers->pop();
-  }
-}
-
-void TransportFlow::ClearLayers(std::deque<TransportLayer *>* layers) {
-  while (!layers->empty()) {
-    delete layers->front();
-    layers->pop_front();
+  for (std::deque<TransportLayer *>::iterator it = layers_.begin();
+       it != layers_.end(); ++it) {
+    delete *it;
   }
 }
 
 nsresult TransportFlow::PushLayer(TransportLayer *layer) {
-  CheckThread();
-  ScopedDeletePtr<TransportLayer> layer_tmp(layer);  // Destroy on failure.
-
   // Don't allow pushes once we are in error state.
   if (state_ == TransportLayer::TS_ERROR) {
     MOZ_MTLOG(PR_LOG_ERROR, id_ + ": Can't call PushLayer in error state for flow ");
     return NS_ERROR_FAILURE;
   }
 
   nsresult rv = layer->Init();
   if (!NS_SUCCEEDED(rv)) {
-    // Destroy the rest of the flow, because it's no longer in an acceptable
-    // state.
-    ClearLayers(layers_.get());
-
     // Set ourselves to have failed.
     MOZ_MTLOG(PR_LOG_ERROR, id_ << ": Layer initialization failed; invalidating");
     StateChangeInt(TransportLayer::TS_ERROR);
-
     return rv;
   }
-  EnsureSameThread(layer);
 
-  TransportLayer *old_layer = layers_->empty() ? nullptr : layers_->front();
+  TransportLayer *old_layer = layers_.empty() ? nullptr : layers_.front();
 
   // Re-target my signals to the new layer
   if (old_layer) {
     old_layer->SignalStateChange.disconnect(this);
     old_layer->SignalPacketReceived.disconnect(this);
   }
-  layers_->push_front(layer_tmp.forget());
+  layers_.push_front(layer);
   layer->Inserted(this, old_layer);
 
   layer->SignalStateChange.connect(this, &TransportFlow::StateChange);
   layer->SignalPacketReceived.connect(this, &TransportFlow::PacketReceived);
   StateChangeInt(layer->state());
 
   return NS_OK;
 }
 
 // This is all-or-nothing.
 nsresult TransportFlow::PushLayers(nsAutoPtr<std::queue<TransportLayer *> > layers) {
-  CheckThread();
-
   MOZ_ASSERT(!layers->empty());
   if (layers->empty()) {
     MOZ_MTLOG(PR_LOG_ERROR, id_ << ": Can't call PushLayers with empty layers");
     return NS_ERROR_INVALID_ARG;
   }
 
   // Don't allow pushes once we are in error state.
   if (state_ == TransportLayer::TS_ERROR) {
     MOZ_MTLOG(PR_LOG_ERROR, id_ << ": Can't call PushLayers in error state for flow ");
-    ClearLayers(layers.get());
     return NS_ERROR_FAILURE;
   }
 
   nsresult rv = NS_OK;
 
   // Disconnect all the old signals.
   disconnect_all();
 
   TransportLayer *layer;
 
   while (!layers->empty()) {
-    TransportLayer *old_layer = layers_->empty() ? nullptr : layers_->front();
+    TransportLayer *old_layer = layers_.empty() ? nullptr : layers_.front();
     layer = layers->front();
 
     rv = layer->Init();
     if (NS_FAILED(rv)) {
       MOZ_MTLOG(PR_LOG_ERROR, id_ << ": Layer initialization failed; invalidating flow ");
       break;
     }
 
-    EnsureSameThread(layer);
-
     // Push the layer onto the queue.
-    layers_->push_front(layer);
+    layers_.push_front(layer);
     layers->pop();
     layer->Inserted(this, old_layer);
   }
 
   if (NS_FAILED(rv)) {
     // Destroy any layers we could not push.
-    ClearLayers(layers);
+    while (!layers->empty()) {
+      delete layers->front();
+      layers->pop();
+    }
 
     // Now destroy the rest of the flow, because it's no longer
     // in an acceptable state.
-    ClearLayers(layers_);
+    while (!layers_.empty()) {
+      delete layers_.front();
+      layers_.pop_front();
+    }
 
     // Set ourselves to have failed.
     StateChangeInt(TransportLayer::TS_ERROR);
 
     // Return failure.
     return rv;
   }
 
@@ -161,82 +118,54 @@ nsresult TransportFlow::PushLayers(nsAut
   layer->SignalStateChange.connect(this, &TransportFlow::StateChange);
   layer->SignalPacketReceived.connect(this, &TransportFlow::PacketReceived);
   StateChangeInt(layer->state());  // Signals if the state changes.
 
   return NS_OK;
 }
 
 TransportLayer *TransportFlow::top() const {
-  CheckThread();
-
-  return layers_->empty() ? nullptr : layers_->front();
+  return layers_.empty() ? nullptr : layers_.front();
 }
 
 TransportLayer *TransportFlow::GetLayer(const std::string& id) const {
-  CheckThread();
-
-  for (std::deque<TransportLayer *>::const_iterator it = layers_->begin();
-       it != layers_->end(); ++it) {
+  for (std::deque<TransportLayer *>::const_iterator it = layers_.begin();
+       it != layers_.end(); ++it) {
     if ((*it)->id() == id)
       return *it;
   }
 
   return nullptr;
 }
 
 TransportLayer::State TransportFlow::state() {
-  CheckThread();
-
   return state_;
 }
 
 TransportResult TransportFlow::SendPacket(const unsigned char *data,
                                           size_t len) {
-  CheckThread();
-
   if (state_ != TransportLayer::TS_OPEN) {
     return TE_ERROR;
   }
   return top() ? top()->SendPacket(data, len) : TE_ERROR;
 }
 
-void TransportFlow::EnsureSameThread(TransportLayer *layer)  {
-  // Enforce that if any of the layers have a thread binding,
-  // they all have the same binding.
-  if (target_) {
-    const nsCOMPtr<nsIEventTarget>& lthread = layer->GetThread();
-
-    if (lthread && (lthread != target_))
-      MOZ_CRASH();
-  }
-  else {
-    target_ = layer->GetThread();
-  }
-}
-
 void TransportFlow::StateChangeInt(TransportLayer::State state) {
-  CheckThread();
-
   if (state == state_) {
     return;
   }
 
   state_ = state;
   SignalStateChange(this, state_);
 }
 
 void TransportFlow::StateChange(TransportLayer *layer,
                                 TransportLayer::State state) {
-  CheckThread();
-
   StateChangeInt(state);
 }
 
 void TransportFlow::PacketReceived(TransportLayer* layer,
                                    const unsigned char *data,
                                    size_t len) {
-  CheckThread();
-
   SignalPacketReceived(this, data, len);
 }
 
 }  // close namespace
--- a/media/mtransport/transportflow.h
+++ b/media/mtransport/transportflow.h
@@ -10,59 +10,31 @@
 #define transportflow_h__
 
 #include <deque>
 #include <queue>
 #include <string>
 
 #include "nscore.h"
 #include "nsISupportsImpl.h"
-#include "mozilla/Scoped.h"
 #include "transportlayer.h"
 #include "m_cpp_utils.h"
 
 // A stack of transport layers acts as a flow.
 // Generally, one reads and writes to the top layer.
-
-// This code has a confusing hybrid threading model which
-// probably needs some eventual refactoring.
-// TODO(ekr@rtfm.com): Bug 844891
-//
-// TransportFlows are not inherently bound to a thread *but*
-// TransportLayers can be. If any layer in a flow is bound
-// to a given thread, then all layers in the flow MUST be
-// bound to that thread and you can only manipulate the
-// flow (push layers, write, etc.) on that thread.
-//
-// The sole official exception to this is that you are
-// allowed to *destroy* a flow off the bound thread provided
-// that there are no listeners on its signals. This exception
-// is designed to allow idioms where you create the flow
-// and then something goes wrong and you destroy it and
-// you don't want to bother with a thread dispatch.
-//
-// Eventually we hope to relax the "no listeners"
-// restriction by thread-locking the signals, but previous
-// attempts have caused deadlocks.
-//
-// Most of these invariants are enforced by hard asserts
-// (i.e., those which fire even in production builds).
-
 namespace mozilla {
 
 class TransportFlow : public sigslot::has_slots<> {
  public:
   TransportFlow()
     : id_("(anonymous)"),
-      state_(TransportLayer::TS_NONE),
-      layers_(new std::deque<TransportLayer *>) {}
+      state_(TransportLayer::TS_NONE) {}
   TransportFlow(const std::string id)
     : id_(id),
-      state_(TransportLayer::TS_NONE),
-      layers_(new std::deque<TransportLayer *>) {}
+      state_(TransportLayer::TS_NONE) {}
 
   ~TransportFlow();
 
   const std::string& id() const { return id_; }
 
   // Layer management. Note PushLayer() is not thread protected, so
   // either:
   // (a) Do it in the thread handling the I/O
@@ -95,45 +67,20 @@ class TransportFlow : public sigslot::ha
   sigslot::signal3<TransportFlow*, const unsigned char *, size_t>
     SignalPacketReceived;
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TransportFlow)
 
  private:
   DISALLOW_COPY_ASSIGN(TransportFlow);
 
-  // Check if we are on the right thread
-  void CheckThread() const {
-    if (!CheckThreadInt())
-      MOZ_CRASH();
-  }
-
-  bool CheckThreadInt() const {
-    bool on;
-
-    if (!target_)  // OK if no thread set.
-      return true;
-    if (NS_FAILED(target_->IsOnCurrentThread(&on)))
-      return false;
-
-    return on;
-  }
-
-  void EnsureSameThread(TransportLayer *layer);
-
   void StateChange(TransportLayer *layer, TransportLayer::State state);
   void StateChangeInt(TransportLayer::State state);
   void PacketReceived(TransportLayer* layer, const unsigned char *data,
       size_t len);
-  static void DestroyFinal(nsAutoPtr<std::deque<TransportLayer *> > layers);
-
-  // Overload needed because we use deque internally and queue externally.
-  static void ClearLayers(std::deque<TransportLayer *>* layers);
-  static void ClearLayers(std::queue<TransportLayer *>* layers);
 
   std::string id_;
+  std::deque<TransportLayer *> layers_;
   TransportLayer::State state_;
-  ScopedDeletePtr<std::deque<TransportLayer *> > layers_;
-  nsCOMPtr<nsIEventTarget> target_;
 };
 
 }  // close namespace
 #endif
--- a/media/mtransport/transportlayer.cpp
+++ b/media/mtransport/transportlayer.cpp
@@ -27,25 +27,31 @@ nsresult TransportLayer::Init() {
     return rv;
   }
   state_ = TS_INIT;
 
   return NS_OK;
 }
 
 void TransportLayer::Inserted(TransportFlow *flow, TransportLayer *downward) {
+  flow_ = flow;
   downward_ = downward;
-  flow_id_ = flow->id();
+
   MOZ_MTLOG(PR_LOG_DEBUG, LAYER_INFO << "Inserted: downward='" <<
     (downward ? downward->id(): "none") << "'");
 
   WasInserted();
 }
 
 void TransportLayer::SetState(State state) {
   if (state != state_) {
     MOZ_MTLOG(PR_LOG_DEBUG, LAYER_INFO << "state " << state_ << "->" << state);
     state_ = state;
     SignalStateChange(this, state);
   }
 }
 
+const std::string& TransportLayer::flow_id() {
+    static const std::string empty;
+
+    return flow_ ? flow_->id() : empty;
+  }
 }  // close namespace
--- a/media/mtransport/transportlayer.h
+++ b/media/mtransport/transportlayer.h
@@ -40,17 +40,17 @@ class TransportLayer : public sigslot::h
   // We can't use "ERROR" because Windows has a macro named "ERROR"
   enum State { TS_NONE, TS_INIT, TS_CONNECTING, TS_OPEN, TS_CLOSED, TS_ERROR };
   enum Mode { STREAM, DGRAM };
 
   // Is this a stream or datagram flow
   TransportLayer(Mode mode = STREAM) :
     mode_(mode),
     state_(TS_NONE),
-    flow_id_(),
+    flow_(nullptr),
     downward_(nullptr) {}
 
   virtual ~TransportLayer() {}
 
   // Called to initialize
   nsresult Init();  // Called by Insert() to set up -- do not override
   virtual nsresult InitInternal() { return NS_OK; } // Called by Init
 
@@ -77,59 +77,49 @@ class TransportLayer : public sigslot::h
     return event->Run();
   }
 
   // Get the state
   State state() const { return state_; }
   // Must be implemented by derived classes
   virtual TransportResult SendPacket(const unsigned char *data, size_t len) = 0;
 
-  // Get the thread.
-  const nsCOMPtr<nsIEventTarget> GetThread() const {
-    return target_;
-  }
-
   // Event definitions that one can register for
   // State has changed
   sigslot::signal2<TransportLayer*, State> SignalStateChange;
   // Data received on the flow
   sigslot::signal3<TransportLayer*, const unsigned char *, size_t>
                          SignalPacketReceived;
 
   // Return the layer id for this layer
   virtual const std::string id() = 0;
 
   // The id of the flow
-  const std::string& flow_id() {
-    return flow_id_;
-  }
+  virtual const std::string& flow_id();
 
  protected:
   virtual void WasInserted() {}
   virtual void SetState(State state);
-  // Check if we are on the right thread
+
   void CheckThread() {
     NS_ABORT_IF_FALSE(CheckThreadInt(), "Wrong thread");
   }
 
   Mode mode_;
   State state_;
-  std::string flow_id_;
+  TransportFlow *flow_;  // The flow this is part of
   TransportLayer *downward_; // The next layer in the stack
   nsCOMPtr<nsIEventTarget> target_;
 
  private:
   DISALLOW_COPY_ASSIGN(TransportLayer);
 
   bool CheckThreadInt() {
     bool on;
-
-    if (!target_)  // OK if no thread set.
-      return true;
-
+    NS_ENSURE_TRUE(target_, false);
     NS_ENSURE_SUCCESS(target_->IsOnCurrentThread(&on), false);
     NS_ENSURE_TRUE(on, false);
 
     return true;
   }
 };
 
 #define LAYER_INFO "Flow[" << flow_id() << "(none)" << "]; Layer[" << id() << "]: "
--- a/media/mtransport/transportlayerloopback.h
+++ b/media/mtransport/transportlayerloopback.h
@@ -29,16 +29,17 @@
 // A simple loopback transport layer that is used for testing.
 namespace mozilla {
 
 class TransportLayerLoopback : public TransportLayer {
  public:
   TransportLayerLoopback() :
       peer_(nullptr),
       timer_(nullptr),
+      target_(nullptr),
       packets_(),
       packets_lock_(nullptr),
       deliverer_(nullptr) {}
 
   ~TransportLayerLoopback() {
     while (!packets_.empty()) {
       QueuedPacket *packet = packets_.front();
       packets_.pop();
@@ -124,15 +125,16 @@ class TransportLayerLoopback : public Tr
     TransportLayerLoopback *layer_;
   };
 
   // Queue a packet for delivery
   nsresult QueuePacket(const unsigned char *data, size_t len);
 
   TransportLayerLoopback* peer_;
   nsCOMPtr<nsITimer> timer_;
+  nsCOMPtr<nsIEventTarget> target_;
   std::queue<QueuedPacket *> packets_;
   PRLock *packets_lock_;
   nsRefPtr<Deliverer> deliverer_;
 };
 
 }  // close namespace
 #endif