Switch local launching of debugserver over to always use a FIFO in order to handshake with the launched debugserver.

This helps ensure that the launched debugserver is ready and listening for a connection. Prior to this we had a race condition.

Consolidate the launching of debugserver into a single place: a static function in GDBRemoteCommunication.

llvm-svn: 196401
diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp
index 22db738..6f60839 100644
--- a/lldb/tools/debugserver/source/RNBRemote.cpp
+++ b/lldb/tools/debugserver/source/RNBRemote.cpp
@@ -915,7 +915,6 @@
 
                 if (reg_entry.nub_info.value_regs == NULL)
                 {
-                    DNBLogThreaded("%s -> %u", reg_entry.nub_info.name, reg_data_offset);
                     reg_data_offset += reg_entry.nub_info.size;
                 }
 
diff --git a/lldb/tools/debugserver/source/RNBSocket.cpp b/lldb/tools/debugserver/source/RNBSocket.cpp
index 67dc009..448db257 100644
--- a/lldb/tools/debugserver/source/RNBSocket.cpp
+++ b/lldb/tools/debugserver/source/RNBSocket.cpp
@@ -120,20 +120,6 @@
         return rnb_err;
     }
 
-    if (callback && port == 0)
-    {
-        // We were asked to listen on port zero which means we
-        // must now read the actual port that was given to us 
-        // as port zero is a special code for "find an open port
-        // for me".
-        socklen_t sa_len = sizeof (sa);
-        if (getsockname(listen_fd, (struct sockaddr *)&sa, &sa_len) == 0)
-        {
-            port = ntohs (sa.sin_port);
-            callback (callback_baton, port);
-        }
-    }
-
     error = ::listen (listen_fd, 5);
     if (error == -1)
         err.SetError(errno, DNBError::POSIX);
@@ -146,6 +132,27 @@
         ClosePort (listen_fd, false);
         return rnb_err;
     }
+    
+    if (callback)
+    {
+        // We were asked to listen on port zero which means we
+        // must now read the actual port that was given to us
+        // as port zero is a special code for "find an open port
+        // for me".
+        if (port == 0)
+        {
+            socklen_t sa_len = sizeof (sa);
+            if (getsockname(listen_fd, (struct sockaddr *)&sa, &sa_len) == 0)
+            {
+                port = ntohs (sa.sin_port);
+                callback (callback_baton, port);
+            }
+        }
+        else
+        {
+            callback (callback_baton, port);
+        }
+    }
 
     struct sockaddr_in accept_addr;
     ::memset (&accept_addr, 0, sizeof accept_addr);
diff --git a/lldb/tools/debugserver/source/debugserver.cpp b/lldb/tools/debugserver/source/debugserver.cpp
index baa0fb7..b0b694c 100644
--- a/lldb/tools/debugserver/source/debugserver.cpp
+++ b/lldb/tools/debugserver/source/debugserver.cpp
@@ -625,73 +625,32 @@
     return eRNBRunLoopModeExit;
 }
 
-//----------------------------------------------------------------------
-// Convenience function to set up the remote listening port
-// Returns 1 for success 0 for failure.
-//----------------------------------------------------------------------
-
 static void
