зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1363372
- Wait until OVERLAPPED structure return a result before distroying a socket. r=mcmanus
This commit is contained in:
Родитель
77398bcd88
Коммит
a7386daa3f
|
@ -1278,8 +1278,7 @@ nsSocketTransport::BuildSocket(PRFileDesc *&fd, bool &proxyTransparent, bool &us
|
|||
SOCKET_LOG((" error pushing io layer [%u:%s rv=%" PRIx32 "]\n", i, mTypes[i],
|
||||
static_cast<uint32_t>(rv)));
|
||||
if (fd) {
|
||||
CloseSocket(fd,
|
||||
mSocketTransportService->IsTelemetryEnabledAndNotSleepPhase());
|
||||
CloseSocket(fd, mSocketTransportService);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1473,8 +1472,7 @@ nsSocketTransport::InitiateSocket()
|
|||
// inform socket transport about this newly created socket...
|
||||
rv = mSocketTransportService->AttachSocket(fd, this);
|
||||
if (NS_FAILED(rv)) {
|
||||
CloseSocket(fd,
|
||||
mSocketTransportService->IsTelemetryEnabledAndNotSleepPhase());
|
||||
CloseSocket(fd, mSocketTransportService);
|
||||
return rv;
|
||||
}
|
||||
mAttached = true;
|
||||
|
@ -1981,8 +1979,7 @@ public:
|
|||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
nsSocketTransport::CloseSocket(mFD,
|
||||
gSocketTransportService->IsTelemetryEnabledAndNotSleepPhase());
|
||||
nsSocketTransport::CloseSocket(mFD, gSocketTransportService);
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
|
@ -2017,8 +2014,7 @@ nsSocketTransport::ReleaseFD_Locked(PRFileDesc *fd)
|
|||
SOCKET_LOG(("Intentional leak"));
|
||||
} else if (OnSocketThread()) {
|
||||
SOCKET_LOG(("nsSocketTransport: calling PR_Close [this=%p]\n", this));
|
||||
CloseSocket(mFD,
|
||||
mSocketTransportService->IsTelemetryEnabledAndNotSleepPhase());
|
||||
CloseSocket(mFD, mSocketTransportService);
|
||||
} else {
|
||||
// Can't PR_Close() a socket off STS thread. Thunk it to STS to die
|
||||
STS_PRCloseOnSocketTransport(mFD);
|
||||
|
@ -3437,8 +3433,10 @@ nsSocketTransport::PRFileDescAutoLock::SetKeepaliveVals(bool aEnabled,
|
|||
}
|
||||
|
||||
void
|
||||
nsSocketTransport::CloseSocket(PRFileDesc *aFd, bool aTelemetryEnabled)
|
||||
nsSocketTransport::CloseSocket(PRFileDesc *aFd, nsSocketTransportService *aSTS)
|
||||
{
|
||||
bool telemetryEnabled = aSTS->IsTelemetryEnabledAndNotSleepPhase();
|
||||
|
||||
#if defined(XP_WIN)
|
||||
AttachShutdownLayer(aFd);
|
||||
#endif
|
||||
|
@ -3447,13 +3445,67 @@ nsSocketTransport::CloseSocket(PRFileDesc *aFd, bool aTelemetryEnabled)
|
|||
// nsIOService::LastOfflineStateChange time and
|
||||
// nsIOService::LastConectivityChange time to be atomic.
|
||||
PRIntervalTime closeStarted;
|
||||
if (aTelemetryEnabled) {
|
||||
if (telemetryEnabled) {
|
||||
closeStarted = PR_IntervalNow();
|
||||
}
|
||||
|
||||
PR_Close(aFd);
|
||||
#if defined(_WIN64) && defined(WIN95)
|
||||
bool canClose = false;
|
||||
if (aSTS->HasFileDesc2PlatformOverlappedIOHandleFunc()) {
|
||||
LPOVERLAPPED ol = nullptr;
|
||||
if (aSTS->CallFileDesc2PlatformOverlappedIOHandleFunc(aFd, (void**)&ol) == PR_SUCCESS) {
|
||||
SOCKET_LOG(("nsSocketTransport::CloseSocket - we have an overlapped "
|
||||
"structure=%p aFd=%p\n", ol, aFd));
|
||||
PROsfd osfd = PR_FileDesc2NativeHandle(aFd);
|
||||
if (telemetryEnabled) {
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::NETWORK_TCP_OVERLAPPED_IO_CANCELED_BEFORE_FINISHED, 1);
|
||||
}
|
||||
if (CancelIo((HANDLE) osfd) == TRUE) {
|
||||
SOCKET_LOG(("nsSocketTransport::CloseSocket - "
|
||||
"CancelIo succeeded\n"));
|
||||
} else {
|
||||
int err = WSAGetLastError();
|
||||
SOCKET_LOG(("nsSocketTransport::CloseSocket - "
|
||||
"CancelIo failed err=%x\n", err));
|
||||
}
|
||||
|
||||
if (aTelemetryEnabled) {
|
||||
DWORD rvSent;
|
||||
if (GetOverlappedResult((HANDLE) osfd, ol, &rvSent, FALSE) == TRUE) {
|
||||
SOCKET_LOG(("nsSocketTransport::CloseSocket - "
|
||||
"GetOverlappedResult done\n"));
|
||||
canClose = true;
|
||||
} else {
|
||||
int err = WSAGetLastError();
|
||||
SOCKET_LOG(("nsSocketTransport::CloseSocket - "
|
||||
"GetOverlappedResult err=%x\n", err));
|
||||
if (err != ERROR_IO_PENDING) {
|
||||
canClose = true;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
SOCKET_LOG(("nsSocketTransport::CloseSocket - no overlapped struct\n"));
|
||||
canClose = true;
|
||||
}
|
||||
} else {
|
||||
SOCKET_LOG(("nsSocketTransport::CloseSocket - there is no "
|
||||
"PR_FileDesc2PlatformOverlappedIOHandle function.\n"));
|
||||
canClose = true;
|
||||
}
|
||||
|
||||
if (canClose) {
|
||||
PR_Close(aFd);
|
||||
} else {
|
||||
if (telemetryEnabled) {
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::NETWORK_TCP_OVERLAPPED_RESULT_DELAYED, 1);
|
||||
}
|
||||
aSTS->AddOverlappedPendingSocket(aFd);
|
||||
}
|
||||
#else
|
||||
PR_Close(aFd);
|
||||
#endif
|
||||
|
||||
if (telemetryEnabled) {
|
||||
SendPRBlockingTelemetry(closeStarted,
|
||||
Telemetry::PRCLOSE_TCP_BLOCKING_TIME_NORMAL,
|
||||
Telemetry::PRCLOSE_TCP_BLOCKING_TIME_SHUTDOWN,
|
||||
|
|
|
@ -170,7 +170,7 @@ public:
|
|||
|
||||
uint64_t ByteCountReceived() override { return mInput.ByteCount(); }
|
||||
uint64_t ByteCountSent() override { return mOutput.ByteCount(); }
|
||||
static void CloseSocket(PRFileDesc *aFd, bool aTelemetryEnabled);
|
||||
static void CloseSocket(PRFileDesc *aFd, nsSocketTransportService *aSTS);
|
||||
static void SendPRBlockingTelemetry(PRIntervalTime aStart,
|
||||
Telemetry::HistogramID aIDNormal,
|
||||
Telemetry::HistogramID aIDShutdown,
|
||||
|
|
|
@ -98,6 +98,11 @@ nsSocketTransportService::nsSocketTransportService()
|
|||
#if defined(XP_WIN)
|
||||
, mPolling(false)
|
||||
#endif
|
||||
#if defined(_WIN64) && defined(WIN95)
|
||||
, mFileDesc2PlatformOverlappedIOHandleFuncChecked(false)
|
||||
, mNsprLibrary(nullptr)
|
||||
, mFileDesc2PlatformOverlappedIOHandleFunc(nullptr)
|
||||
#endif
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "wrong thread");
|
||||
|
||||
|
@ -122,6 +127,12 @@ nsSocketTransportService::~nsSocketTransportService()
|
|||
free(mIdleList);
|
||||
free(mPollList);
|
||||
gSocketTransportService = nullptr;
|
||||
#if defined(_WIN64) && defined(WIN95)
|
||||
if (mNsprLibrary) {
|
||||
BOOL rv = FreeLibrary(mNsprLibrary);
|
||||
SOCKET_LOG(("Free nspr library: %d\n", rv));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -944,6 +955,9 @@ nsSocketTransportService::Run()
|
|||
TimeStamp::NowLoRes());
|
||||
pollDuration += singlePollDuration;
|
||||
}
|
||||
#if defined(_WIN64) && defined(WIN95)
|
||||
CheckOverlappedPendingSocketsAreDone();
|
||||
#endif
|
||||
|
||||
mRawThread->HasPendingEvents(&pendingEvents);
|
||||
if (pendingEvents) {
|
||||
|
@ -1036,6 +1050,19 @@ nsSocketTransportService::Run()
|
|||
// socket detach handlers get processed.
|
||||
NS_ProcessPendingEvents(mRawThread);
|
||||
|
||||
#if defined(_WIN64) && defined(WIN95)
|
||||
// Final pass over panding overlapped ios. If they are not finish we will
|
||||
// leak FDs.
|
||||
CheckOverlappedPendingSocketsAreDone();
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
if (mOverlappedPendingSockets.Length()) {
|
||||
PRIntervalTime delay = PR_MillisecondsToInterval(5000);
|
||||
PR_Sleep(delay); // wait another 5s.
|
||||
CheckOverlappedPendingSocketsAreDone();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
gSocketThread = nullptr;
|
||||
|
||||
psm::StopSSLServerCertVerificationThreads();
|
||||
|
@ -1674,5 +1701,106 @@ nsSocketTransportService::EndPolling()
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64) && defined(WIN95)
|
||||
void
|
||||
nsSocketTransportService::AddOverlappedPendingSocket(PRFileDesc *aFd)
|
||||
{
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
MOZ_ASSERT(HasFileDesc2PlatformOverlappedIOHandleFunc());
|
||||
SOCKET_LOG(("STS AddOverlappedPendingSocket append aFd=%p\n", aFd));
|
||||
mOverlappedPendingSockets.AppendElement(aFd);
|
||||
}
|
||||
|
||||
void
|
||||
nsSocketTransportService::CheckOverlappedPendingSocketsAreDone()
|
||||
{
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
if (!HasFileDesc2PlatformOverlappedIOHandleFunc()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SOCKET_LOG(("STS CheckOverlappedPendingSocketsAreDone: "
|
||||
"pending sockets = %d\n", mOverlappedPendingSockets.Length()));
|
||||
for (int i = mOverlappedPendingSockets.Length() - 1; i >= 0; i--) {
|
||||
bool canClose = false;
|
||||
PRFileDesc *fd = mOverlappedPendingSockets[i];
|
||||
LPOVERLAPPED ol = nullptr;
|
||||
if (mFileDesc2PlatformOverlappedIOHandleFunc(fd, (void**)&ol) == PR_SUCCESS) {
|
||||
PROsfd osfd = PR_FileDesc2NativeHandle(fd);
|
||||
SOCKET_LOG(("STS CheckOverlappedPendingSocketsAreDone "
|
||||
"fd=%p osfd=%d\n", fd, (int)osfd));
|
||||
DWORD rvSent;
|
||||
if (GetOverlappedResult((HANDLE)osfd, ol, &rvSent, FALSE) == TRUE) {
|
||||
SOCKET_LOG(("STS CheckOverlappedPendingSocketsAreDone "
|
||||
"GetOverlappedResult succeeded\n"));
|
||||
canClose = true;
|
||||
} else {
|
||||
int err = WSAGetLastError();
|
||||
SOCKET_LOG(("STS CheckOverlappedPendingSocketsAreDone "
|
||||
"GetOverlappedResult failed error=%x \n", err));
|
||||
if (err != ERROR_IO_PENDING) {
|
||||
canClose = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
canClose = true;
|
||||
}
|
||||
|
||||
if (canClose) {
|
||||
SOCKET_LOG(("STS CheckOverlappedPendingSocketsAreDone "
|
||||
"remove fd=%p\n", fd));
|
||||
mOverlappedPendingSockets.RemoveElementAt(i);
|
||||
PR_Close(fd);
|
||||
}
|
||||
}
|
||||
SOCKET_LOG(("STS CheckOverlappedPendingSocketsAreDone: end a check, "
|
||||
"pending sockets = %d\n", mOverlappedPendingSockets.Length()));
|
||||
}
|
||||
|
||||
void
|
||||
nsSocketTransportService::CheckFileDesc2PlatformOverlappedIOHandleFunc()
|
||||
{
|
||||
if (mFileDesc2PlatformOverlappedIOHandleFuncChecked) {
|
||||
return;
|
||||
}
|
||||
|
||||
mFileDesc2PlatformOverlappedIOHandleFuncChecked = true;
|
||||
HMODULE library = LoadLibraryA("nss3.dll");
|
||||
MOZ_ASSERT(library);
|
||||
if (library) {
|
||||
mFileDesc2PlatformOverlappedIOHandleFunc =
|
||||
reinterpret_cast<FileDesc2PlatformOverlappedIOHandleFunc>(
|
||||
GetProcAddress(library, "PR_FileDesc2PlatformOverlappedIOHandle"));
|
||||
if (mFileDesc2PlatformOverlappedIOHandleFunc) {
|
||||
SOCKET_LOG(("FileDesc2PlatformOverlappedIOHandle function "
|
||||
"present"));
|
||||
mNsprLibrary = library;
|
||||
} else {
|
||||
BOOL rv = FreeLibrary(library);
|
||||
SOCKET_LOG(("No FileDesc2PlatformOverlappedIOHandle function: "
|
||||
"%d\n", rv));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsSocketTransportService::HasFileDesc2PlatformOverlappedIOHandleFunc()
|
||||
{
|
||||
CheckFileDesc2PlatformOverlappedIOHandleFunc();
|
||||
return mFileDesc2PlatformOverlappedIOHandleFunc;
|
||||
}
|
||||
|
||||
PRStatus
|
||||
nsSocketTransportService::CallFileDesc2PlatformOverlappedIOHandleFunc(PRFileDesc *fd, void **ol)
|
||||
{
|
||||
CheckFileDesc2PlatformOverlappedIOHandleFunc();
|
||||
if (mFileDesc2PlatformOverlappedIOHandleFunc) {
|
||||
return mFileDesc2PlatformOverlappedIOHandleFunc(fd, ol);
|
||||
}
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -24,6 +24,12 @@
|
|||
#include "mozilla/UniquePtr.h"
|
||||
#include "PollableEvent.h"
|
||||
|
||||
#if defined(_WIN64) && defined(WIN95)
|
||||
#include "WinDef.h"
|
||||
|
||||
typedef PRStatus (*FileDesc2PlatformOverlappedIOHandleFunc)(PRFileDesc *fd, void **ol);
|
||||
#endif
|
||||
|
||||
class nsASocketHandler;
|
||||
struct PRPollDesc;
|
||||
class nsIPrefBranch;
|
||||
|
@ -120,6 +126,12 @@ public:
|
|||
bool IsTelemetryEnabledAndNotSleepPhase() { return mTelemetryEnabledPref &&
|
||||
!mSleepPhase; }
|
||||
PRIntervalTime MaxTimeForPrClosePref() {return mMaxTimeForPrClosePref; }
|
||||
|
||||
#if defined(_WIN64) && defined(WIN95)
|
||||
void AddOverlappedPendingSocket(PRFileDesc *aFd);
|
||||
bool HasFileDesc2PlatformOverlappedIOHandleFunc();
|
||||
PRStatus CallFileDesc2PlatformOverlappedIOHandleFunc(PRFileDesc *fd, void **ol);
|
||||
#endif
|
||||
protected:
|
||||
|
||||
virtual ~nsSocketTransportService();
|
||||
|
@ -270,6 +282,21 @@ private:
|
|||
void StartPolling();
|
||||
void EndPolling();
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64) && defined(WIN95)
|
||||
// If TCP Fast Open is used on Windows an overlapped io is used. We need to
|
||||
// wait until this io is finished or canceled before detroying its
|
||||
// PRFileDesc.
|
||||
nsTArray<PRFileDesc *> mOverlappedPendingSockets;
|
||||
|
||||
bool mFileDesc2PlatformOverlappedIOHandleFuncChecked;
|
||||
HMODULE mNsprLibrary;
|
||||
FileDesc2PlatformOverlappedIOHandleFunc mFileDesc2PlatformOverlappedIOHandleFunc;
|
||||
|
||||
void CheckFileDesc2PlatformOverlappedIOHandleFunc();
|
||||
void CheckOverlappedPendingSocketsAreDone();
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
extern nsSocketTransportService *gSocketTransportService;
|
||||
|
|
|
@ -3587,7 +3587,12 @@ nsHttpConnectionMgr::GetOrCreateConnectionEntry(nsHttpConnectionInfo *specificCI
|
|||
if (!specificEnt) {
|
||||
RefPtr<nsHttpConnectionInfo> clone(specificCI->Clone());
|
||||
specificEnt = new nsConnectionEntry(clone);
|
||||
#if defined(_WIN64) && defined(WIN95)
|
||||
specificEnt->mUseFastOpen = gHttpHandler->UseFastOpen() &&
|
||||
gSocketTransportService->HasFileDesc2PlatformOverlappedIOHandleFunc();
|
||||
#else
|
||||
specificEnt->mUseFastOpen = gHttpHandler->UseFastOpen();
|
||||
#endif
|
||||
mCT.Put(clone->HashKey(), specificEnt);
|
||||
}
|
||||
return specificEnt;
|
||||
|
|
|
@ -813,6 +813,38 @@ formautofill.addresses:
|
|||
record_in_processes:
|
||||
- 'main'
|
||||
|
||||
# The following section is for probes for tcp protocol.
|
||||
network.tcp:
|
||||
overlapped_io_canceled_before_finished:
|
||||
bug_numbers:
|
||||
- 1363372
|
||||
description: >
|
||||
Count the number of sockets that use overlapped io and are canceled before
|
||||
the overlapped io finishes. (We only use overlapped io for connectEx when
|
||||
TCP Fast Open is used.)
|
||||
expires: "58"
|
||||
kind: uint
|
||||
notification_emails:
|
||||
- necko@mozilla.com
|
||||
- ddamjanovic@ozilla.com
|
||||
record_in_processes:
|
||||
- 'main'
|
||||
|
||||
overlapped_result_delayed:
|
||||
bug_numbers:
|
||||
- 1363372
|
||||
description: >
|
||||
Count the number of overlapped io that are canceled but cancelation
|
||||
have not completed immediately. (We only use overlapped io for
|
||||
connectEx when TCP Fast Open is used.)
|
||||
expires: "58"
|
||||
kind: uint
|
||||
notification_emails:
|
||||
- necko@mozilla.com
|
||||
- ddamjanovic@mozilla.com
|
||||
record_in_processes:
|
||||
- 'main'
|
||||
|
||||
# The following section is for probes testing the Telemetry system. They will not be
|
||||
# submitted in pings and are only used for testing.
|
||||
telemetry.test:
|
||||
|
|
Загрузка…
Ссылка в новой задаче