media/mtransport/transportflow.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/media/mtransport/transportflow.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,143 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +// Original author: ekr@rtfm.com
    1.11 +
    1.12 +#ifndef transportflow_h__
    1.13 +#define transportflow_h__
    1.14 +
    1.15 +#include <deque>
    1.16 +#include <queue>
    1.17 +#include <string>
    1.18 +
    1.19 +#include "nscore.h"
    1.20 +#include "nsISupportsImpl.h"
    1.21 +#include "mozilla/Scoped.h"
    1.22 +#include "transportlayer.h"
    1.23 +#include "m_cpp_utils.h"
    1.24 +#include "nsAutoPtr.h"
    1.25 +
    1.26 +// A stack of transport layers acts as a flow.
    1.27 +// Generally, one reads and writes to the top layer.
    1.28 +
    1.29 +// This code has a confusing hybrid threading model which
    1.30 +// probably needs some eventual refactoring.
    1.31 +// TODO(ekr@rtfm.com): Bug 844891
    1.32 +//
    1.33 +// TransportFlows are not inherently bound to a thread *but*
    1.34 +// TransportLayers can be. If any layer in a flow is bound
    1.35 +// to a given thread, then all layers in the flow MUST be
    1.36 +// bound to that thread and you can only manipulate the
    1.37 +// flow (push layers, write, etc.) on that thread.
    1.38 +//
    1.39 +// The sole official exception to this is that you are
    1.40 +// allowed to *destroy* a flow off the bound thread provided
    1.41 +// that there are no listeners on its signals. This exception
    1.42 +// is designed to allow idioms where you create the flow
    1.43 +// and then something goes wrong and you destroy it and
    1.44 +// you don't want to bother with a thread dispatch.
    1.45 +//
    1.46 +// Eventually we hope to relax the "no listeners"
    1.47 +// restriction by thread-locking the signals, but previous
    1.48 +// attempts have caused deadlocks.
    1.49 +//
    1.50 +// Most of these invariants are enforced by hard asserts
    1.51 +// (i.e., those which fire even in production builds).
    1.52 +
    1.53 +namespace mozilla {
    1.54 +
    1.55 +class TransportFlow : public nsISupports,
    1.56 +                      public sigslot::has_slots<> {
    1.57 + public:
    1.58 +  TransportFlow()
    1.59 +    : id_("(anonymous)"),
    1.60 +      state_(TransportLayer::TS_NONE),
    1.61 +      layers_(new std::deque<TransportLayer *>) {}
    1.62 +  TransportFlow(const std::string id)
    1.63 +    : id_(id),
    1.64 +      state_(TransportLayer::TS_NONE),
    1.65 +      layers_(new std::deque<TransportLayer *>) {}
    1.66 +
    1.67 +  ~TransportFlow();
    1.68 +
    1.69 +  const std::string& id() const { return id_; }
    1.70 +
    1.71 +  // Layer management. Note PushLayer() is not thread protected, so
    1.72 +  // either:
    1.73 +  // (a) Do it in the thread handling the I/O
    1.74 +  // (b) Do it before you activate the I/O system
    1.75 +  //
    1.76 +  // The flow takes ownership of the layers after a successful
    1.77 +  // push.
    1.78 +  nsresult PushLayer(TransportLayer *layer);
    1.79 +
    1.80 +  // Convenience function to push multiple layers on. Layers
    1.81 +  // are pushed on in the order that they are in the queue.
    1.82 +  // Any failures cause the flow to become inoperable and
    1.83 +  // destroys all the layers including those already pushed.
    1.84 +  // TODO(ekr@rtfm.com): Change layers to be ref-counted.
    1.85 +  nsresult PushLayers(nsAutoPtr<std::queue<TransportLayer *> > layers);
    1.86 +
    1.87 +  TransportLayer *top() const;
    1.88 +  TransportLayer *GetLayer(const std::string& id) const;
    1.89 +
    1.90 +  // Wrappers for whatever TLayer happens to be the top layer
    1.91 +  // at the time. This way you don't need to do top()->Foo().
    1.92 +  TransportLayer::State state(); // Current state
    1.93 +  TransportResult SendPacket(const unsigned char *data, size_t len);
    1.94 +
    1.95 +  // State has changed. Reflects the top flow.
    1.96 +  sigslot::signal2<TransportFlow *, TransportLayer::State>
    1.97 +    SignalStateChange;
    1.98 +
    1.99 +  // Data received on the flow
   1.100 +  sigslot::signal3<TransportFlow*, const unsigned char *, size_t>
   1.101 +    SignalPacketReceived;
   1.102 +
   1.103 +  bool Contains(TransportLayer *layer) const;
   1.104 +
   1.105 +  NS_DECL_THREADSAFE_ISUPPORTS
   1.106 +
   1.107 + private:
   1.108 +  DISALLOW_COPY_ASSIGN(TransportFlow);
   1.109 +
   1.110 +  // Check if we are on the right thread
   1.111 +  void CheckThread() const {
   1.112 +    if (!CheckThreadInt())
   1.113 +      MOZ_CRASH();
   1.114 +  }
   1.115 +
   1.116 +  bool CheckThreadInt() const {
   1.117 +    bool on;
   1.118 +
   1.119 +    if (!target_)  // OK if no thread set.
   1.120 +      return true;
   1.121 +    if (NS_FAILED(target_->IsOnCurrentThread(&on)))
   1.122 +      return false;
   1.123 +
   1.124 +    return on;
   1.125 +  }
   1.126 +
   1.127 +  void EnsureSameThread(TransportLayer *layer);
   1.128 +
   1.129 +  void StateChange(TransportLayer *layer, TransportLayer::State state);
   1.130 +  void StateChangeInt(TransportLayer::State state);
   1.131 +  void PacketReceived(TransportLayer* layer, const unsigned char *data,
   1.132 +      size_t len);
   1.133 +  static void DestroyFinal(nsAutoPtr<std::deque<TransportLayer *> > layers);
   1.134 +
   1.135 +  // Overload needed because we use deque internally and queue externally.
   1.136 +  static void ClearLayers(std::deque<TransportLayer *>* layers);
   1.137 +  static void ClearLayers(std::queue<TransportLayer *>* layers);
   1.138 +
   1.139 +  std::string id_;
   1.140 +  TransportLayer::State state_;
   1.141 +  ScopedDeletePtr<std::deque<TransportLayer *> > layers_;
   1.142 +  nsCOMPtr<nsIEventTarget> target_;
   1.143 +};
   1.144 +
   1.145 +}  // close namespace
   1.146 +#endif

mercurial