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