Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include "mozilla/Mutex.h"
6 : #include "nsTransportUtils.h"
7 : #include "nsITransport.h"
8 : #include "nsProxyRelease.h"
9 : #include "nsThreadUtils.h"
10 : #include "nsAutoPtr.h"
11 : #include "nsCOMPtr.h"
12 :
13 : using namespace mozilla;
14 :
15 : //-----------------------------------------------------------------------------
16 :
17 : class nsTransportStatusEvent;
18 :
19 : class nsTransportEventSinkProxy : public nsITransportEventSink
20 : {
21 : public:
22 : NS_DECL_THREADSAFE_ISUPPORTS
23 : NS_DECL_NSITRANSPORTEVENTSINK
24 :
25 3 : nsTransportEventSinkProxy(nsITransportEventSink *sink,
26 : nsIEventTarget *target)
27 3 : : mSink(sink)
28 : , mTarget(target)
29 : , mLock("nsTransportEventSinkProxy.mLock")
30 3 : , mLastEvent(nullptr)
31 : {
32 3 : NS_ADDREF(mSink);
33 3 : }
34 :
35 : private:
36 6 : virtual ~nsTransportEventSinkProxy()
37 6 : {
38 : // our reference to mSink could be the last, so be sure to release
39 : // it on the target thread. otherwise, we could get into trouble.
40 3 : NS_ProxyRelease(
41 6 : "nsTransportEventSinkProxy::mSink", mTarget, dont_AddRef(mSink));
42 9 : }
43 :
44 : public:
45 : nsITransportEventSink *mSink;
46 : nsCOMPtr<nsIEventTarget> mTarget;
47 : Mutex mLock;
48 : nsTransportStatusEvent *mLastEvent;
49 : };
50 :
51 : class nsTransportStatusEvent : public Runnable
52 : {
53 : public:
54 16 : nsTransportStatusEvent(nsTransportEventSinkProxy *proxy,
55 : nsITransport *transport,
56 : nsresult status,
57 : int64_t progress,
58 : int64_t progressMax)
59 16 : : Runnable("nsTransportStatusEvent")
60 : , mProxy(proxy)
61 : , mTransport(transport)
62 : , mStatus(status)
63 : , mProgress(progress)
64 16 : , mProgressMax(progressMax)
65 16 : {}
66 :
67 48 : ~nsTransportStatusEvent() {}
68 :
69 16 : NS_IMETHOD Run() override
70 : {
71 : // since this event is being handled, we need to clear the proxy's ref.
72 : // if not coalescing all, then last event may not equal self!
73 : {
74 32 : MutexAutoLock lock(mProxy->mLock);
75 16 : if (mProxy->mLastEvent == this)
76 3 : mProxy->mLastEvent = nullptr;
77 : }
78 :
79 32 : mProxy->mSink->OnTransportStatus(mTransport, mStatus, mProgress,
80 32 : mProgressMax);
81 16 : return NS_OK;
82 : }
83 :
84 : RefPtr<nsTransportEventSinkProxy> mProxy;
85 :
86 : // parameters to OnTransportStatus
87 : nsCOMPtr<nsITransport> mTransport;
88 : nsresult mStatus;
89 : int64_t mProgress;
90 : int64_t mProgressMax;
91 : };
92 :
93 47 : NS_IMPL_ISUPPORTS(nsTransportEventSinkProxy, nsITransportEventSink)
94 :
95 : NS_IMETHODIMP
96 16 : nsTransportEventSinkProxy::OnTransportStatus(nsITransport *transport,
97 : nsresult status,
98 : int64_t progress,
99 : int64_t progressMax)
100 : {
101 16 : nsresult rv = NS_OK;
102 32 : RefPtr<nsTransportStatusEvent> event;
103 : {
104 32 : MutexAutoLock lock(mLock);
105 :
106 : // try to coalesce events! ;-)
107 16 : if (mLastEvent && (mLastEvent->mStatus == status)) {
108 0 : mLastEvent->mStatus = status;
109 0 : mLastEvent->mProgress = progress;
110 0 : mLastEvent->mProgressMax = progressMax;
111 : }
112 : else {
113 : event = new nsTransportStatusEvent(this, transport, status,
114 16 : progress, progressMax);
115 16 : if (!event)
116 0 : rv = NS_ERROR_OUT_OF_MEMORY;
117 16 : mLastEvent = event; // weak ref
118 : }
119 : }
120 16 : if (event) {
121 16 : rv = mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
122 16 : if (NS_FAILED(rv)) {
123 0 : NS_WARNING("unable to post transport status event");
124 :
125 0 : MutexAutoLock lock(mLock); // cleanup.. don't reference anymore!
126 0 : mLastEvent = nullptr;
127 : }
128 : }
129 32 : return rv;
130 : }
131 :
132 : //-----------------------------------------------------------------------------
133 :
134 : nsresult
135 3 : net_NewTransportEventSinkProxy(nsITransportEventSink **result,
136 : nsITransportEventSink *sink,
137 : nsIEventTarget *target)
138 : {
139 3 : *result = new nsTransportEventSinkProxy(sink, target);
140 3 : if (!*result)
141 0 : return NS_ERROR_OUT_OF_MEMORY;
142 3 : NS_ADDREF(*result);
143 3 : return NS_OK;
144 : }
|