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 <noreply+kokoro@google.com>
Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu>
Reviewed-by: Matt Sinclair <mattdsinclair@gmail.com>
Maintainer: Matt Sinclair <mattdsinclair@gmail.com>
This commit is contained in:
Kyle Roarty
2021-07-20 15:02:16 -05:00
committed by Matt Sinclair
parent 078dc689b9
commit 906bb599d4
4 changed files with 34 additions and 0 deletions

View File

@@ -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());
}

View File

@@ -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<ContextID> vforkContexts;
// Track how many system calls are executed
statistics::Scalar numSyscalls;
};

View File

@@ -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();
/**

View File

@@ -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