-PortWasBoundCallback (const void *baton, in_port_t port)
+PortWasBoundCallbackNamedPipe (const void *baton, in_port_t port)
 {
-    //::printf ("PortWasBoundCallback (baton = %p, port = %u)\n", baton, port);
-
-    const char *unix_socket_name = (const char *)baton;
-    
-    if (unix_socket_name && unix_socket_name[0])
+    const char *named_pipe = (const char *)baton;
+    if (named_pipe && named_pipe[0])
     {
-        // We were given a unix socket name to use to communicate the port
-        // that we ended up binding to back to our parent process
-        struct sockaddr_un saddr_un;
-        int s = ::socket (AF_UNIX, SOCK_STREAM, 0);
-        if (s < 0)
+        int fd = ::open(named_pipe, O_WRONLY);
+        if (fd > -1)
         {
-            perror("error: socket (AF_UNIX, SOCK_STREAM, 0)");
-            exit(1);
+            char port_str[64];
+            const ssize_t port_str_len = ::snprintf (port_str, sizeof(port_str), "%u", port);
+            // Write the port number as a C string with the NULL terminator
+            ::write (fd, port_str, port_str_len + 1);
+            close (fd);
         }
-        
-        saddr_un.sun_family = AF_UNIX;
-        ::strncpy(saddr_un.sun_path, unix_socket_name, sizeof(saddr_un.sun_path) - 1);
-        saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
-        saddr_un.sun_len = SUN_LEN (&saddr_un);
-        
-        if (::connect (s, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0) 
-        {
-            perror("error: connect (socket, &saddr_un, saddr_un_len)");
-            exit(1);
-        }
-        
-        //::printf ("connect () sucess!!\n");
-
-        
-        // We were able to connect to the socket, now write our PID so whomever
-        // launched us will know this process's ID
-        RNBLogSTDOUT ("Listening to port %i...\n", port);
-        
-        char pid_str[64];
-        const int pid_str_len = ::snprintf (pid_str, sizeof(pid_str), "%u", port);
-        const int bytes_sent = ::send (s, pid_str, pid_str_len, 0);
-        
-        if (pid_str_len != bytes_sent)
-        {
-            perror("error: send (s, pid_str, pid_str_len, 0)");
-            exit (1);
-        }
-
-        //::printf ("send () sucess!!\n");
-
-        // We are done with the socket
-        close (s);
     }
 }
 
 static int
-StartListening (RNBRemote *remote, const char *listen_host, int listen_port, const char *unix_socket_name)
+StartListening (RNBRemote *remote, const char *listen_host, int listen_port, const char *named_pipe_path)
 {
     if (!remote->Comm().IsConnected())
     {
         if (listen_port != 0)
             RNBLogSTDOUT ("Listening to port %i for a connection from %s...\n", listen_port, listen_host ? listen_host : "localhost");
-        if (remote->Comm().Listen(listen_host, listen_port, PortWasBoundCallback, unix_socket_name) != rnb_success)
+        if (remote->Comm().Listen(listen_host, listen_port, PortWasBoundCallbackNamedPipe, named_pipe_path) != rnb_success)
         {
             RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
             return 0;
@@ -786,7 +745,7 @@
     { "disable-aslr",       no_argument,        NULL,               'D' },  // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization
     { "working-dir",        required_argument,  NULL,               'W' },  // The working directory that the inferior process should have (only if debugserver launches the process)
     { "platform",           required_argument,  NULL,               'p' },  // Put this executable into a remote platform mode
-    { "unix-socket",        required_argument,  NULL,               'u' },  // If we need to handshake with our parent process, an option will be passed down that specifies a unix socket name to use
+    { "named-pipe",         required_argument,  NULL,               'P' },
     { NULL,                 0,                  NULL,               0   }
 };
 
@@ -838,7 +797,7 @@
     std::string attach_pid_name;
     std::string arch_name;
     std::string working_dir;                // The new working directory to use for the inferior
-    std::string unix_socket_name;           // If we need to handshake with our parent process, an option will be passed down that specifies a unix socket name to use
+    std::string named_pipe_path;            // If we need to handshake with our parent process, an option will be passed down that specifies a named pipe to use
     useconds_t waitfor_interval = 1000;     // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
     useconds_t waitfor_duration = 0;        // Time in seconds to wait for a process by name, 0 means wait forever.
     bool no_stdio = false;
@@ -1086,8 +1045,8 @@
                 start_mode = eRNBRunLoopModePlatformMode;
                 break;
 
-            case 'u':
-                unix_socket_name.assign (optarg);
+            case 'P':
+                named_pipe_path.assign (optarg);
                 break;
         }
     }
@@ -1306,7 +1265,7 @@
 #endif
                 if (listen_port != INT32_MAX)
                 {
-                    if (!StartListening (remote, listen_host.c_str(), listen_port, unix_socket_name.c_str()))
+                    if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str()))
                         mode = eRNBRunLoopModeExit;
                 }
                 else if (str[0] == '/')
@@ -1419,7 +1378,7 @@
                 {
                     if (listen_port != INT32_MAX)
                     {
-                        if (!StartListening (remote, listen_host.c_str(), listen_port, unix_socket_name.c_str()))
+                        if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str()))
                             mode = eRNBRunLoopModeExit;
                     }
                     else if (str[0] == '/')
@@ -1444,7 +1403,7 @@
                     {
                         if (listen_port != INT32_MAX)
                         {
-                            if (!StartListening (remote, listen_host.c_str(), listen_port, unix_socket_name.c_str()))
+                            if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str()))
                                 mode = eRNBRunLoopModeExit;
                         }
                         else if (str[0] == '/')
@@ -1471,7 +1430,7 @@
             case eRNBRunLoopModePlatformMode:
                 if (listen_port != INT32_MAX)
                 {
-                    if (!StartListening (remote, listen_host.c_str(), listen_port, unix_socket_name.c_str()))
+                    if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str()))
                         mode = eRNBRunLoopModeExit;
                 }
                 else if (str[0] == '/')