Add "vAttachOrWait" to debugserver, so you can implement "attach to the process if it exists OR wait for it" without race conditions.  Use that in lldb.

llvm-svn: 160578
diff --git a/lldb/tools/debugserver/source/DNB.cpp b/lldb/tools/debugserver/source/DNB.cpp
index 0a29eaa..6de893d 100644
--- a/lldb/tools/debugserver/source/DNB.cpp
+++ b/lldb/tools/debugserver/source/DNB.cpp
@@ -499,7 +499,6 @@
                     else
                     {
                         // We found a matching process, add it to our list
-
                         matching_proc_infos.push_back(proc_infos[i]);
                     }
                 }
@@ -513,6 +512,7 @@
 nub_process_t
 DNBProcessAttachWait (const char *waitfor_process_name, 
                       nub_launch_flavor_t launch_flavor,
+                      bool ignore_existing,
                       struct timespec *timeout_abstime, 
                       useconds_t waitfor_interval,
                       char *err_str, 
@@ -536,7 +536,12 @@
     }
 
     if (attach_token == NULL)
-        num_exclude_proc_infos = GetAllInfosMatchingName (waitfor_process_name, exclude_proc_infos);
+    {
+        if (ignore_existing)
+            num_exclude_proc_infos = GetAllInfosMatchingName (waitfor_process_name, exclude_proc_infos);
+        else
+            num_exclude_proc_infos = 0;
+    }
 
     DNBLogThreadedIf (LOG_PROCESS, "Waiting for '%s' to appear...\n", waitfor_process_name);
 
diff --git a/lldb/tools/debugserver/source/DNB.h b/lldb/tools/debugserver/source/DNB.h
index 68df124..d206826 100644
--- a/lldb/tools/debugserver/source/DNB.h
+++ b/lldb/tools/debugserver/source/DNB.h
@@ -48,7 +48,7 @@
 
 nub_process_t   DNBProcessAttach        (nub_process_t pid, struct timespec *timeout, char *err_str, size_t err_len) DNB_EXPORT;
 nub_process_t   DNBProcessAttachByName  (const char *name, struct timespec *timeout, char *err_str, size_t err_len) DNB_EXPORT;
-nub_process_t   DNBProcessAttachWait    (const char *wait_name, nub_launch_flavor_t launch_flavor, struct timespec *timeout, useconds_t interval, char *err_str, size_t err_len, DNBShouldCancelCallback should_cancel = NULL, void *callback_data = NULL) DNB_EXPORT;
+nub_process_t   DNBProcessAttachWait    (const char *wait_name, nub_launch_flavor_t launch_flavor, bool ignore_existing, struct timespec *timeout, useconds_t interval, char *err_str, size_t err_len, DNBShouldCancelCallback should_cancel = NULL, void *callback_data = NULL) DNB_EXPORT;
 // Resume a process with exact instructions on what to do with each thread:
 // - If no thread actions are supplied (actions is NULL or num_actions is zero),
 //   then all threads are continued.
diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp
index 4b2571d..eaad18b 100644
--- a/lldb/tools/debugserver/source/RNBRemote.cpp
+++ b/lldb/tools/debugserver/source/RNBRemote.cpp
@@ -141,6 +141,7 @@
     t.push_back (Packet (thread_alive_p,                &RNBRemote::HandlePacket_T,             NULL, "T", "Is thread alive"));
     t.push_back (Packet (vattach,                       &RNBRemote::HandlePacket_v,             NULL, "vAttach", "Attach to a new process"));
     t.push_back (Packet (vattachwait,                   &RNBRemote::HandlePacket_v,             NULL, "vAttachWait", "Wait for a process to start up then attach to it"));
+    t.push_back (Packet (vattachorwait,                 &RNBRemote::HandlePacket_v,             NULL, "vAttachOrWait", "Attach to the process or if it doesn't exist, wait for the process to start up then attach to it"));
     t.push_back (Packet (vattachname,                   &RNBRemote::HandlePacket_v,             NULL, "vAttachName", "Attach to an existing process by name"));
     t.push_back (Packet (vcont_list_actions,            &RNBRemote::HandlePacket_v,             NULL, "vCont;", "Verbose resume with thread actions"));
     t.push_back (Packet (vcont_list_actions,            &RNBRemote::HandlePacket_v,             NULL, "vCont?", "List valid continue-with-thread-actions actions"));
@@ -169,6 +170,7 @@
     t.push_back (Packet (query_register_info,           &RNBRemote::HandlePacket_qRegisterInfo, NULL, "qRegisterInfo", "Dynamically discover remote register context information."));
     t.push_back (Packet (query_shlib_notify_info_addr,  &RNBRemote::HandlePacket_qShlibInfoAddr,NULL, "qShlibInfoAddr", "Returns the address that contains info needed for getting shared library notifications"));
     t.push_back (Packet (query_step_packet_supported,   &RNBRemote::HandlePacket_qStepPacketSupported,NULL, "qStepPacketSupported", "Replys with OK if the 's' packet is supported."));
+    t.push_back (Packet (query_vattachorwait_supported, &RNBRemote::HandlePacket_qVAttachOrWaitSupported,NULL, "qVAttachOrWaitSupported", "Replys with OK if the 'vAttachOrWait' packet is supported."));
     t.push_back (Packet (query_host_info,               &RNBRemote::HandlePacket_qHostInfo,     NULL, "qHostInfo", "Replies with multiple 'key:value;' tuples appended to each other."));
 //  t.push_back (Packet (query_symbol_lookup,           &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "qSymbol", "Notify that host debugger is ready to do symbol lookups"));
     t.push_back (Packet (start_noack_mode,              &RNBRemote::HandlePacket_QStartNoAckMode        , NULL, "QStartNoAckMode", "Request that " DEBUGSERVER_PROGRAM_NAME " stop acking remote protocol packets"));
@@ -1302,6 +1304,13 @@
 }
 
 rnb_err_t
+RNBRemote::HandlePacket_qVAttachOrWaitSupported (const char *p)
+{
+    // We support attachOrWait meaning attach if the process exists, otherwise wait to attach.
+    return SendPacket("OK");
+}
+
+rnb_err_t
 RNBRemote::HandlePacket_qThreadStopInfo (const char *p)
 {
     p += strlen ("qThreadStopInfo");
@@ -2678,6 +2687,31 @@
     return SendPacket ("E54");
 }
 
+static bool
+GetProcessNameFrom_vAttach (const char *&p, std::string &attach_name)
+{
+    bool return_val = true;
+    while (*p != '\0')
+    {
+        char smallbuf[3];
+        smallbuf[0] = *p;
+        smallbuf[1] = *(p + 1);
+        smallbuf[2] = '\0';
+
+        errno = 0;
+        int ch = strtoul (smallbuf, NULL, 16);
+        if (errno != 0 && ch == 0)
+        {
+            return_val = false;
+            break;
+        }
+
+        attach_name.push_back(ch);
+        p += 2;
+    }
+    return return_val;
+}
+
 /*
  vAttach;pid
 
@@ -2781,51 +2815,37 @@
     {
         nub_process_t attach_pid = INVALID_NUB_PROCESS;
         char err_str[1024]={'\0'};
+        
         if (strstr (p, "vAttachWait;") == p)
         {
             p += strlen("vAttachWait;");
             std::string attach_name;
-            while (*p != '\0')
+            if (!GetProcessNameFrom_vAttach(p, attach_name))
             {
-                char smallbuf[3];
-                smallbuf[0] = *p;
-                smallbuf[1] = *(p + 1);
-                smallbuf[2] = '\0';
-
-                errno = 0;
-                int ch = strtoul (smallbuf, NULL, 16);
-                if (errno != 0 && ch == 0)
-                {
-                    return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'vAttachWait' pkt");
-                }
-
-                attach_name.push_back(ch);
-                p += 2;
+                return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'vAttachWait' pkt");
             }
+            const bool ignore_existing = true;
+            attach_pid = DNBProcessAttachWait(attach_name.c_str (), m_ctx.LaunchFlavor(), ignore_existing, NULL, 1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback);
 
-            attach_pid = DNBProcessAttachWait(attach_name.c_str (), m_ctx.LaunchFlavor(), NULL, 1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback);
-
+        }
+        else if (strstr (p, "vAttachOrWait;") == p)
+        {
+            p += strlen("vAttachOrWait;");
+            std::string attach_name;
+            if (!GetProcessNameFrom_vAttach(p, attach_name))
+            {
+                return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'vAttachOrWait' pkt");
+            }
+            const bool ignore_existing = false;
+            attach_pid = DNBProcessAttachWait(attach_name.c_str (), m_ctx.LaunchFlavor(), ignore_existing, NULL, 1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback);
         }
         else if (strstr (p, "vAttachName;") == p)
         {
             p += strlen("vAttachName;");
             std::string attach_name;
-            while (*p != '\0')
+            if (!GetProcessNameFrom_vAttach(p, attach_name))
             {
-                char smallbuf[3];
-                smallbuf[0] = *p;
-                smallbuf[1] = *(p + 1);
-                smallbuf[2] = '\0';
-
-                errno = 0;
-                int ch = strtoul (smallbuf, NULL, 16);
-                if (errno != 0 && ch == 0)
-                {
-                    return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'vAttachWait' pkt");
-                }
-
-                attach_name.push_back(ch);
-                p += 2;
+                return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'vAttachName' pkt");
             }
 
             attach_pid = DNBProcessAttachByName (attach_name.c_str(), NULL, err_str, sizeof(err_str));
@@ -2845,7 +2865,9 @@
             }
         }
         else
+        {
             return HandlePacket_UNIMPLEMENTED(p);
+        }
 
 
         if (attach_pid != INVALID_NUB_PROCESS)
diff --git a/lldb/tools/debugserver/source/RNBRemote.h b/lldb/tools/debugserver/source/RNBRemote.h
index 23eabdd..b10449a 100644
--- a/lldb/tools/debugserver/source/RNBRemote.h
+++ b/lldb/tools/debugserver/source/RNBRemote.h
@@ -63,6 +63,7 @@
         thread_alive_p,                 // 'T'
         vattach,                        // 'vAttach;pid'
         vattachwait,                    // 'vAttachWait:XX...' where XX is one or more hex encoded process name ASCII bytes
+        vattachorwait,                  // 'vAttachOrWait:XX...' where XX is one or more hex encoded process name ASCII bytes
         vattachname,                    // 'vAttachName:XX...' where XX is one or more hex encoded process name ASCII bytes
         vcont,                          // 'vCont'
         vcont_list_actions,             // 'vCont?'
@@ -91,6 +92,7 @@
         query_register_info,            // 'qRegisterInfo'
         query_shlib_notify_info_addr,   // 'qShlibInfoAddr'
         query_step_packet_supported,    // 'qStepPacketSupported'
+        query_vattachorwait_supported,  // 'qVAttachOrWaitSupported'
         query_host_info,                // 'qHostInfo'
         pass_signals_to_inferior,       // 'QPassSignals'
         start_noack_mode,               // 'QStartNoAckMode'
@@ -164,6 +166,7 @@
     rnb_err_t HandlePacket_qRegisterInfo (const char *p);
     rnb_err_t HandlePacket_qShlibInfoAddr (const char *p);
     rnb_err_t HandlePacket_qStepPacketSupported (const char *p);
+    rnb_err_t HandlePacket_qVAttachOrWaitSupported (const char *p);
     rnb_err_t HandlePacket_qThreadInfo (const char *p);
     rnb_err_t HandlePacket_qThreadExtraInfo (const char *p);
     rnb_err_t HandlePacket_qThreadStopInfo (const char *p);
diff --git a/lldb/tools/debugserver/source/debugserver.cpp b/lldb/tools/debugserver/source/debugserver.cpp
index fe98848..6f3ba70 100644
--- a/lldb/tools/debugserver/source/debugserver.cpp
+++ b/lldb/tools/debugserver/source/debugserver.cpp
@@ -105,7 +105,7 @@
                 err = remote->HandleReceivedPacket (&type);
 
                 // check if we tried to attach to a process
-                if (type == RNBRemote::vattach || type == RNBRemote::vattachwait)
+                if (type == RNBRemote::vattach || type == RNBRemote::vattachwait || type == RNBRemote::vattachorwait)
                 {
                     if (err == rnb_success)
                         return eRNBRunLoopModeInferiorExecuting;
@@ -1319,8 +1319,8 @@
                     }
 
                     ctx.SetLaunchFlavor(launch_flavor);
-
-                    nub_process_t pid = DNBProcessAttachWait (waitfor_pid_name.c_str(), launch_flavor, timeout_ptr, waitfor_interval, err_str, sizeof(err_str));
+                    bool ignore_existing = false;
+                    nub_process_t pid = DNBProcessAttachWait (waitfor_pid_name.c_str(), launch_flavor, ignore_existing, timeout_ptr, waitfor_interval, err_str, sizeof(err_str));
                     g_pid = pid;
 
                     if (pid == INVALID_NUB_PROCESS)