Source code

Revision control

Other Tools

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
public:
21
NS_DECL_THREADSAFE_ISUPPORTS
22
NS_DECL_NSITRANSPORTEVENTSINK
23
24
nsTransportEventSinkProxy(nsITransportEventSink* sink, nsIEventTarget* target)
25
: mSink(sink),
26
mTarget(target),
27
mLock("nsTransportEventSinkProxy.mLock"),
28
mLastEvent(nullptr) {
29
NS_ADDREF(mSink);
30
}
31
32
private:
33
virtual ~nsTransportEventSinkProxy() {
34
// our reference to mSink could be the last, so be sure to release
35
// it on the target thread. otherwise, we could get into trouble.
36
NS_ProxyRelease("nsTransportEventSinkProxy::mSink", mTarget,
37
dont_AddRef(mSink));
38
}
39
40
public:
41
nsITransportEventSink* mSink;
42
nsCOMPtr<nsIEventTarget> mTarget;
43
Mutex mLock;
44
nsTransportStatusEvent* mLastEvent;
45
};
46
47
class nsTransportStatusEvent : public Runnable {
48
public:
49
nsTransportStatusEvent(nsTransportEventSinkProxy* proxy,
50
nsITransport* transport, nsresult status,
51
int64_t progress, int64_t progressMax)
52
: Runnable("nsTransportStatusEvent"),
53
mProxy(proxy),
54
mTransport(transport),
55
mStatus(status),
56
mProgress(progress),
57
mProgressMax(progressMax) {}
58
59
~nsTransportStatusEvent() = default;
60
61
NS_IMETHOD Run() override {
62
// since this event is being handled, we need to clear the proxy's ref.
63
// if not coalescing all, then last event may not equal self!
64
{
65
MutexAutoLock lock(mProxy->mLock);
66
if (mProxy->mLastEvent == this) mProxy->mLastEvent = nullptr;
67
}
68
69
mProxy->mSink->OnTransportStatus(mTransport, mStatus, mProgress,
70
mProgressMax);
71
return NS_OK;
72
}
73
74
RefPtr<nsTransportEventSinkProxy> mProxy;
75
76
// parameters to OnTransportStatus
77
nsCOMPtr<nsITransport> mTransport;
78
nsresult mStatus;
79
int64_t mProgress;
80
int64_t mProgressMax;
81
};
82
83
NS_IMPL_ISUPPORTS(nsTransportEventSinkProxy, nsITransportEventSink)
84
85
NS_IMETHODIMP
86
nsTransportEventSinkProxy::OnTransportStatus(nsITransport* transport,
87
nsresult status, int64_t progress,
88
int64_t progressMax) {
89
nsresult rv = NS_OK;
90
RefPtr<nsTransportStatusEvent> event;
91
{
92
MutexAutoLock lock(mLock);
93
94
// try to coalesce events! ;-)
95
if (mLastEvent && (mLastEvent->mStatus == status)) {
96
mLastEvent->mStatus = status;
97
mLastEvent->mProgress = progress;
98
mLastEvent->mProgressMax = progressMax;
99
} else {
100
event = new nsTransportStatusEvent(this, transport, status, progress,
101
progressMax);
102
if (!event) rv = NS_ERROR_OUT_OF_MEMORY;
103
mLastEvent = event; // weak ref
104
}
105
}
106
if (event) {
107
rv = mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
108
if (NS_FAILED(rv)) {
109
NS_WARNING("unable to post transport status event");
110
111
MutexAutoLock lock(mLock); // cleanup.. don't reference anymore!
112
mLastEvent = nullptr;
113
}
114
}
115
return rv;
116
}
117
118
//-----------------------------------------------------------------------------
119
120
nsresult net_NewTransportEventSinkProxy(nsITransportEventSink** result,
121
nsITransportEventSink* sink,
122
nsIEventTarget* target) {
123
*result = new nsTransportEventSinkProxy(sink, target);
124
if (!*result) return NS_ERROR_OUT_OF_MEMORY;
125
NS_ADDREF(*result);
126
return NS_OK;
127
}