From 906bb599d4bcab9bfe31c75d7a9613c916e1b59e Mon Sep 17 00:00:00 2001 From: Kyle Roarty Date: Tue, 20 Jul 2021 15:02:16 -0500 Subject: [PATCH] sim-se: Properly handle a clone with the VFORK flag When clone is called with the VFORK flag, the calling process is suspended until the child process either exits, or calls execve. This patch adds in a new variable to Process, which is used to store the context of the calling process if this process is created through a clone with VFORK set. This patch also adds the required support in clone to suspend the calling thread, and in exitImpl and execveFunc to wake up the calling thread when the child thread calls either of those functions Change-Id: I85af67544ea1d5df7102dcff1331b5a6f6f4fa7c Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/48346 Tested-by: kokoro Reviewed-by: Bobby R. Bruce Reviewed-by: Matt Sinclair Maintainer: Matt Sinclair --- src/sim/process.cc | 7 +++++++ src/sim/process.hh | 3 +++ src/sim/syscall_emul.cc | 10 ++++++++++ src/sim/syscall_emul.hh | 14 ++++++++++++++ 4 files changed, 34 insertions(+) diff --git a/src/sim/process.cc b/src/sim/process.cc index 207c275cf2..272fc9fd12 100644 --- a/src/sim/process.cc +++ b/src/sim/process.cc @@ -174,6 +174,9 @@ Process::clone(ThreadContext *otc, ThreadContext *ntc, #endif #ifndef CLONE_THREAD #define CLONE_THREAD 0 +#endif +#ifndef CLONE_VFORK +#define CLONE_VFORK 0 #endif if (CLONE_VM & flags) { /** @@ -249,6 +252,10 @@ Process::clone(ThreadContext *otc, ThreadContext *ntc, np->exitGroup = exitGroup; } + if (CLONE_VFORK & flags) { + np->vforkContexts.push_back(otc->contextId()); + } + np->argv.insert(np->argv.end(), argv.begin(), argv.end()); np->envp.insert(np->envp.end(), envp.begin(), envp.end()); } diff --git a/src/sim/process.hh b/src/sim/process.hh index 632ba90edd..34768a0d92 100644 --- a/src/sim/process.hh +++ b/src/sim/process.hh @@ -284,6 +284,9 @@ class Process : public SimObject // Process was forked with SIGCHLD set. bool *sigchld; + // Contexts to wake up when this thread exits or calls execve + std::vector vforkContexts; + // Track how many system calls are executed statistics::Scalar numSyscalls; }; diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc index 147cb3931c..713bec42d6 100644 --- a/src/sim/syscall_emul.cc +++ b/src/sim/syscall_emul.cc @@ -193,6 +193,16 @@ exitImpl(SyscallDesc *desc, ThreadContext *tc, bool group, int status) } } + /** + * If we were a thread created by a clone with vfork set, wake up + * the thread that created us + */ + if (!p->vforkContexts.empty()) { + ThreadContext *vtc = sys->threads[p->vforkContexts.front()]; + assert(vtc->status() == ThreadContext::Suspended); + vtc->activate(); + } + tc->halt(); /** diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh index 09be700f27..8695638758 100644 --- a/src/sim/syscall_emul.hh +++ b/src/sim/syscall_emul.hh @@ -1521,6 +1521,10 @@ cloneFunc(SyscallDesc *desc, ThreadContext *tc, RegVal flags, RegVal newStack, ctc->pcState(cpc); ctc->activate(); + if (flags & OS::TGT_CLONE_VFORK) { + tc->suspend(); + } + return cp->pid(); } @@ -1997,6 +2001,16 @@ execveFunc(SyscallDesc *desc, ThreadContext *tc, } }; + /** + * If we were a thread created by a clone with vfork set, wake up + * the thread that created us + */ + if (!p->vforkContexts.empty()) { + ThreadContext *vtc = p->system->threads[p->vforkContexts.front()]; + assert(vtc->status() == ThreadContext::Suspended); + vtc->activate(); + } + /** * Note that ProcessParams is generated by swig and there are no other * examples of how to create anything but this default constructor. The