mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backed out changeset d5d0b5994149 (bug 1152046) for b2g debug hustdown hangs
CLOSED TREE
This commit is contained in:
parent
bc98239148
commit
2c66fb8d92
288
netwerk/base/ClosingService.cpp
Normal file
288
netwerk/base/ClosingService.cpp
Normal file
@ -0,0 +1,288 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ClosingService.h"
|
||||
#include "nsIOService.h"
|
||||
|
||||
class ClosingLayerSecret
|
||||
{
|
||||
public:
|
||||
explicit ClosingLayerSecret(mozilla::net::ClosingService *aClosingService)
|
||||
: mClosingService(aClosingService)
|
||||
{
|
||||
}
|
||||
|
||||
~ClosingLayerSecret()
|
||||
{
|
||||
mClosingService = nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<mozilla::net::ClosingService> mClosingService;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
static PRIOMethods sTcpUdpPRCloseLayerMethods;
|
||||
static PRIOMethods *sTcpUdpPRCloseLayerMethodsPtr = nullptr;
|
||||
static PRDescIdentity sTcpUdpPRCloseLayerId;
|
||||
|
||||
static PRStatus
|
||||
TcpUdpPRCloseLayerClose(PRFileDesc *aFd)
|
||||
{
|
||||
if (!aFd) {
|
||||
return PR_FAILURE;
|
||||
}
|
||||
|
||||
PRFileDesc* layer = PR_PopIOLayer(aFd, PR_TOP_IO_LAYER);
|
||||
MOZ_RELEASE_ASSERT(layer &&
|
||||
layer->identity == sTcpUdpPRCloseLayerId,
|
||||
"Closing Layer not on top of stack");
|
||||
|
||||
ClosingLayerSecret *closingLayerSecret =
|
||||
reinterpret_cast<ClosingLayerSecret *>(layer->secret);
|
||||
|
||||
PRStatus status = PR_SUCCESS;
|
||||
|
||||
if (aFd) {
|
||||
// If this is called during shutdown do not call ..method->close(fd) and
|
||||
// let it leak.
|
||||
if (gIOService->IsShutdown()) {
|
||||
// If the ClosingService layer is the first layer above PR_NSPR_IO_LAYER
|
||||
// we are not going to leak anything, but the PR_Close will not be called.
|
||||
PR_Free(aFd);
|
||||
} else if (closingLayerSecret->mClosingService) {
|
||||
closingLayerSecret->mClosingService->PostRequest(aFd);
|
||||
} else {
|
||||
// Socket is created before closing service has been started or there was
|
||||
// a problem with starting it.
|
||||
PR_Close(aFd);
|
||||
}
|
||||
}
|
||||
|
||||
layer->secret = nullptr;
|
||||
layer->dtor(layer);
|
||||
delete closingLayerSecret;
|
||||
return status;
|
||||
}
|
||||
|
||||
ClosingService* ClosingService::sInstance = nullptr;
|
||||
|
||||
ClosingService::ClosingService()
|
||||
: mShutdown(false)
|
||||
, mMonitor("ClosingService.mMonitor")
|
||||
{
|
||||
MOZ_ASSERT(!sInstance,
|
||||
"multiple ClosingService instances!");
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
ClosingService::Start()
|
||||
{
|
||||
if (!sTcpUdpPRCloseLayerMethodsPtr) {
|
||||
sTcpUdpPRCloseLayerId = PR_GetUniqueIdentity("TCP and UDP PRClose layer");
|
||||
PR_ASSERT(PR_INVALID_IO_LAYER != sTcpUdpPRCloseLayerId);
|
||||
|
||||
sTcpUdpPRCloseLayerMethods = *PR_GetDefaultIOMethods();
|
||||
sTcpUdpPRCloseLayerMethods.close = TcpUdpPRCloseLayerClose;
|
||||
sTcpUdpPRCloseLayerMethodsPtr = &sTcpUdpPRCloseLayerMethods;
|
||||
}
|
||||
|
||||
if (!sInstance) {
|
||||
ClosingService* service = new ClosingService();
|
||||
if (NS_SUCCEEDED(service->StartInternal())) {
|
||||
NS_ADDREF(service);
|
||||
sInstance = service;
|
||||
} else {
|
||||
delete service;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
ClosingService::StartInternal()
|
||||
{
|
||||
mThread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, this,
|
||||
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
|
||||
PR_JOINABLE_THREAD, 4 * 4096);
|
||||
if (!mThread) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
ClosingService::AttachIOLayer(PRFileDesc *aFd)
|
||||
{
|
||||
if (!sTcpUdpPRCloseLayerMethodsPtr) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRFileDesc * layer;
|
||||
PRStatus status;
|
||||
|
||||
layer = PR_CreateIOLayerStub(sTcpUdpPRCloseLayerId,
|
||||
sTcpUdpPRCloseLayerMethodsPtr);
|
||||
|
||||
if (!layer) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ClosingLayerSecret *secret = new ClosingLayerSecret(sInstance);
|
||||
layer->secret = reinterpret_cast<PRFilePrivate *>(secret);
|
||||
|
||||
status = PR_PushIOLayer(aFd, PR_NSPR_IO_LAYER, layer);
|
||||
|
||||
if (status == PR_FAILURE) {
|
||||
delete secret;
|
||||
PR_DELETE(layer);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ClosingService::PostRequest(PRFileDesc *aFd)
|
||||
{
|
||||
mozilla::MonitorAutoLock mon(mMonitor);
|
||||
|
||||
// Check if shutdown is called.
|
||||
if (mShutdown) {
|
||||
// Let the socket leak. We are in shutdown and some PRClose can take a long
|
||||
// time. To prevent shutdown crash (bug 1152046) do not accept sockets any
|
||||
// more.
|
||||
// If the ClosingService layer is the first layer above PR_NSPR_IO_LAYER
|
||||
// we are not going to leak anything, but PR_Close will not be called.
|
||||
PR_Free(aFd);
|
||||
return;
|
||||
}
|
||||
|
||||
mQueue.AppendElement(aFd);
|
||||
if (mQueue.Length() == 1) {
|
||||
mon.Notify();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
ClosingService::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (sInstance) {
|
||||
sInstance->ShutdownInternal();
|
||||
NS_RELEASE(sInstance);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClosingService::ShutdownInternal()
|
||||
{
|
||||
{
|
||||
mozilla::MonitorAutoLock mon(mMonitor);
|
||||
mShutdown = true;
|
||||
// If it is waiting on the empty queue, wake it up.
|
||||
if (mQueue.Length() == 0) {
|
||||
mon.Notify();
|
||||
}
|
||||
}
|
||||
|
||||
if (mThread) {
|
||||
PR_JoinThread(mThread);
|
||||
mThread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClosingService::ThreadFunc()
|
||||
{
|
||||
for (;;) {
|
||||
PRFileDesc *fd;
|
||||
{
|
||||
mozilla::MonitorAutoLock mon(mMonitor);
|
||||
while (!mShutdown && (mQueue.Length() == 0)) {
|
||||
mon.Wait();
|
||||
}
|
||||
|
||||
if (mShutdown) {
|
||||
// If we are in shutdown leak the rest of the sockets.
|
||||
for (uint32_t i = 0; i < mQueue.Length(); i++) {
|
||||
fd = mQueue[i];
|
||||
// If the ClosingService layer is the first layer above
|
||||
// PR_NSPR_IO_LAYER we are not going to leak anything, but PR_Close
|
||||
// will not be called.
|
||||
PR_Free(fd);
|
||||
}
|
||||
mQueue.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
fd = mQueue[0];
|
||||
mQueue.RemoveElementAt(0);
|
||||
}
|
||||
// Leave lock before closing socket. It can block for a long time and in
|
||||
// case we accidentally attach this layer twice this would cause deadlock.
|
||||
|
||||
bool tcp = (PR_GetDescType(PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER)) ==
|
||||
PR_DESC_SOCKET_TCP);
|
||||
|
||||
PRIntervalTime closeStarted = PR_IntervalNow();
|
||||
fd->methods->close(fd);
|
||||
|
||||
// Post telemetry.
|
||||
if (tcp) {
|
||||
SendPRCloseTelemetry(closeStarted,
|
||||
Telemetry::PRCLOSE_TCP_BLOCKING_TIME_NORMAL,
|
||||
Telemetry::PRCLOSE_TCP_BLOCKING_TIME_SHUTDOWN,
|
||||
Telemetry::PRCLOSE_TCP_BLOCKING_TIME_CONNECTIVITY_CHANGE,
|
||||
Telemetry::PRCLOSE_TCP_BLOCKING_TIME_LINK_CHANGE,
|
||||
Telemetry::PRCLOSE_TCP_BLOCKING_TIME_OFFLINE);
|
||||
} else {
|
||||
SendPRCloseTelemetry(closeStarted,
|
||||
Telemetry::PRCLOSE_UDP_BLOCKING_TIME_NORMAL,
|
||||
Telemetry::PRCLOSE_UDP_BLOCKING_TIME_SHUTDOWN,
|
||||
Telemetry::PRCLOSE_UDP_BLOCKING_TIME_CONNECTIVITY_CHANGE,
|
||||
Telemetry::PRCLOSE_UDP_BLOCKING_TIME_LINK_CHANGE,
|
||||
Telemetry::PRCLOSE_UDP_BLOCKING_TIME_OFFLINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClosingService::SendPRCloseTelemetry(PRIntervalTime aStart,
|
||||
mozilla::Telemetry::ID aIDNormal,
|
||||
mozilla::Telemetry::ID aIDShutdown,
|
||||
mozilla::Telemetry::ID aIDConnectivityChange,
|
||||
mozilla::Telemetry::ID aIDLinkChange,
|
||||
mozilla::Telemetry::ID aIDOffline)
|
||||
{
|
||||
PRIntervalTime now = PR_IntervalNow();
|
||||
if (gIOService->IsShutdown()) {
|
||||
Telemetry::Accumulate(aIDShutdown,
|
||||
PR_IntervalToMilliseconds(now - aStart));
|
||||
|
||||
} else if (PR_IntervalToSeconds(now - gIOService->LastConnectivityChange())
|
||||
< 60) {
|
||||
Telemetry::Accumulate(aIDConnectivityChange,
|
||||
PR_IntervalToMilliseconds(now - aStart));
|
||||
} else if (PR_IntervalToSeconds(now - gIOService->LastNetworkLinkChange())
|
||||
< 60) {
|
||||
Telemetry::Accumulate(aIDLinkChange,
|
||||
PR_IntervalToMilliseconds(now - aStart));
|
||||
|
||||
} else if (PR_IntervalToSeconds(now - gIOService->LastOfflineStateChange())
|
||||
< 60) {
|
||||
Telemetry::Accumulate(aIDOffline,
|
||||
PR_IntervalToMilliseconds(now - aStart));
|
||||
} else {
|
||||
Telemetry::Accumulate(aIDNormal,
|
||||
PR_IntervalToMilliseconds(now - aStart));
|
||||
}
|
||||
}
|
||||
|
||||
} //namwspacw mozilla
|
||||
} //namespace net
|
71
netwerk/base/ClosingService.h
Normal file
71
netwerk/base/ClosingService.h
Normal file
@ -0,0 +1,71 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef ClosingService_h__
|
||||
#define ClosingService_h__
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "nspr.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ClosingService
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// A helper class carrying call to PR_Close on FD to a separate thread -
|
||||
// closingThread. This may be a workaround for shutdown blocks that are caused
|
||||
// by serial calls to close on UDP and TCP sockets.
|
||||
// This service is started by nsIOService and also the class adds itself as an
|
||||
// observer to "xpcom-shutdown-threads" notification where we join the thread
|
||||
// and remove reference.
|
||||
// During worktime of the thread the class is also self-referenced,
|
||||
// since observer service might throw the reference away sooner than the thread
|
||||
// is actually done.
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class ClosingService final
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ClosingService)
|
||||
|
||||
ClosingService();
|
||||
|
||||
// Attaching this layer on tcp or udp sockets PRClose will be send to the
|
||||
// closingThread.
|
||||
static nsresult AttachIOLayer(PRFileDesc *aFd);
|
||||
static void Start();
|
||||
static void Shutdown();
|
||||
void PostRequest(PRFileDesc *aFd);
|
||||
|
||||
private:
|
||||
~ClosingService() {}
|
||||
nsresult StartInternal();
|
||||
void ShutdownInternal();
|
||||
void ThreadFunc();
|
||||
static void ThreadFunc(void *aClosure)
|
||||
{ static_cast<ClosingService*>(aClosure)->ThreadFunc(); }
|
||||
|
||||
void SendPRCloseTelemetry(PRIntervalTime aStart,
|
||||
mozilla::Telemetry::ID aIDNormal,
|
||||
mozilla::Telemetry::ID aIDShutdown,
|
||||
mozilla::Telemetry::ID aIDConnectivityChange,
|
||||
mozilla::Telemetry::ID aIDLinkChange,
|
||||
mozilla::Telemetry::ID aIDOffline);
|
||||
|
||||
static ClosingService* sInstance;
|
||||
Atomic<bool> mShutdown;
|
||||
nsTArray<PRFileDesc *> mQueue;
|
||||
mozilla::Monitor mMonitor;
|
||||
PRThread *mThread;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // ClosingService_h_
|
@ -189,6 +189,7 @@ UNIFIED_SOURCES += [
|
||||
'CaptivePortalService.cpp',
|
||||
'ChannelDiverterChild.cpp',
|
||||
'ChannelDiverterParent.cpp',
|
||||
'ClosingService.cpp',
|
||||
'Dashboard.cpp',
|
||||
'EventTokenBucket.cpp',
|
||||
'LoadContextInfo.cpp',
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
||||
#include "nsIOService.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsIFileProtocolHandler.h"
|
||||
#include "nscore.h"
|
||||
@ -20,6 +21,7 @@
|
||||
#include "nsIProxiedProtocolHandler.h"
|
||||
#include "nsIProxyInfo.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsSecCheckWrapChannel.h"
|
||||
@ -42,6 +44,7 @@
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/net/NeckoCommon.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/net/DNS.h"
|
||||
#include "CaptivePortalService.h"
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "nsProxyInfo.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "ClosingService.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "plstr.h"
|
||||
@ -1194,7 +1195,7 @@ nsSocketTransport::BuildSocket(PRFileDesc *&fd, bool &proxyTransparent, bool &us
|
||||
if (NS_FAILED(rv)) {
|
||||
SOCKET_LOG((" error pushing io layer [%u:%s rv=%x]\n", i, mTypes[i], rv));
|
||||
if (fd) {
|
||||
CloseSocket(fd, mSocketTransportService->IsTelemetryEnabled());
|
||||
PR_Close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1322,6 +1323,9 @@ nsSocketTransport::InitiateSocket()
|
||||
// Attach network activity monitor
|
||||
mozilla::net::NetworkActivityMonitor::AttachIOLayer(fd);
|
||||
|
||||
// Attach closing service.
|
||||
ClosingService::AttachIOLayer(fd);
|
||||
|
||||
PRStatus status;
|
||||
|
||||
// Make the socket non-blocking...
|
||||
@ -1358,7 +1362,7 @@ nsSocketTransport::InitiateSocket()
|
||||
// inform socket transport about this newly created socket...
|
||||
rv = mSocketTransportService->AttachSocket(fd, this);
|
||||
if (NS_FAILED(rv)) {
|
||||
CloseSocket(fd, mSocketTransportService->IsTelemetryEnabled());
|
||||
PR_Close(fd);
|
||||
return rv;
|
||||
}
|
||||
mAttached = true;
|
||||
@ -1698,8 +1702,7 @@ public:
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsSocketTransport::CloseSocket(mFD,
|
||||
gSocketTransportService->IsTelemetryEnabled());
|
||||
PR_Close(mFD);
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
@ -1731,7 +1734,7 @@ nsSocketTransport::ReleaseFD_Locked(PRFileDesc *fd)
|
||||
if (--mFDref == 0) {
|
||||
if (PR_GetCurrentThread() == gSocketThread) {
|
||||
SOCKET_LOG(("nsSocketTransport: calling PR_Close [this=%p]\n", this));
|
||||
CloseSocket(mFD, mSocketTransportService->IsTelemetryEnabled());
|
||||
PR_Close(mFD);
|
||||
} else {
|
||||
// Can't PR_Close() a socket off STS thread. Thunk it to STS to die
|
||||
STS_PRCloseOnSocketTransport(mFD);
|
||||
@ -3039,29 +3042,6 @@ nsSocketTransport::PRFileDescAutoLock::SetKeepaliveVals(bool aEnabled,
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
nsSocketTransport::CloseSocket(PRFileDesc *aFd, bool aTelemetryEnabled) {
|
||||
|
||||
// We use PRIntervalTime here because we need
|
||||
// nsIOService::LastOfflineStateChange time and
|
||||
// nsIOService::LastConectivityChange time to be atomic.
|
||||
PRIntervalTime closeStarted;
|
||||
if (aTelemetryEnabled) {
|
||||
closeStarted = PR_IntervalNow();
|
||||
}
|
||||
|
||||
PR_Close(aFd);
|
||||
|
||||
if (aTelemetryEnabled) {
|
||||
SendPRBlockingTelemetry(closeStarted,
|
||||
Telemetry::PRCLOSE_BLOCKING_TIME_NORMAL,
|
||||
Telemetry::PRCLOSE_BLOCKING_TIME_SHUTDOWN,
|
||||
Telemetry::PRCLOSE_BLOCKING_TIME_CONNECTIVITY_CHANGE,
|
||||
Telemetry::PRCLOSE_BLOCKING_TIME_LINK_CHANGE,
|
||||
Telemetry::PRCLOSE_BLOCKING_TIME_OFFLINE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsSocketTransport::SendPRBlockingTelemetry(PRIntervalTime aStart,
|
||||
Telemetry::ID aIDNormal,
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "nsSocketTransport2.h"
|
||||
#include "NetworkActivityMonitor.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "ClosingService.h"
|
||||
#endif // !defined(MOZILLA_XPCOMRT_API)
|
||||
#include "nsASocketHandler.h"
|
||||
#include "nsError.h"
|
||||
@ -551,6 +552,13 @@ nsSocketTransportService::Init()
|
||||
obsSvc->AddObserver(this, "last-pb-context-exited", false);
|
||||
}
|
||||
|
||||
#if !defined(MOZILLA_XPCOMRT_API)
|
||||
// Start the closing service. Actual PR_Close() will be carried out on
|
||||
// a separate "closing" thread. Start the closing servicee here since this
|
||||
// point is executed only once per session.
|
||||
ClosingService::Start();
|
||||
#endif //!defined(MOZILLA_XPCOMRT_API)
|
||||
|
||||
mInitialized = true;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -601,6 +609,7 @@ nsSocketTransportService::Shutdown()
|
||||
|
||||
#if !defined(MOZILLA_XPCOMRT_API)
|
||||
mozilla::net::NetworkActivityMonitor::Shutdown();
|
||||
ClosingService::Shutdown();
|
||||
#endif // !defined(MOZILLA_XPCOMRT_API)
|
||||
|
||||
mInitialized = false;
|
||||
@ -1438,7 +1447,8 @@ nsSocketTransportService::AnalyzeConnection(nsTArray<SocketInfo> *data,
|
||||
if (context->mHandler->mIsPrivate)
|
||||
return;
|
||||
PRFileDesc *aFD = context->mFD;
|
||||
bool tcp = (PR_GetDescType(aFD) == PR_DESC_SOCKET_TCP);
|
||||
bool tcp = (PR_GetDescType(PR_GetIdentitiesLayer(aFD, PR_NSPR_IO_LAYER)) ==
|
||||
PR_DESC_SOCKET_TCP);
|
||||
|
||||
PRNetAddr peer_addr;
|
||||
PR_GetPeerName(aFD, &peer_addr);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "nsIDNSRecord.h"
|
||||
#include "nsIDNSService.h"
|
||||
#include "nsICancelable.h"
|
||||
#include "ClosingService.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "NetStatistics.h"
|
||||
@ -36,7 +37,6 @@
|
||||
using namespace mozilla::net;
|
||||
using namespace mozilla;
|
||||
|
||||
static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
|
||||
static const uint32_t UDP_PACKET_CHUNK_SIZE = 1400;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -91,191 +91,6 @@ private:
|
||||
PRSocketOptionData mOpt;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsUDPSocketCloseThread
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// A helper class carrying call to PR_Close on nsUDPSocket's FD to a separate
|
||||
// thread. This may be a workaround for shutdown blocks that are caused by
|
||||
// serial calls to close on UDP sockets.
|
||||
// It starts an NSPR thread for each socket and also adds itself as an observer
|
||||
// to "xpcom-shutdown-threads" notification where we join the thread (if not
|
||||
// already done). During worktime of the thread the class is also
|
||||
// self-referenced, since observer service might throw the reference away
|
||||
// sooner than the thread is actually done.
|
||||
class nsUDPSocketCloseThread : public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
static bool Close(PRFileDesc *aFd);
|
||||
|
||||
private:
|
||||
explicit nsUDPSocketCloseThread(PRFileDesc *aFd);
|
||||
virtual ~nsUDPSocketCloseThread() { }
|
||||
|
||||
bool Begin();
|
||||
void ThreadFunc();
|
||||
void AddObserver();
|
||||
void JoinAndRemove();
|
||||
|
||||
static void ThreadFunc(void *aClosure)
|
||||
{ static_cast<nsUDPSocketCloseThread*>(aClosure)->ThreadFunc(); }
|
||||
|
||||
// Socket to close.
|
||||
PRFileDesc *mFd;
|
||||
PRThread *mThread;
|
||||
|
||||
// Self reference, added before we create the thread, dropped
|
||||
// after the thread is done (from the thread). No races, since
|
||||
// mSelf is assigned bofore the thread func is executed and
|
||||
// released only on the thread func.
|
||||
nsRefPtr<nsUDPSocketCloseThread> mSelf;
|
||||
|
||||
// Telemetry probes.
|
||||
TimeStamp mBeforeClose;
|
||||
TimeStamp mAfterClose;
|
||||
|
||||
// Active threads (roughly) counter, modified only on the main thread
|
||||
// and used only for telemetry reports.
|
||||
static uint32_t sActiveThreadsCount;
|
||||
|
||||
// Switches to true on "xpcom-shutdown-threads" notification and since
|
||||
// then it makes the code fallback to a direct call to PR_Close().
|
||||
static bool sPastShutdown;
|
||||
};
|
||||
|
||||
uint32_t nsUDPSocketCloseThread::sActiveThreadsCount = 0;
|
||||
bool nsUDPSocketCloseThread::sPastShutdown = false;
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsUDPSocketCloseThread, nsIObserver);
|
||||
|
||||
bool
|
||||
nsUDPSocketCloseThread::Close(PRFileDesc *aFd)
|
||||
{
|
||||
if (sPastShutdown) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<nsUDPSocketCloseThread> t = new nsUDPSocketCloseThread(aFd);
|
||||
return t->Begin();
|
||||
}
|
||||
|
||||
nsUDPSocketCloseThread::nsUDPSocketCloseThread(PRFileDesc *aFd)
|
||||
: mFd(aFd)
|
||||
, mThread(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
nsUDPSocketCloseThread::Begin()
|
||||
{
|
||||
// Observer service must be worked with on the main thread only.
|
||||
// This method is called usually on the socket thread.
|
||||
// Register us before the thread starts. It may happen the thread is
|
||||
// done and posts removal event sooner then we would post this event
|
||||
// after the thread creation.
|
||||
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(
|
||||
this, &nsUDPSocketCloseThread::AddObserver);
|
||||
if (event) {
|
||||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
|
||||
// Keep us self-referenced during lifetime of the thread.
|
||||
// Released after the thread is done.
|
||||
mSelf = this;
|
||||
mThread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, this,
|
||||
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
|
||||
PR_JOINABLE_THREAD, 4 * 4096);
|
||||
if (!mThread) {
|
||||
// This doesn't join since there is no thread, just removes
|
||||
// this class as an observer.
|
||||
JoinAndRemove();
|
||||
mSelf = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsUDPSocketCloseThread::AddObserver()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
++sActiveThreadsCount;
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(this, "xpcom-shutdown-threads", false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsUDPSocketCloseThread::JoinAndRemove()
|
||||
{
|
||||
// Posted from the particular (this) UDP close socket when it's done
|
||||
// or from "xpcom-shutdown-threads" notification.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mThread) {
|
||||
PR_JoinThread(mThread);
|
||||
mThread = nullptr;
|
||||
|
||||
Telemetry::Accumulate(Telemetry::UDP_SOCKET_PARALLEL_CLOSE_COUNT, sActiveThreadsCount);
|
||||
Telemetry::AccumulateTimeDelta(Telemetry::UDP_SOCKET_CLOSE_TIME, mBeforeClose, mAfterClose);
|
||||
|
||||
MOZ_ASSERT(sActiveThreadsCount > 0);
|
||||
--sActiveThreadsCount;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->RemoveObserver(this, "xpcom-shutdown-threads");
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUDPSocketCloseThread::Observe(nsISupports *aSubject,
|
||||
const char *aTopic,
|
||||
const char16_t *aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!strcmp(aTopic, "xpcom-shutdown-threads")) {
|
||||
sPastShutdown = true;
|
||||
JoinAndRemove();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_CRASH("Unexpected observer topic");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsUDPSocketCloseThread::ThreadFunc()
|
||||
{
|
||||
PR_SetCurrentThreadName("UDP socket close");
|
||||
|
||||
mBeforeClose = TimeStamp::Now();
|
||||
|
||||
PR_Close(mFd);
|
||||
mFd = nullptr;
|
||||
|
||||
mAfterClose = TimeStamp::Now();
|
||||
|
||||
// Join and remove the observer on the main thread.
|
||||
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(
|
||||
this, &nsUDPSocketCloseThread::JoinAndRemove);
|
||||
if (event) {
|
||||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
|
||||
// Thread's done, release the self-reference.
|
||||
mSelf = nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsUDPOutputStream impl
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -457,9 +272,7 @@ nsUDPSocket::nsUDPSocket()
|
||||
nsUDPSocket::~nsUDPSocket()
|
||||
{
|
||||
if (mFD) {
|
||||
if (!nsUDPSocketCloseThread::Close(mFD)) {
|
||||
PR_Close(mFD);
|
||||
}
|
||||
PR_Close(mFD);
|
||||
mFD = nullptr;
|
||||
}
|
||||
|
||||
@ -701,9 +514,7 @@ nsUDPSocket::OnSocketDetached(PRFileDesc *fd)
|
||||
if (mFD)
|
||||
{
|
||||
NS_ASSERTION(mFD == fd, "wrong file descriptor");
|
||||
if (!nsUDPSocketCloseThread::Close(mFD)) {
|
||||
PR_Close(mFD);
|
||||
}
|
||||
PR_Close(mFD);
|
||||
mFD = nullptr;
|
||||
}
|
||||
SaveNetworkStats(true);
|
||||
@ -844,6 +655,7 @@ nsUDPSocket::InitWithAddress(const NetAddr *aAddr, nsIPrincipal *aPrincipal,
|
||||
|
||||
// create proxy via NetworkActivityMonitor
|
||||
NetworkActivityMonitor::AttachIOLayer(mFD);
|
||||
ClosingService::AttachIOLayer(mFD);
|
||||
|
||||
// wait until AsyncListen is called before polling the socket for
|
||||
// client connections.
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "prnetdb.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "prerr.h"
|
||||
#include "prerror.h"
|
||||
#include "NetworkActivityMonitor.h"
|
||||
#include "ClosingService.h"
|
||||
|
||||
using namespace mozilla::net;
|
||||
|
||||
@ -144,6 +145,9 @@ void ARTPConnection::MakePortPair(
|
||||
NetworkActivityMonitor::AttachIOLayer(*rtpSocket);
|
||||
NetworkActivityMonitor::AttachIOLayer(*rtcpSocket);
|
||||
|
||||
ClosingService::AttachIOLayer(*rtpSocket);
|
||||
ClosingService::AttachIOLayer(*rtcpSocket);
|
||||
|
||||
// Reduce the chance of using duplicate port numbers.
|
||||
srand(time(NULL));
|
||||
// rand() * 1000 may overflow int type, use long long.
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "prnetdb.h"
|
||||
#include "prerr.h"
|
||||
#include "NetworkActivityMonitor.h"
|
||||
#include "ClosingService.h"
|
||||
|
||||
using namespace mozilla::net;
|
||||
|
||||
@ -109,6 +110,7 @@ void ARTPSession::MakeUDPSocket(PRFileDesc **s, unsigned port) {
|
||||
}
|
||||
|
||||
NetworkActivityMonitor::AttachIOLayer(*s);
|
||||
ClosingService::AttachIOLayer(*s);
|
||||
|
||||
PRNetAddr addr;
|
||||
addr.inet.family = PR_AF_INET;
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <media/stagefright/MetaData.h>
|
||||
#include <utils/ByteOrder.h>
|
||||
|
||||
#include "ClosingService.h"
|
||||
#include "NetworkActivityMonitor.h"
|
||||
|
||||
using namespace mozilla::net;
|
||||
@ -64,6 +65,7 @@ ARTPWriter::ARTPWriter(int fd)
|
||||
}
|
||||
|
||||
NetworkActivityMonitor::AttachIOLayer(mSocket);
|
||||
ClosingService::AttachIOLayer(mSocket);
|
||||
|
||||
mRTPAddr.inet.family = PR_AF_INET;
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "ClosingService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsICryptoHash.h"
|
||||
|
||||
@ -283,6 +284,7 @@ void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
|
||||
}
|
||||
|
||||
NetworkActivityMonitor::AttachIOLayer(mSocket);
|
||||
ClosingService::AttachIOLayer(mSocket);
|
||||
|
||||
MakeSocketBlocking(mSocket, false);
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "prnetdb.h"
|
||||
#include "prerr.h"
|
||||
#include "NetworkActivityMonitor.h"
|
||||
#include "ClosingService.h"
|
||||
|
||||
using namespace mozilla::net;
|
||||
|
||||
@ -44,6 +45,7 @@ UDPPusher::UDPPusher(const char *filename, unsigned port)
|
||||
}
|
||||
|
||||
NetworkActivityMonitor::AttachIOLayer(mSocket);
|
||||
ClosingService::AttachIOLayer(mSocket);
|
||||
|
||||
PRNetAddr addr;
|
||||
addr.inet.family = PR_AF_INET;
|
||||
|
@ -2567,35 +2567,70 @@
|
||||
"n_buckets": 1000,
|
||||
"description": "Time spent blocked in PR_ConnectContinue when the offline state has changed in the last 60s (ms)."
|
||||
},
|
||||
"PRCLOSE_BLOCKING_TIME_NORMAL": {
|
||||
"PRCLOSE_TCP_BLOCKING_TIME_NORMAL": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "60000",
|
||||
"n_buckets": 1000,
|
||||
"description": "Time spent blocked in PR_Close when we are not shutting down and there has been niether a network nor an offline state change in the last 60s (ms)."
|
||||
},
|
||||
"PRCLOSE_BLOCKING_TIME_SHUTDOWN": {
|
||||
"PRCLOSE_TCP_BLOCKING_TIME_SHUTDOWN": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "60000",
|
||||
"n_buckets": 1000,
|
||||
"description": "Time spent blocked in PR_Close during a shutdown (ms)."
|
||||
},
|
||||
"PRCLOSE_BLOCKING_TIME_CONNECTIVITY_CHANGE": {
|
||||
"PRCLOSE_TCP_BLOCKING_TIME_CONNECTIVITY_CHANGE": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "60000",
|
||||
"n_buckets": 1000,
|
||||
"description": "Time spent blocked in PR_Close when there has been the connectivity change in the last 60s (ms)."
|
||||
},
|
||||
"PRCLOSE_BLOCKING_TIME_LINK_CHANGE": {
|
||||
"PRCLOSE_TCP_BLOCKING_TIME_LINK_CHANGE": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "60000",
|
||||
"n_buckets": 1000,
|
||||
"description": "Time spent blocked in PR_Close when there has been a link change in the last 60s (ms)."
|
||||
},
|
||||
"PRCLOSE_BLOCKING_TIME_OFFLINE": {
|
||||
"PRCLOSE_TCP_BLOCKING_TIME_OFFLINE": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "60000",
|
||||
"n_buckets": 1000,
|
||||
"description": "Time spent blocked in PR_Close when the offline state has changed in the last 60s (ms)."
|
||||
},
|
||||
"PRCLOSE_UDP_BLOCKING_TIME_NORMAL": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "60000",
|
||||
"n_buckets": 1000,
|
||||
"description": "Time spent blocked in PR_Close when we are not shutting down and there has been niether a network nor an offline state change in the last 60s (ms)."
|
||||
},
|
||||
"PRCLOSE_UDP_BLOCKING_TIME_SHUTDOWN": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "60000",
|
||||
"n_buckets": 1000,
|
||||
"description": "Time spent blocked in PR_Close during a shutdown (ms)."
|
||||
},
|
||||
"PRCLOSE_UDP_BLOCKING_TIME_CONNECTIVITY_CHANGE": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "60000",
|
||||
"n_buckets": 1000,
|
||||
"description": "Time spent blocked in PR_Close when there has been the connectivity change in the last 60s (ms)."
|
||||
},
|
||||
"PRCLOSE_UDP_BLOCKING_TIME_LINK_CHANGE": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "60000",
|
||||
"n_buckets": 1000,
|
||||
"description": "Time spent blocked in PR_Close when there has been a link change in the last 60s (ms)."
|
||||
},
|
||||
"PRCLOSE_UDP_BLOCKING_TIME_OFFLINE": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "60000",
|
||||
@ -8687,20 +8722,6 @@
|
||||
"kind": "count",
|
||||
"description": "Count plugin hang notices in e10s"
|
||||
},
|
||||
"UDP_SOCKET_PARALLEL_CLOSE_COUNT": {
|
||||
"expires_in_version": "41",
|
||||
"kind": "linear",
|
||||
"high": "20",
|
||||
"n_buckets": 19,
|
||||
"description": "Number of concurrent UDP socket closing threads"
|
||||
},
|
||||
"UDP_SOCKET_CLOSE_TIME": {
|
||||
"expires_in_version": "45",
|
||||
"kind": "exponential",
|
||||
"high": "60000",
|
||||
"n_buckets": 30,
|
||||
"description": "Time PR_Close of a UDP socket taken (ms)"
|
||||
},
|
||||
"SERVICE_WORKER_SPAWN_ATTEMPTS": {
|
||||
"expires_in_version": "50",
|
||||
"kind": "count",
|
||||
|
Loading…
Reference in New Issue
Block a user