labath created this revision. labath added reviewers: jingham, mgorny. Herald added a project: All. labath requested review of this revision. Herald added a project: LLDB.
Step over thread plans were claiming to explain the fork stop reasons, which prevented the default fork logic (detaching from the child process) from kicking in. This patch changes that. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D141605 Files: lldb/source/Target/ThreadPlan.cpp lldb/test/API/functionalities/fork/resumes-child/Makefile lldb/test/API/functionalities/fork/resumes-child/TestForkResumesChild.py lldb/test/API/functionalities/fork/resumes-child/main.cpp Index: lldb/test/API/functionalities/fork/resumes-child/main.cpp =================================================================== --- /dev/null +++ lldb/test/API/functionalities/fork/resumes-child/main.cpp @@ -0,0 +1,29 @@ +#include <cassert> +#include <chrono> +#include <cstdlib> +#include <sys/wait.h> +#include <thread> +#include <unistd.h> + +int main() { + pid_t fork_result = fork(); // break here + assert(fork_result >= 0); + if (fork_result == 0) { + // child + _exit(47); + } + // parent + // Use polling to avoid blocking if the child is not actually resumed. + auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(10); + std::chrono::milliseconds poll_interval{10}; + while (std::chrono::steady_clock::now() < deadline) { + int status; + pid_t waitpid_result = waitpid(fork_result, &status, WNOHANG); + if (waitpid_result == fork_result) + return 0; + assert(waitpid_result == 0); + std::this_thread::sleep_for(poll_interval); + poll_interval *= 2; + } + abort(); +} Index: lldb/test/API/functionalities/fork/resumes-child/TestForkResumesChild.py =================================================================== --- /dev/null +++ lldb/test/API/functionalities/fork/resumes-child/TestForkResumesChild.py @@ -0,0 +1,22 @@ +""" +Make sure that the fork child keeps running. +""" + + + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * + + +class TestForkResumesChild(TestBase): + + NO_DEBUG_INFO_TESTCASE = True + + @skipIfWindows + def test_step_over_fork(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.cpp")) + self.runCmd("next") + self.expect("continue", substrs = ["exited with status = 0"]) Index: lldb/test/API/functionalities/fork/resumes-child/Makefile =================================================================== --- /dev/null +++ lldb/test/API/functionalities/fork/resumes-child/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules Index: lldb/source/Target/ThreadPlan.cpp =================================================================== --- lldb/source/Target/ThreadPlan.cpp +++ lldb/source/Target/ThreadPlan.cpp @@ -171,6 +171,9 @@ case eStopReasonExec: case eStopReasonThreadExiting: case eStopReasonInstrumentation: + case eStopReasonFork: + case eStopReasonVFork: + case eStopReasonVForkDone: return true; default: return false;
Index: lldb/test/API/functionalities/fork/resumes-child/main.cpp =================================================================== --- /dev/null +++ lldb/test/API/functionalities/fork/resumes-child/main.cpp @@ -0,0 +1,29 @@ +#include <cassert> +#include <chrono> +#include <cstdlib> +#include <sys/wait.h> +#include <thread> +#include <unistd.h> + +int main() { + pid_t fork_result = fork(); // break here + assert(fork_result >= 0); + if (fork_result == 0) { + // child + _exit(47); + } + // parent + // Use polling to avoid blocking if the child is not actually resumed. + auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(10); + std::chrono::milliseconds poll_interval{10}; + while (std::chrono::steady_clock::now() < deadline) { + int status; + pid_t waitpid_result = waitpid(fork_result, &status, WNOHANG); + if (waitpid_result == fork_result) + return 0; + assert(waitpid_result == 0); + std::this_thread::sleep_for(poll_interval); + poll_interval *= 2; + } + abort(); +} Index: lldb/test/API/functionalities/fork/resumes-child/TestForkResumesChild.py =================================================================== --- /dev/null +++ lldb/test/API/functionalities/fork/resumes-child/TestForkResumesChild.py @@ -0,0 +1,22 @@ +""" +Make sure that the fork child keeps running. +""" + + + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * + + +class TestForkResumesChild(TestBase): + + NO_DEBUG_INFO_TESTCASE = True + + @skipIfWindows + def test_step_over_fork(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.cpp")) + self.runCmd("next") + self.expect("continue", substrs = ["exited with status = 0"]) Index: lldb/test/API/functionalities/fork/resumes-child/Makefile =================================================================== --- /dev/null +++ lldb/test/API/functionalities/fork/resumes-child/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules Index: lldb/source/Target/ThreadPlan.cpp =================================================================== --- lldb/source/Target/ThreadPlan.cpp +++ lldb/source/Target/ThreadPlan.cpp @@ -171,6 +171,9 @@ case eStopReasonExec: case eStopReasonThreadExiting: case eStopReasonInstrumentation: + case eStopReasonFork: + case eStopReasonVFork: + case eStopReasonVForkDone: return true; default: return false;
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits