bug 1152046 - Revert Make separate thread only for PRClose. r=backout
☠☠ backed out by 5320f1017b81 ☠ ☠
authorPatrick McManus <mcmanus@ducksong.com>
Tue, 15 Sep 2015 21:40:28 -0400
changeset 295323 d5d0b5994149bc22ee38b1ae14acb69853a9646d
parent 295322 902358f27dd2f8d8ffabfeba7a088390c13813b8
child 295324 248f5a4b7e0e42bd3278269e9ad4043e59c056b6
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1152046
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1152046 - Revert Make separate thread only for PRClose. r=backout This reverts commit 760a84e7cf7fa49c889a5a17a5935d3ca1e02384.
netwerk/base/ClosingService.cpp
netwerk/base/ClosingService.h
netwerk/base/moz.build
netwerk/base/nsIOService.cpp
netwerk/base/nsSocketTransport2.cpp
netwerk/base/nsSocketTransportService2.cpp
netwerk/base/nsUDPSocket.cpp
netwerk/base/nsURLHelper.cpp
netwerk/protocol/rtsp/rtsp/ARTPConnection.cpp
netwerk/protocol/rtsp/rtsp/ARTPSession.cpp
netwerk/protocol/rtsp/rtsp/ARTPWriter.cpp
netwerk/protocol/rtsp/rtsp/ARTSPConnection.cpp
netwerk/protocol/rtsp/rtsp/UDPPusher.cpp
toolkit/components/telemetry/Histograms.json
deleted file mode 100644
--- a/netwerk/base/ClosingService.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-/* -*- 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
deleted file mode 100644
--- a/netwerk/base/ClosingService.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* -*- 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_
--- a/netwerk/base/moz.build
+++ b/netwerk/base/moz.build
@@ -184,17 +184,16 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk
     ]
 
 UNIFIED_SOURCES += [
     'ArrayBufferInputStream.cpp',
     'BackgroundFileSaver.cpp',
     'CaptivePortalService.cpp',
     'ChannelDiverterChild.cpp',
     'ChannelDiverterParent.cpp',
-    'ClosingService.cpp',
     'Dashboard.cpp',
     'EventTokenBucket.cpp',
     'LoadContextInfo.cpp',
     'LoadInfo.cpp',
     'MemoryDownloader.cpp',
     'NetworkActivityMonitor.cpp',
     'nsAsyncRedirectVerifyHelper.cpp',
     'nsAsyncStreamCopier.cpp',
--- a/netwerk/base/nsIOService.cpp
+++ b/netwerk/base/nsIOService.cpp
@@ -2,31 +2,29 @@
 /* vim:set ts=4 sw=4 cindent et: */
 /* 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 "mozilla/DebugOnly.h"
 
 #include "nsIOService.h"
-#include "nsIDOMNode.h"
 #include "nsIProtocolHandler.h"
 #include "nsIFileProtocolHandler.h"
 #include "nscore.h"
 #include "nsIURI.h"
 #include "prprf.h"
 #include "nsIErrorService.h"
 #include "netCore.h"
 #include "nsIObserverService.h"
 #include "nsIPrefService.h"
 #include "nsXPCOM.h"
 #include "nsIProxiedProtocolHandler.h"
 #include "nsIProxyInfo.h"
 #include "nsEscape.h"
-#include "nsNetUtil.h"
 #include "nsNetCID.h"
 #include "nsCRT.h"
 #include "nsSecCheckWrapChannel.h"
 #include "nsSimpleNestedURI.h"
 #include "nsTArray.h"
 #include "nsIConsoleService.h"
 #include "nsIUploadChannel2.h"
 #include "nsXULAppAPI.h"
@@ -39,17 +37,16 @@
 #include "nsURLHelper.h"
 #include "nsPIDNSService.h"
 #include "nsIProtocolProxyService2.h"
 #include "MainThreadUtils.h"
 #include "nsIWidget.h"
 #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"
 #include "ReferrerPolicy.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsINetworkManager.h"
 #include "nsINetworkInterface.h"
--- a/netwerk/base/nsSocketTransport2.cpp
+++ b/netwerk/base/nsSocketTransport2.cpp
@@ -11,17 +11,16 @@
 #include "nsIOService.h"
 #include "nsStreamUtils.h"
 #include "nsNetSegmentUtils.h"
 #include "nsNetAddr.h"
 #include "nsTransportUtils.h"
 #include "nsProxyInfo.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
-#include "ClosingService.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "plstr.h"
 #include "prerr.h"
 #include "NetworkActivityMonitor.h"
 #include "NSSErrorsService.h"
 #include "mozilla/net/NeckoChild.h"
 #include "nsThreadUtils.h"
@@ -1190,17 +1189,17 @@ nsSocketTransport::BuildSocket(PRFileDes
                 proxyPort = -1;
                 proxyTransparent = true;
             }
         }
 
         if (NS_FAILED(rv)) {
             SOCKET_LOG(("  error pushing io layer [%u:%s rv=%x]\n", i, mTypes[i], rv));
             if (fd) {
-                PR_Close(fd);
+                CloseSocket(fd, mSocketTransportService->IsTelemetryEnabled());
             }
         }
     }
 
     return rv;
 }
 
 nsresult
@@ -1318,19 +1317,16 @@ nsSocketTransport::InitiateSocket()
     if (NS_FAILED(rv)) {
         SOCKET_LOG(("  BuildSocket failed [rv=%x]\n", rv));
         return rv;
     }
 
     // Attach network activity monitor
     mozilla::net::NetworkActivityMonitor::AttachIOLayer(fd);
 
-    // Attach closing service.
-    ClosingService::AttachIOLayer(fd);
-
     PRStatus status;
 
     // Make the socket non-blocking...
     PRSocketOptionData opt;
     opt.option = PR_SockOpt_Nonblocking;
     opt.value.non_blocking = true;
     status = PR_SetSocketOption(fd, &opt);
     NS_ASSERTION(status == PR_SUCCESS, "unable to make socket non-blocking");
@@ -1357,17 +1353,17 @@ nsSocketTransport::InitiateSocket()
         opt.option = PR_SockOpt_IpTypeOfService;
         opt.value.tos = mQoSBits;
         PR_SetSocketOption(fd, &opt);
     }
 
     // inform socket transport about this newly created socket...
     rv = mSocketTransportService->AttachSocket(fd, this);
     if (NS_FAILED(rv)) {
-        PR_Close(fd);
+        CloseSocket(fd, mSocketTransportService->IsTelemetryEnabled());
         return rv;
     }
     mAttached = true;
 
     // assign mFD so that we can properly handle OnSocketDetached before we've
     // established a connection.
     {
         MutexAutoLock lock(mLock);
@@ -1697,17 +1693,18 @@ nsSocketTransport::GetFD_Locked()
 
 class ThunkPRClose : public nsRunnable
 {
 public:
   explicit ThunkPRClose(PRFileDesc *fd) : mFD(fd) {}
 
   NS_IMETHOD Run()
   {
-    PR_Close(mFD);
+    nsSocketTransport::CloseSocket(mFD,
+      gSocketTransportService->IsTelemetryEnabled());
     return NS_OK;
   }
 private:
   PRFileDesc *mFD;
 };
 
 void
 STS_PRCloseOnSocketTransport(PRFileDesc *fd)
@@ -1729,17 +1726,17 @@ nsSocketTransport::ReleaseFD_Locked(PRFi
     mLock.AssertCurrentThreadOwns();
 
     NS_ASSERTION(mFD == fd, "wrong fd");
     SOCKET_LOG(("JIMB: ReleaseFD_Locked: mFDref = %d\n", mFDref));
 
     if (--mFDref == 0) {
         if (PR_GetCurrentThread() == gSocketThread) {
             SOCKET_LOG(("nsSocketTransport: calling PR_Close [this=%p]\n", this));
-            PR_Close(mFD);
+            CloseSocket(mFD, mSocketTransportService->IsTelemetryEnabled());
         } else {
             // Can't PR_Close() a socket off STS thread. Thunk it to STS to die
             STS_PRCloseOnSocketTransport(mFD);
         }
         mFD = nullptr;
     }
 }
 
@@ -3038,16 +3035,39 @@ nsSocketTransport::PRFileDescAutoLock::S
 #else
     MOZ_ASSERT(false, "nsSocketTransport::PRFileDescAutoLock::SetKeepaliveVals "
                "called on unsupported platform!");
     return NS_ERROR_UNEXPECTED;
 #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,
                                            Telemetry::ID aIDShutdown,
                                            Telemetry::ID aIDConnectivityChange,
                                            Telemetry::ID aIDLinkChange,
                                            Telemetry::ID aIDOffline)
 {
     PRIntervalTime now = PR_IntervalNow();
--- a/netwerk/base/nsSocketTransportService2.cpp
+++ b/netwerk/base/nsSocketTransportService2.cpp
@@ -3,17 +3,16 @@
  * 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 "nsSocketTransportService2.h"
 #if !defined(MOZILLA_XPCOMRT_API)
 #include "nsSocketTransport2.h"
 #include "NetworkActivityMonitor.h"
 #include "mozilla/Preferences.h"
-#include "ClosingService.h"
 #endif // !defined(MOZILLA_XPCOMRT_API)
 #include "nsASocketHandler.h"
 #include "nsError.h"
 #include "prnetdb.h"
 #include "prerror.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsServiceManagerUtils.h"
@@ -547,23 +546,16 @@ nsSocketTransportService::Init()
     UpdatePrefs();
 
     nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
     if (obsSvc) {
         obsSvc->AddObserver(this, "profile-initial-state", false);
         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;
 }
 
 // called from main thread only
 NS_IMETHODIMP
 nsSocketTransportService::Shutdown()
 {
@@ -604,17 +596,16 @@ nsSocketTransportService::Shutdown()
     nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
     if (obsSvc) {
         obsSvc->RemoveObserver(this, "profile-initial-state");
         obsSvc->RemoveObserver(this, "last-pb-context-exited");
     }
 
 #if !defined(MOZILLA_XPCOMRT_API)
     mozilla::net::NetworkActivityMonitor::Shutdown();
-    ClosingService::Shutdown();
 #endif // !defined(MOZILLA_XPCOMRT_API)
 
     mInitialized = false;
     mShuttingDown = false;
 
     return NS_OK;
 }
 
@@ -1442,18 +1433,17 @@ nsSocketTransportService::DiscoverMaxCou
 // Used to return connection info to Dashboard.cpp
 void
 nsSocketTransportService::AnalyzeConnection(nsTArray<SocketInfo> *data,
         struct SocketContext *context, bool aActive)
 {
     if (context->mHandler->mIsPrivate)
         return;
     PRFileDesc *aFD = context->mFD;
-    bool tcp = (PR_GetDescType(PR_GetIdentitiesLayer(aFD, PR_NSPR_IO_LAYER)) ==
-                PR_DESC_SOCKET_TCP);
+    bool tcp = (PR_GetDescType(aFD) == PR_DESC_SOCKET_TCP);
 
     PRNetAddr peer_addr;
     PR_GetPeerName(aFD, &peer_addr);
 
     char host[64] = {0};
     PR_NetAddrToString(&peer_addr, host, sizeof(host));
 
     uint16_t port;
--- a/netwerk/base/nsUDPSocket.cpp
+++ b/netwerk/base/nsUDPSocket.cpp
@@ -23,25 +23,25 @@
 #include "NetworkActivityMonitor.h"
 #include "nsStreamUtils.h"
 #include "nsIPipe.h"
 #include "prerror.h"
 #include "nsThreadUtils.h"
 #include "nsIDNSRecord.h"
 #include "nsIDNSService.h"
 #include "nsICancelable.h"
-#include "ClosingService.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "NetStatistics.h"
 #endif
 
 using namespace mozilla::net;
 using namespace mozilla;
 
+static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
 static const uint32_t UDP_PACKET_CHUNK_SIZE = 1400;
 
 //-----------------------------------------------------------------------------
 
 typedef void (nsUDPSocket:: *nsUDPSocketFunc)(void);
 
 static nsresult
 PostEvent(nsUDPSocket *s, nsUDPSocketFunc func)
@@ -87,16 +87,201 @@ public:
   }
 
 private:
   nsRefPtr<nsUDPSocket> mSocket;
   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
 //-----------------------------------------------------------------------------
 NS_IMPL_ISUPPORTS(nsUDPOutputStream, nsIOutputStream)
 
 nsUDPOutputStream::nsUDPOutputStream(nsUDPSocket* aSocket,
                                      PRFileDesc* aFD,
                                      PRNetAddr& aPrClientAddr)
   : mSocket(aSocket)
@@ -267,17 +452,19 @@ nsUDPSocket::nsUDPSocket()
 
   mSts = gSocketTransportService;
   MOZ_COUNT_CTOR(nsUDPSocket);
 }
 
 nsUDPSocket::~nsUDPSocket()
 {
   if (mFD) {
-    PR_Close(mFD);
+    if (!nsUDPSocketCloseThread::Close(mFD)) {
+      PR_Close(mFD);
+    }
     mFD = nullptr;
   }
 
   MOZ_COUNT_DTOR(nsUDPSocket);
 }
 
 void
 nsUDPSocket::AddOutputBytes(uint64_t aBytes)
@@ -509,17 +696,19 @@ nsUDPSocket::OnSocketDetached(PRFileDesc
 {
   // force a failure condition if none set; maybe the STS is shutting down :-/
   if (NS_SUCCEEDED(mCondition))
     mCondition = NS_ERROR_ABORT;
 
   if (mFD)
   {
     NS_ASSERTION(mFD == fd, "wrong file descriptor");
-    PR_Close(mFD);
+    if (!nsUDPSocketCloseThread::Close(mFD)) {
+      PR_Close(mFD);
+    }
     mFD = nullptr;
   }
   SaveNetworkStats(true);
 
   if (mListener)
   {
     // need to atomically clear mListener.  see our Close() method.
     nsCOMPtr<nsIUDPSocketListener> listener;
@@ -650,17 +839,16 @@ nsUDPSocket::InitWithAddress(const NetAd
     NS_WARNING("cannot get socket name");
     goto fail;
   }
 
   PRNetAddrToNetAddr(&addr, &mAddr);
 
   // create proxy via NetworkActivityMonitor
   NetworkActivityMonitor::AttachIOLayer(mFD);
-  ClosingService::AttachIOLayer(mFD);
 
   // wait until AsyncListen is called before polling the socket for
   // client connections.
   return NS_OK;
 
 fail:
   Close();
   return NS_ERROR_FAILURE;
--- a/netwerk/base/nsURLHelper.cpp
+++ b/netwerk/base/nsURLHelper.cpp
@@ -7,17 +7,16 @@
 #include "mozilla/RangedPtr.h"
 
 #include "nsURLHelper.h"
 #include "nsIFile.h"
 #include "nsIURLParser.h"
 #include "nsCOMPtr.h"
 #include "nsCRT.h"
 #include "nsNetCID.h"
-#include "mozilla/Preferences.h"
 #include "prnetdb.h"
 
 using namespace mozilla;
 
 //----------------------------------------------------------------------------
 // Init/Shutdown
 //----------------------------------------------------------------------------
 
--- a/netwerk/protocol/rtsp/rtsp/ARTPConnection.cpp
+++ b/netwerk/protocol/rtsp/rtsp/ARTPConnection.cpp
@@ -31,17 +31,16 @@
 #include <arpa/inet.h>
 
 #include "mozilla/mozalloc.h"
 #include "nsTArray.h"
 #include "prnetdb.h"
 #include "prerr.h"
 #include "prerror.h"
 #include "NetworkActivityMonitor.h"
-#include "ClosingService.h"
 
 using namespace mozilla::net;
 
 namespace android {
 
 static const size_t kMaxUDPSize = 1500;
 
 static uint16_t u16at(const uint8_t *data) {
@@ -140,19 +139,16 @@ void ARTPConnection::MakePortPair(
         TRESPASS();
     }
 
     bumpSocketBufferSize(*rtcpSocket);
 
     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.
     unsigned start = (unsigned)((rand() * 1000ll) / RAND_MAX) + 15550;
     start &= ~1;
 
     for (uint32_t port = start; port < 65536; port += 2) {
         PRNetAddr addr;
--- a/netwerk/protocol/rtsp/rtsp/ARTPSession.cpp
+++ b/netwerk/protocol/rtsp/rtsp/ARTPSession.cpp
@@ -29,17 +29,16 @@
 
 #include "APacketSource.h"
 #include "ARTPConnection.h"
 #include "ASessionDescription.h"
 
 #include "prnetdb.h"
 #include "prerr.h"
 #include "NetworkActivityMonitor.h"
-#include "ClosingService.h"
 
 using namespace mozilla::net;
 
 namespace android {
 
 ARTPSession::ARTPSession()
     : mInitCheck(NO_INIT) {
 }
@@ -105,17 +104,16 @@ status_t ARTPSession::setup(const sp<ASe
 // static
 void ARTPSession::MakeUDPSocket(PRFileDesc **s, unsigned port) {
     *s = PR_OpenUDPSocket(PR_AF_INET);
     if (!*s) {
         TRESPASS();
     }
 
     NetworkActivityMonitor::AttachIOLayer(*s);
-    ClosingService::AttachIOLayer(*s);
 
     PRNetAddr addr;
     addr.inet.family = PR_AF_INET;
     addr.inet.ip = PR_htonl(PR_INADDR_ANY);
     addr.inet.port = PR_htons(port);
 
     if (PR_Bind(*s, &addr) == PR_FAILURE) {
         TRESPASS();
--- a/netwerk/protocol/rtsp/rtsp/ARTPWriter.cpp
+++ b/netwerk/protocol/rtsp/rtsp/ARTPWriter.cpp
@@ -26,17 +26,16 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/ByteOrder.h>
 
-#include "ClosingService.h"
 #include "NetworkActivityMonitor.h"
 
 using namespace mozilla::net;
 
 #define PT      97
 #define PT_STR  "97"
 
 namespace android {
@@ -60,17 +59,16 @@ ARTPWriter::ARTPWriter(int fd)
     mLooper->start();
 
     mSocket = PR_OpenUDPSocket(PR_AF_INET);
     if (!mSocket) {
         TRESPASS();
     }
 
     NetworkActivityMonitor::AttachIOLayer(mSocket);
-    ClosingService::AttachIOLayer(mSocket);
 
     mRTPAddr.inet.family = PR_AF_INET;
 
 #if 1
     mRTPAddr.inet.ip = PR_htonl(PR_INADDR_ANY);
 #else
     PR_StringToNetAddr("172.19.18.246", &mRTPAddr);
 #endif
--- a/netwerk/protocol/rtsp/rtsp/ARTSPConnection.cpp
+++ b/netwerk/protocol/rtsp/rtsp/ARTSPConnection.cpp
@@ -29,17 +29,16 @@
 
 #include <arpa/inet.h>
 #include <fcntl.h>
 #include <netdb.h>
 
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsNetCID.h"
-#include "ClosingService.h"
 #include "nsIServiceManager.h"
 #include "nsICryptoHash.h"
 
 #include "prnetdb.h"
 #include "prerr.h"
 #include "prerror.h"
 #include "NetworkActivityMonitor.h"
 
@@ -279,17 +278,16 @@ void ARTSPConnection::onConnect(const sp
     }
 
     mSocket = PR_OpenTCPSocket(PR_AF_INET);
     if (!mSocket) {
         TRESPASS();
     }
 
     NetworkActivityMonitor::AttachIOLayer(mSocket);
-    ClosingService::AttachIOLayer(mSocket);
 
     MakeSocketBlocking(mSocket, false);
 
     PRNetAddr remote;
     remote.inet.family = PR_AF_INET;
     remote.inet.ip = *((uint32_t *) hostentry.h_addr_list[0]);
     remote.inet.port = PR_htons(port);
 
--- a/netwerk/protocol/rtsp/rtsp/UDPPusher.cpp
+++ b/netwerk/protocol/rtsp/rtsp/UDPPusher.cpp
@@ -22,17 +22,16 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <utils/ByteOrder.h>
 
 #include "prnetdb.h"
 #include "prerr.h"
 #include "NetworkActivityMonitor.h"
-#include "ClosingService.h"
 
 using namespace mozilla::net;
 
 namespace android {
 
 UDPPusher::UDPPusher(const char *filename, unsigned port)
     : mFile(fopen(filename, "rb")),
       mFirstTimeMs(0),
@@ -40,17 +39,16 @@ UDPPusher::UDPPusher(const char *filenam
     CHECK(mFile != NULL);
 
     mSocket = PR_OpenUDPSocket(PR_AF_INET);
     if (!mSocket) {
         TRESPASS();
     }
 
     NetworkActivityMonitor::AttachIOLayer(mSocket);
-    ClosingService::AttachIOLayer(mSocket);
 
     PRNetAddr addr;
     addr.inet.family = PR_AF_INET;
     addr.inet.ip = PR_htonl(PR_INADDR_ANY);
     addr.inet.port = PR_htons(0);
 
     CHECK_EQ(PR_SUCCESS, PR_Bind(mSocket, &addr));
 
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -2562,80 +2562,45 @@
   },
   "PRCONNECTCONTINUE_BLOCKING_TIME_OFFLINE": {
     "expires_in_version": "never",
     "kind": "exponential",
     "high": "60000",
     "n_buckets": 1000,
     "description": "Time spent blocked in PR_ConnectContinue when the offline state has changed in the last 60s (ms)."
   },
-  "PRCLOSE_TCP_BLOCKING_TIME_NORMAL": {
+  "PRCLOSE_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_TCP_BLOCKING_TIME_SHUTDOWN": {
+  "PRCLOSE_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_TCP_BLOCKING_TIME_CONNECTIVITY_CHANGE": {
+  "PRCLOSE_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_TCP_BLOCKING_TIME_LINK_CHANGE": {
+  "PRCLOSE_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_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": {
+  "PRCLOSE_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)."
   },
   "IPV4_AND_IPV6_ADDRESS_CONNECTIVITY": {
     "expires_in_version": "never",
@@ -8717,16 +8682,30 @@
     "description": "Count slow script notices"
   },
   "PLUGIN_HANG_NOTICE_COUNT": {
     "alert_emails": ["perf-telemetry-alerts@mozilla.com"],
     "expires_in_version": "never",
     "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",
     "description": "Count attempts to spawn a ServiceWorker for a domain. File bugs in Core::DOM in case of a Telemetry regression."
   },
   "SERVICE_WORKER_WAS_SPAWNED": {
     "expires_in_version": "50",
     "kind": "count",