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/. */
7 // Original author: ekr@rtfm.com
9 #ifndef transportflow_h__
10 #define transportflow_h__
17 #include "nsISupportsImpl.h"
18 #include "mozilla/Scoped.h"
19 #include "transportlayer.h"
20 #include "m_cpp_utils.h"
21 #include "nsAutoPtr.h"
23 // A stack of transport layers acts as a flow.
24 // Generally, one reads and writes to the top layer.
26 // This code has a confusing hybrid threading model which
27 // probably needs some eventual refactoring.
28 // TODO(ekr@rtfm.com): Bug 844891
30 // TransportFlows are not inherently bound to a thread *but*
31 // TransportLayers can be. If any layer in a flow is bound
32 // to a given thread, then all layers in the flow MUST be
33 // bound to that thread and you can only manipulate the
34 // flow (push layers, write, etc.) on that thread.
36 // The sole official exception to this is that you are
37 // allowed to *destroy* a flow off the bound thread provided
38 // that there are no listeners on its signals. This exception
39 // is designed to allow idioms where you create the flow
40 // and then something goes wrong and you destroy it and
41 // you don't want to bother with a thread dispatch.
43 // Eventually we hope to relax the "no listeners"
44 // restriction by thread-locking the signals, but previous
45 // attempts have caused deadlocks.
47 // Most of these invariants are enforced by hard asserts
48 // (i.e., those which fire even in production builds).
52 class TransportFlow
: public nsISupports
,
53 public sigslot::has_slots
<> {
57 state_(TransportLayer::TS_NONE
),
58 layers_(new std::deque
<TransportLayer
*>) {}
59 explicit TransportFlow(const std::string id
)
61 state_(TransportLayer::TS_NONE
),
62 layers_(new std::deque
<TransportLayer
*>) {}
64 const std::string
& id() const { return id_
; }
66 // Layer management. Note PushLayer() is not thread protected, so
68 // (a) Do it in the thread handling the I/O
69 // (b) Do it before you activate the I/O system
71 // The flow takes ownership of the layers after a successful
73 nsresult
PushLayer(TransportLayer
*layer
);
75 // Convenience function to push multiple layers on. Layers
76 // are pushed on in the order that they are in the queue.
77 // Any failures cause the flow to become inoperable and
78 // destroys all the layers including those already pushed.
79 // TODO(ekr@rtfm.com): Change layers to be ref-counted.
80 nsresult
PushLayers(nsAutoPtr
<std::queue
<TransportLayer
*> > layers
);
82 TransportLayer
*top() const;
83 TransportLayer
*GetLayer(const std::string
& id
) const;
85 // Wrappers for whatever TLayer happens to be the top layer
86 // at the time. This way you don't need to do top()->Foo().
87 TransportLayer::State
state(); // Current state
88 TransportResult
SendPacket(const unsigned char *data
, size_t len
);
90 // State has changed. Reflects the top flow.
91 sigslot::signal2
<TransportFlow
*, TransportLayer::State
>
94 // Data received on the flow
95 sigslot::signal3
<TransportFlow
*, const unsigned char *, size_t>
98 bool Contains(TransportLayer
*layer
) const;
100 NS_DECL_THREADSAFE_ISUPPORTS
105 DISALLOW_COPY_ASSIGN(TransportFlow
);
107 // Check if we are on the right thread
108 void CheckThread() const {
109 if (!CheckThreadInt())
113 bool CheckThreadInt() const {
116 if (!target_
) // OK if no thread set.
118 if (NS_FAILED(target_
->IsOnCurrentThread(&on
)))
124 void EnsureSameThread(TransportLayer
*layer
);
126 void StateChange(TransportLayer
*layer
, TransportLayer::State state
);
127 void StateChangeInt(TransportLayer::State state
);
128 void PacketReceived(TransportLayer
* layer
, const unsigned char *data
,
130 static void DestroyFinal(nsAutoPtr
<std::deque
<TransportLayer
*> > layers
);
132 // Overload needed because we use deque internally and queue externally.
133 static void ClearLayers(std::deque
<TransportLayer
*>* layers
);
134 static void ClearLayers(std::queue
<TransportLayer
*>* layers
);
137 TransportLayer::State state_
;
138 ScopedDeletePtr
<std::deque
<TransportLayer
*> > layers_
;
139 nsCOMPtr
<nsIEventTarget
> target_
;