transportflow.h 4.5 KB

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