transportflow.h (3214B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 // Original author: ekr@rtfm.com 8 9 #ifndef transportflow_h__ 10 #define transportflow_h__ 11 12 #include <deque> 13 #include <string> 14 15 #include "m_cpp_utils.h" 16 #include "mozilla/UniquePtr.h" 17 #include "nsISupportsImpl.h" 18 #include "nscore.h" 19 #include "transportlayer.h" 20 21 // A stack of transport layers acts as a flow. 22 // Generally, one reads and writes to the top layer. 23 24 // This code has a confusing hybrid threading model which 25 // probably needs some eventual refactoring. 26 // TODO(ekr@rtfm.com): Bug 844891 27 // 28 // TransportFlows are not inherently bound to a thread *but* 29 // TransportLayers can be. If any layer in a flow is bound 30 // to a given thread, then all layers in the flow MUST be 31 // bound to that thread and you can only manipulate the 32 // flow (push layers, write, etc.) on that thread. 33 // 34 // The sole official exception to this is that you are 35 // allowed to *destroy* a flow off the bound thread provided 36 // that there are no listeners on its signals. This exception 37 // is designed to allow idioms where you create the flow 38 // and then something goes wrong and you destroy it and 39 // you don't want to bother with a thread dispatch. 40 // 41 // Eventually we hope to relax the "no listeners" 42 // restriction by thread-locking the signals, but previous 43 // attempts have caused deadlocks. 44 // 45 // Most of these invariants are enforced by hard asserts 46 // (i.e., those which fire even in production builds). 47 48 namespace mozilla { 49 50 class TransportFlow final : public nsISupports { 51 public: 52 TransportFlow() 53 : id_("(anonymous)"), layers_(new std::deque<TransportLayer*>) {} 54 explicit TransportFlow(const std::string id) 55 : id_(id), layers_(new std::deque<TransportLayer*>) {} 56 57 const std::string& id() const { return id_; } 58 59 // Layer management. Note PushLayer() is not thread protected, so 60 // either: 61 // (a) Do it in the thread handling the I/O 62 // (b) Do it before you activate the I/O system 63 // 64 // The flow takes ownership of the layers after a successful 65 // push. 66 void PushLayer(TransportLayer* layer); 67 68 TransportLayer* GetLayer(const std::string& id) const; 69 70 NS_DECL_THREADSAFE_ISUPPORTS 71 72 private: 73 ~TransportFlow(); 74 75 DISALLOW_COPY_ASSIGN(TransportFlow); 76 77 // Check if we are on the right thread 78 void CheckThread() const { 79 if (!CheckThreadInt()) MOZ_CRASH(); 80 } 81 82 bool CheckThreadInt() const { 83 bool on; 84 85 if (!target_) // OK if no thread set. 86 return true; 87 if (NS_FAILED(target_->IsOnCurrentThread(&on))) return false; 88 89 return on; 90 } 91 92 void EnsureSameThread(TransportLayer* layer); 93 94 static void DestroyFinal(UniquePtr<std::deque<TransportLayer*>> layers); 95 96 // Overload needed because we use deque internally and queue externally. 97 static void ClearLayers(std::deque<TransportLayer*>* layers); 98 99 std::string id_; 100 UniquePtr<std::deque<TransportLayer*>> layers_; 101 nsCOMPtr<nsIEventTarget> target_; 102 }; 103 104 } // namespace mozilla 105 #endif