[PR,d/88654] Committed phobos fix for thread deadlock in std.net.curl

Message ID CABOHX+f_EpEsabumWkAOfsXyoJ_8=H7av2wGswuwnmxmQQm10g@mail.gmail.com
State New
Headers show
Series
  • [PR,d/88654] Committed phobos fix for thread deadlock in std.net.curl
Related show

Commit Message

Iain Buclaw Feb. 10, 2019, 2:28 p.m.
Hi,

This patch is the library fix for a thread deadlock that occurred when
libcurl is missing.  It is only one half of the fix for the PR, the
other is for the testsuite scripts to check that libcurl exists before
attempting to run the std.net.curl unittest.

Bootstrapped and tested on x86_64-linux-gnu (-m32) to verify test goes
from timed out to just fail.

Committed to trunk as r268746.

-- 
Iain
---

Patch

diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index eee413903c0..aef240e0722 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@ 
-d4933a90b1e8446c04d64cd044658f2b33250bd3
+6c9fb28b0f8813d41798202a9d19c6b37ba5da5f
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
diff --git a/libphobos/src/std/net/curl.d b/libphobos/src/std/net/curl.d
index 9d751411705..e3ce527c303 100644
--- a/libphobos/src/std/net/curl.d
+++ b/libphobos/src/std/net/curl.d
@@ -178,7 +178,7 @@  version (unittest)
     import std.range;
     import std.stdio;
 
-    import std.socket : Address, INADDR_LOOPBACK, Socket, TcpSocket;
+    import std.socket : Address, INADDR_LOOPBACK, Socket, SocketShutdown, TcpSocket;
 
     private struct TestServer
     {
@@ -192,6 +192,7 @@  version (unittest)
     private:
         string _addr;
         Tid tid;
+        TcpSocket sock;
 
         static void loop(shared TcpSocket listener)
         {
@@ -215,20 +216,34 @@  version (unittest)
 
     private TestServer startServer()
     {
+        tlsInit = true;
         auto sock = new TcpSocket;
         sock.bind(new InternetAddress(INADDR_LOOPBACK, InternetAddress.PORT_ANY));
         sock.listen(1);
         auto addr = sock.localAddress.toString();
         auto tid = spawn(&TestServer.loop, cast(shared) sock);
-        return TestServer(addr, tid);
+        return TestServer(addr, tid, sock);
     }
 
+    __gshared TestServer server;
+    bool tlsInit;
+
     private ref TestServer testServer()
     {
-        __gshared TestServer server;
         return initOnce!server(startServer());
     }
 
+    static ~this()
+    {
+        // terminate server from a thread local dtor of the thread that started it,
+        //  because thread_joinall is called before shared module dtors
+        if (tlsInit && server.sock)
+        {
+            server.sock.shutdown(SocketShutdown.RECEIVE);
+            server.sock.close();
+        }
+    }
+
     private struct Request(T)
     {
         string hdrs;
@@ -429,7 +444,11 @@  if (isCurlConn!Conn)
             s.send(httpOK("Hello world"));
         });
         auto fn = std.file.deleteme;
-        scope (exit) std.file.remove(fn);
+        scope (exit)
+        {
+            if (std.file.exists(fn))
+                std.file.remove(fn);
+        }
         download(host, fn);
         assert(std.file.readText(fn) == "Hello world");
     }
@@ -491,7 +510,11 @@  if (isCurlConn!Conn)
     foreach (host; [testServer.addr, "http://"~testServer.addr])
     {
         auto fn = std.file.deleteme;
-        scope (exit) std.file.remove(fn);
+        scope (exit)
+        {
+            if (std.file.exists(fn))
+                std.file.remove(fn);
+        }
         std.file.write(fn, "upload data\n");
         testServer.handle((s) {
             auto req = s.recvReq;