forked from mirrors/gecko-dev
Bug 1869175 - netwerk nsSocketTransport2 thread-safety annotations r=necko-reviewers,kershaw,valentin
Differential Revision: https://phabricator.services.mozilla.com/D195979
This commit is contained in:
parent
ab4aad7ce6
commit
7a1b759c87
2 changed files with 121 additions and 92 deletions
|
|
@ -689,8 +689,8 @@ nsSocketOutputStream::AsyncWait(nsIOutputStreamCallback* callback,
|
|||
nsSocketTransport::nsSocketTransport()
|
||||
: mFD(this),
|
||||
mSocketTransportService(gSocketTransportService),
|
||||
mInput(this),
|
||||
mOutput(this) {
|
||||
mInput(new nsSocketInputStream(this)),
|
||||
mOutput(new nsSocketOutputStream(this)) {
|
||||
SOCKET_LOG(("creating nsSocketTransport @%p\n", this));
|
||||
|
||||
mTimeouts[TIMEOUT_CONNECT] = UINT16_MAX; // no timeout
|
||||
|
|
@ -925,10 +925,10 @@ void nsSocketTransport::SendStatus(nsresult status) {
|
|||
sink = mEventSink;
|
||||
switch (status) {
|
||||
case NS_NET_STATUS_SENDING_TO:
|
||||
progress = mOutput.ByteCount();
|
||||
progress = mOutput->ByteCount(lock);
|
||||
break;
|
||||
case NS_NET_STATUS_RECEIVING_FROM:
|
||||
progress = mInput.ByteCount();
|
||||
progress = mInput->ByteCount(lock);
|
||||
break;
|
||||
default:
|
||||
progress = 0;
|
||||
|
|
@ -1803,7 +1803,7 @@ void nsSocketTransport::OnMsgInputClosed(nsresult reason) {
|
|||
NS_BASE_STREAM_CLOSED; // XXX except if NS_FAILED(mCondition), right??
|
||||
} else {
|
||||
if (mState == STATE_TRANSFERRING) mPollFlags &= ~PR_POLL_READ;
|
||||
mInput.OnSocketReady(reason);
|
||||
mInput->OnSocketReady(reason);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1824,7 +1824,7 @@ void nsSocketTransport::OnMsgOutputClosed(nsresult reason) {
|
|||
NS_BASE_STREAM_CLOSED; // XXX except if NS_FAILED(mCondition), right??
|
||||
} else {
|
||||
if (mState == STATE_TRANSFERRING) mPollFlags &= ~PR_POLL_WRITE;
|
||||
mOutput.OnSocketReady(reason);
|
||||
mOutput->OnSocketReady(reason);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1964,8 +1964,8 @@ void nsSocketTransport::OnSocketEvent(uint32_t type, nsresult status,
|
|||
//
|
||||
// notify input/output streams in case either has a pending notify.
|
||||
//
|
||||
mInput.OnSocketReady(mCondition);
|
||||
mOutput.OnSocketReady(mCondition);
|
||||
mInput->OnSocketReady(mCondition);
|
||||
mOutput->OnSocketReady(mCondition);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2088,6 +2088,10 @@ void nsSocketTransport::OnSocketEvent(uint32_t type, nsresult status,
|
|||
}
|
||||
}
|
||||
|
||||
uint64_t nsSocketTransport::ByteCountReceived() { return mInput->ByteCount(); }
|
||||
|
||||
uint64_t nsSocketTransport::ByteCountSent() { return mOutput->ByteCount(); }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// socket handler impl
|
||||
|
||||
|
|
@ -2108,14 +2112,14 @@ void nsSocketTransport::OnSocketReady(PRFileDesc* fd, int16_t outFlags) {
|
|||
// assume that we won't need to poll any longer (the stream will
|
||||
// request that we poll again if it is still pending).
|
||||
mPollFlags &= ~PR_POLL_WRITE;
|
||||
mOutput.OnSocketReady(NS_OK);
|
||||
mOutput->OnSocketReady(NS_OK);
|
||||
}
|
||||
// if waiting to read and socket is readable or hit an exception.
|
||||
if ((mPollFlags & PR_POLL_READ) && (outFlags & ~PR_POLL_WRITE)) {
|
||||
// assume that we won't need to poll any longer (the stream will
|
||||
// request that we poll again if it is still pending).
|
||||
mPollFlags &= ~PR_POLL_READ;
|
||||
mInput.OnSocketReady(NS_OK);
|
||||
mInput->OnSocketReady(NS_OK);
|
||||
}
|
||||
// Update poll timeout in case it was changed
|
||||
{
|
||||
|
|
@ -2250,8 +2254,8 @@ void nsSocketTransport::OnSocketDetached(PRFileDesc* fd) {
|
|||
//
|
||||
// notify input/output streams
|
||||
//
|
||||
mInput.OnSocketReady(mCondition);
|
||||
mOutput.OnSocketReady(mCondition);
|
||||
mInput->OnSocketReady(mCondition);
|
||||
mOutput->OnSocketReady(mCondition);
|
||||
if (gIOService->IsNetTearingDown()) {
|
||||
if (mInputCopyContext) {
|
||||
NS_CancelAsyncCopy(mInputCopyContext, mCondition);
|
||||
|
|
@ -2263,7 +2267,7 @@ void nsSocketTransport::OnSocketDetached(PRFileDesc* fd) {
|
|||
}
|
||||
|
||||
if (mCondition == NS_ERROR_NET_RESET && mDNSRecord &&
|
||||
mOutput.ByteCount() == 0) {
|
||||
mOutput->ByteCount() == 0) {
|
||||
// If we are here, it's likely that we are retrying a transaction. Blocking
|
||||
// the already used address could increase the successful rate of the retry.
|
||||
mDNSRecord->ReportUnusable(SocketPort());
|
||||
|
|
@ -2331,7 +2335,7 @@ nsSocketTransport::OpenInputStream(uint32_t flags, uint32_t segsize,
|
|||
SOCKET_LOG(
|
||||
("nsSocketTransport::OpenInputStream [this=%p flags=%x]\n", this, flags));
|
||||
|
||||
NS_ENSURE_TRUE(!mInput.IsReferenced(), NS_ERROR_UNEXPECTED);
|
||||
NS_ENSURE_TRUE(!mInput->IsReferenced(), NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIAsyncInputStream> pipeIn;
|
||||
|
|
@ -2351,14 +2355,14 @@ nsSocketTransport::OpenInputStream(uint32_t flags, uint32_t segsize,
|
|||
true, segsize, segcount);
|
||||
|
||||
// async copy from socket to pipe
|
||||
rv = NS_AsyncCopy(&mInput, pipeOut, mSocketTransportService,
|
||||
rv = NS_AsyncCopy(mInput.get(), pipeOut, mSocketTransportService,
|
||||
NS_ASYNCCOPY_VIA_WRITESEGMENTS, segsize, nullptr, nullptr,
|
||||
true, true, getter_AddRefs(inputCopyContext));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
result = pipeIn;
|
||||
} else {
|
||||
result = &mInput;
|
||||
result = mInput.get();
|
||||
}
|
||||
|
||||
// flag input stream as open
|
||||
|
|
@ -2384,7 +2388,7 @@ nsSocketTransport::OpenOutputStream(uint32_t flags, uint32_t segsize,
|
|||
SOCKET_LOG(("nsSocketTransport::OpenOutputStream [this=%p flags=%x]\n", this,
|
||||
flags));
|
||||
|
||||
NS_ENSURE_TRUE(!mOutput.IsReferenced(), NS_ERROR_UNEXPECTED);
|
||||
NS_ENSURE_TRUE(!mOutput->IsReferenced(), NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIAsyncOutputStream> pipeOut;
|
||||
|
|
@ -2403,14 +2407,14 @@ nsSocketTransport::OpenOutputStream(uint32_t flags, uint32_t segsize,
|
|||
!openBlocking, segsize, segcount);
|
||||
|
||||
// async copy from socket to pipe
|
||||
rv = NS_AsyncCopy(pipeIn, &mOutput, mSocketTransportService,
|
||||
rv = NS_AsyncCopy(pipeIn, mOutput.get(), mSocketTransportService,
|
||||
NS_ASYNCCOPY_VIA_READSEGMENTS, segsize, nullptr, nullptr,
|
||||
true, true, getter_AddRefs(outputCopyContext));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
result = pipeOut;
|
||||
} else {
|
||||
result = &mOutput;
|
||||
result = mOutput.get();
|
||||
}
|
||||
|
||||
// flag output stream as open
|
||||
|
|
@ -2437,8 +2441,8 @@ nsSocketTransport::Close(nsresult reason) {
|
|||
|
||||
mDoNotRetryToConnect = true;
|
||||
|
||||
mInput.CloseWithStatus(reason);
|
||||
mOutput.CloseWithStatus(reason);
|
||||
mInput->CloseWithStatus(reason);
|
||||
mOutput->CloseWithStatus(reason);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,67 +46,8 @@ namespace net {
|
|||
|
||||
nsresult ErrorAccordingToNSPR(PRErrorCode errorCode);
|
||||
|
||||
class nsSocketTransport;
|
||||
|
||||
class nsSocketInputStream : public nsIAsyncInputStream {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
NS_DECL_NSIASYNCINPUTSTREAM
|
||||
|
||||
explicit nsSocketInputStream(nsSocketTransport*);
|
||||
virtual ~nsSocketInputStream() = default;
|
||||
|
||||
bool IsReferenced() { return mReaderRefCnt > 0; }
|
||||
nsresult Condition() { return mCondition; }
|
||||
uint64_t ByteCount() { return mByteCount; }
|
||||
|
||||
// called by the socket transport on the socket thread...
|
||||
void OnSocketReady(nsresult condition);
|
||||
|
||||
private:
|
||||
nsSocketTransport* mTransport;
|
||||
ThreadSafeAutoRefCnt mReaderRefCnt{0};
|
||||
|
||||
// access to these is protected by mTransport->mLock
|
||||
nsresult mCondition{NS_OK};
|
||||
nsCOMPtr<nsIInputStreamCallback> mCallback;
|
||||
uint32_t mCallbackFlags{0};
|
||||
uint64_t mByteCount{0};
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsSocketOutputStream : public nsIAsyncOutputStream {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIOUTPUTSTREAM
|
||||
NS_DECL_NSIASYNCOUTPUTSTREAM
|
||||
|
||||
explicit nsSocketOutputStream(nsSocketTransport*);
|
||||
virtual ~nsSocketOutputStream() = default;
|
||||
|
||||
bool IsReferenced() { return mWriterRefCnt > 0; }
|
||||
nsresult Condition() { return mCondition; }
|
||||
uint64_t ByteCount() { return mByteCount; }
|
||||
|
||||
// called by the socket transport on the socket thread...
|
||||
void OnSocketReady(nsresult condition);
|
||||
|
||||
private:
|
||||
static nsresult WriteFromSegments(nsIInputStream*, void*, const char*,
|
||||
uint32_t offset, uint32_t count,
|
||||
uint32_t* countRead);
|
||||
|
||||
nsSocketTransport* mTransport;
|
||||
ThreadSafeAutoRefCnt mWriterRefCnt{0};
|
||||
|
||||
// access to these is protected by mTransport->mLock
|
||||
nsresult mCondition{NS_OK};
|
||||
nsCOMPtr<nsIOutputStreamCallback> mCallback;
|
||||
uint32_t mCallbackFlags{0};
|
||||
uint64_t mByteCount{0};
|
||||
};
|
||||
class nsSocketInputStream;
|
||||
class nsSocketOutputStream;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -165,8 +106,8 @@ class nsSocketTransport final : public nsASocketHandler,
|
|||
void OnSocketEvent(uint32_t type, nsresult status, nsISupports* param,
|
||||
std::function<void()>&& task);
|
||||
|
||||
uint64_t ByteCountReceived() override { return mInput.ByteCount(); }
|
||||
uint64_t ByteCountSent() override { return mOutput.ByteCount(); }
|
||||
uint64_t ByteCountReceived() override;
|
||||
uint64_t ByteCountSent() override;
|
||||
static void CloseSocket(PRFileDesc* aFd, bool aTelemetryEnabled);
|
||||
static void SendPRBlockingTelemetry(
|
||||
PRIntervalTime aStart, Telemetry::HistogramID aIDNormal,
|
||||
|
|
@ -377,10 +318,12 @@ class nsSocketTransport final : public nsASocketHandler,
|
|||
// the exception of some specific methods (XXX).
|
||||
|
||||
// protects members in this section.
|
||||
Mutex mLock MOZ_UNANNOTATED{"nsSocketTransport.mLock"};
|
||||
LockedPRFileDesc mFD;
|
||||
nsrefcnt mFDref{0}; // mFD is closed when mFDref goes to zero.
|
||||
bool mFDconnected{false}; // mFD is available to consumer when TRUE.
|
||||
Mutex mLock{"nsSocketTransport.mLock"};
|
||||
LockedPRFileDesc mFD MOZ_GUARDED_BY(mLock);
|
||||
// mFD is closed when mFDref goes to zero.
|
||||
nsrefcnt mFDref MOZ_GUARDED_BY(mLock){0};
|
||||
// mFD is available to consumer when TRUE.
|
||||
bool mFDconnected MOZ_GUARDED_BY(mLock){false};
|
||||
|
||||
// A delete protector reference to gSocketTransportService held for lifetime
|
||||
// of 'this'. Sometimes used interchangably with gSocketTransportService due
|
||||
|
|
@ -391,8 +334,8 @@ class nsSocketTransport final : public nsASocketHandler,
|
|||
nsCOMPtr<nsITransportEventSink> mEventSink;
|
||||
nsCOMPtr<nsITLSSocketControl> mTLSSocketControl;
|
||||
|
||||
nsSocketInputStream mInput;
|
||||
nsSocketOutputStream mOutput;
|
||||
UniquePtr<nsSocketInputStream> mInput;
|
||||
UniquePtr<nsSocketOutputStream> mOutput;
|
||||
|
||||
friend class nsSocketInputStream;
|
||||
friend class nsSocketOutputStream;
|
||||
|
|
@ -410,8 +353,8 @@ class nsSocketTransport final : public nsASocketHandler,
|
|||
//
|
||||
// mFD access methods: called with mLock held.
|
||||
//
|
||||
PRFileDesc* GetFD_Locked();
|
||||
void ReleaseFD_Locked(PRFileDesc* fd);
|
||||
PRFileDesc* GetFD_Locked() MOZ_REQUIRES(mLock);
|
||||
void ReleaseFD_Locked(PRFileDesc* fd) MOZ_REQUIRES(mLock);
|
||||
|
||||
//
|
||||
// stream state changes (called outside mLock):
|
||||
|
|
@ -479,6 +422,88 @@ class nsSocketTransport final : public nsASocketHandler,
|
|||
bool mRetryDnsIfPossible = false;
|
||||
};
|
||||
|
||||
class nsSocketInputStream : public nsIAsyncInputStream {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
NS_DECL_NSIASYNCINPUTSTREAM
|
||||
|
||||
explicit nsSocketInputStream(nsSocketTransport*);
|
||||
virtual ~nsSocketInputStream() = default;
|
||||
|
||||
// nsSocketTransport holds a ref to us
|
||||
bool IsReferenced() { return mReaderRefCnt > 0; }
|
||||
nsresult Condition() {
|
||||
MutexAutoLock lock(mTransport->mLock);
|
||||
return mCondition;
|
||||
}
|
||||
uint64_t ByteCount() {
|
||||
MutexAutoLock lock(mTransport->mLock);
|
||||
return mByteCount;
|
||||
}
|
||||
uint64_t ByteCount(MutexAutoLock&) MOZ_NO_THREAD_SAFETY_ANALYSIS {
|
||||
return mByteCount;
|
||||
}
|
||||
|
||||
// called by the socket transport on the socket thread...
|
||||
void OnSocketReady(nsresult condition);
|
||||
|
||||
private:
|
||||
nsSocketTransport* mTransport;
|
||||
ThreadSafeAutoRefCnt mReaderRefCnt{0};
|
||||
|
||||
// access to these should be protected by mTransport->mLock but we
|
||||
// can't order things to allow using MOZ_GUARDED_BY().
|
||||
nsresult mCondition MOZ_GUARDED_BY(mTransport->mLock){NS_OK};
|
||||
nsCOMPtr<nsIInputStreamCallback> mCallback MOZ_GUARDED_BY(mTransport->mLock);
|
||||
uint32_t mCallbackFlags MOZ_GUARDED_BY(mTransport->mLock){0};
|
||||
uint64_t mByteCount MOZ_GUARDED_BY(mTransport->mLock){0};
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsSocketOutputStream : public nsIAsyncOutputStream {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIOUTPUTSTREAM
|
||||
NS_DECL_NSIASYNCOUTPUTSTREAM
|
||||
|
||||
explicit nsSocketOutputStream(nsSocketTransport*);
|
||||
virtual ~nsSocketOutputStream() = default;
|
||||
|
||||
// nsSocketTransport holds a ref to us
|
||||
bool IsReferenced() { return mWriterRefCnt > 0; }
|
||||
nsresult Condition() {
|
||||
MutexAutoLock lock(mTransport->mLock);
|
||||
return mCondition;
|
||||
}
|
||||
uint64_t ByteCount() {
|
||||
MutexAutoLock lock(mTransport->mLock);
|
||||
return mByteCount;
|
||||
}
|
||||
uint64_t ByteCount(MutexAutoLock&) MOZ_NO_THREAD_SAFETY_ANALYSIS {
|
||||
return mByteCount;
|
||||
}
|
||||
|
||||
// called by the socket transport on the socket thread...
|
||||
void OnSocketReady(nsresult condition);
|
||||
|
||||
private:
|
||||
static nsresult WriteFromSegments(nsIInputStream*, void*, const char*,
|
||||
uint32_t offset, uint32_t count,
|
||||
uint32_t* countRead);
|
||||
|
||||
nsSocketTransport* mTransport;
|
||||
ThreadSafeAutoRefCnt mWriterRefCnt{0};
|
||||
|
||||
// access to these should be protected by mTransport->mLock but we
|
||||
// can't order things to allow using MOZ_GUARDED_BY().
|
||||
nsresult mCondition MOZ_GUARDED_BY(mTransport->mLock){NS_OK};
|
||||
nsCOMPtr<nsIOutputStreamCallback> mCallback MOZ_GUARDED_BY(mTransport->mLock);
|
||||
uint32_t mCallbackFlags MOZ_GUARDED_BY(mTransport->mLock){0};
|
||||
uint64_t mByteCount MOZ_GUARDED_BY(mTransport->mLock){0};
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue