diff --git a/renderdoc/os/posix/android/android_process.cpp b/renderdoc/os/posix/android/android_process.cpp index a85ccf63f..9114528f6 100644 --- a/renderdoc/os/posix/android/android_process.cpp +++ b/renderdoc/os/posix/android/android_process.cpp @@ -107,7 +107,7 @@ bool StopChildAtMain(pid_t childPid) return false; } -void ResumeProcess(pid_t childPid) +void ResumeProcess(pid_t childPid, uint32_t delay) { } diff --git a/renderdoc/os/posix/apple/apple_process.cpp b/renderdoc/os/posix/apple/apple_process.cpp index 792821362..65c50783d 100644 --- a/renderdoc/os/posix/apple/apple_process.cpp +++ b/renderdoc/os/posix/apple/apple_process.cpp @@ -157,7 +157,7 @@ bool StopChildAtMain(pid_t childPid) return false; } -void ResumeProcess(pid_t childPid) +void ResumeProcess(pid_t childPid, uint32_t delay) { } diff --git a/renderdoc/os/posix/ggp/ggp_process.cpp b/renderdoc/os/posix/ggp/ggp_process.cpp index ee78b1b1c..b1110ed39 100644 --- a/renderdoc/os/posix/ggp/ggp_process.cpp +++ b/renderdoc/os/posix/ggp/ggp_process.cpp @@ -145,7 +145,7 @@ bool StopChildAtMain(pid_t childPid) return false; } -void ResumeProcess(pid_t childPid) +void ResumeProcess(pid_t childPid, uint32_t delay) { } diff --git a/renderdoc/os/posix/linux/linux_hook.cpp b/renderdoc/os/posix/linux/linux_hook.cpp index 8d44041ad..7a594c8f9 100644 --- a/renderdoc/os/posix/linux/linux_hook.cpp +++ b/renderdoc/os/posix/linux/linux_hook.cpp @@ -85,7 +85,7 @@ int GetIdentPort(pid_t childPid); void StopAtMainInChild(); bool StopChildAtMain(pid_t childPid); -void ResumeProcess(pid_t childPid); +void ResumeProcess(pid_t childPid, uint32_t delay = 0); __attribute__((visibility("default"))) pid_t fork() { diff --git a/renderdoc/os/posix/linux/linux_process.cpp b/renderdoc/os/posix/linux/linux_process.cpp index 68c3879de..0a11603b8 100644 --- a/renderdoc/os/posix/linux/linux_process.cpp +++ b/renderdoc/os/posix/linux/linux_process.cpp @@ -410,10 +410,70 @@ void StopAtMainInChild() raise(SIGSTOP); } -void ResumeProcess(pid_t childPid) +void ResumeProcess(pid_t childPid, uint32_t delaySeconds) { if(childPid != 0) { + // if we have a delay, see if the process is paused. If so then detach it but keep it stopped + // and wait to see if someone attaches + if(delaySeconds > 0) + { + uint64_t ip = get_child_ip(childPid); + + if(ip != 0) + { + // detach but stop, to allow a debugger to attach + ptrace(PTRACE_DETACH, childPid, NULL, SIGSTOP); + + rdcstr filename = StringFormat::Fmt("/proc/%u/status", childPid); + + uint64_t start_nano = get_nanotime(); + uint64_t end_nano = 0; + + const uint64_t timeoutNanoseconds = uint64_t(delaySeconds) * 1000 * 1000 * 1000; + + bool connected = false; + + // watch for a tracer to attach + do + { + usleep(10); + + rdcstr status; + FileIO::ReadAll(filename, status); + + int32_t offs = status.find("TracerPid:"); + + if(offs < 0) + break; + + status.erase(0, offs + sizeof("TracerPid:")); + status.trim(); + + end_nano = get_nanotime(); + + if(status[0] != '0') + { + RDCLOG("Debugger PID %u attached after %f seconds", atoi(status.c_str()), + double(end_nano - start_nano) / 1000000000.0); + connected = true; + break; + } + } while(end_nano - start_nano < timeoutNanoseconds); + + if(!connected) + { + RDCLOG("Timed out waiting for debugger, resuming"); + kill(childPid, SIGCONT); + } + return; + } + else + { + RDCERR("Can't delay for debugger without ptrace, check ptrace_scope value"); + } + } + // try to detach and resume the process, ignoring any errors if we weren't tracing ptrace(PTRACE_DETACH, childPid, NULL, NULL); } diff --git a/renderdoc/os/posix/posix_process.cpp b/renderdoc/os/posix/posix_process.cpp index 8b2f2cef1..ea39deec9 100644 --- a/renderdoc/os/posix/posix_process.cpp +++ b/renderdoc/os/posix/posix_process.cpp @@ -48,7 +48,7 @@ int GetIdentPort(pid_t childPid); // us check the ident port and resume. void StopAtMainInChild(); bool StopChildAtMain(pid_t childPid); -void ResumeProcess(pid_t childPid); +void ResumeProcess(pid_t childPid, uint32_t delay = 0); #if ENABLED(RDOC_APPLE) @@ -853,7 +853,7 @@ rdcpair Process::LaunchAndInjectIntoProcess( // exponential wait to get it as soon as possible ret = GetIdentPort(childPid); - ResumeProcess(ret); + ResumeProcess(childPid, opts.delayForDebugger); if(waitForExit) {