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:
Randell Jesup 2023-12-19 15:42:03 +00:00
parent ab4aad7ce6
commit 7a1b759c87
2 changed files with 121 additions and 92 deletions

View file

@ -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;
}

View file

@ -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