Files
Philip DePetro 7b336dcfce [lldb] Allow forks to occur in expression evaluation (#184815)
@jimingham You had suggested to @clayborg that we should call DidFork(),
DidVFork() and DidVForkDone() after a corresponding stop in expression
evaluation. Those functions require parameters that are private to the
specific child StopInfo class. I went with reusing the existing
StopInfo::PerformAction() virtual function, rather than create a new one
just for this purpose.
2026-04-24 11:48:17 -07:00

83 lines
2.2 KiB
C++

#include <pthread.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
int fork_and_return(int value, bool use_vfork) {
pid_t pid = use_vfork ? vfork() : fork();
if (pid == -1)
return -1;
if (pid == 0) {
// child
_exit(value);
}
// parent
int status;
waitpid(pid, &status, 0);
return WEXITSTATUS(status);
}
int fork_and_return_trap(int value) {
pid_t pid = fork();
if (pid == -1)
return -1;
if (pid == 0) {
// child returning from the JITed function wrapper will hit a trap
// instruction and terminate with SIGTRAP.
return value;
}
// parent
int status;
waitpid(pid, &status, 0);
if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTRAP) {
return 1; // Success: child terminated with SIGTRAP
}
return 0; // Failure
}
// Mutex-based synchronization for concurrent fork test.
// The main thread holds the mutex, starts a helper thread that waits
// on the mutex then forks, and the expression releases the mutex and
// waits to reacquire it - forcing the fork to happen on a different
// thread while the expression is running.
static pthread_mutex_t g_fork_mutex = PTHREAD_MUTEX_INITIALIZER;
static pid_t g_child_pid = -1;
static void *concurrent_fork_thread(void *arg) {
// Wait until the expression releases the mutex.
pthread_mutex_lock(&g_fork_mutex);
g_child_pid = fork();
if (g_child_pid == 0) {
// child
_exit(42);
}
// parent - release mutex so expression can reacquire.
pthread_mutex_unlock(&g_fork_mutex);
return nullptr;
}
// Called as an expression while another thread forks.
// The caller must hold g_fork_mutex before evaluating this expression.
int expr_with_concurrent_fork() {
pthread_t t;
pthread_create(&t, nullptr, concurrent_fork_thread, nullptr);
// Release mutex - lets the helper thread proceed to fork.
pthread_mutex_unlock(&g_fork_mutex);
// Wait for the helper thread to finish (it forks and unlocks).
pthread_join(t, nullptr);
// Reacquire mutex to synchronize.
pthread_mutex_lock(&g_fork_mutex);
// Return the child PID so the test can verify fork happened.
return (int)g_child_pid;
}
int main() {
pthread_mutex_lock(&g_fork_mutex);
int x = 42;
return 0; // break here
}