sim-se: (Re)add support for retrying system calls.
The previous incarnation of this support used faults to make the CPU reexecute the system call instruction again and again to prevent emulating/passing through blocking system calls from blocking gem5 as a whole. That support was accidentally removed a while ago. This new version suspends the thread context executing the system call, and periodically wakes it up to retry using a periodically scheduled event. Jira Issue: https://gem5.atlassian.net/browse/GEM5-1123 Change-Id: I4fad23bd119021df23fe6082891fbcd0ee8fb839 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/54024 Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com> Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
#include "sim/syscall_desc.hh"
|
||||
|
||||
#include "base/types.hh"
|
||||
#include "sim/eventq.hh"
|
||||
#include "sim/syscall_debug_macros.hh"
|
||||
|
||||
namespace gem5
|
||||
@@ -45,12 +46,58 @@ SyscallDesc::doSyscall(ThreadContext *tc)
|
||||
SyscallReturn retval = executor(this, tc);
|
||||
|
||||
if (retval.needsRetry()) {
|
||||
DPRINTF_SYSCALL(Base, "Needs retry.\n", name());
|
||||
} else if (retval.suppressed()) {
|
||||
// Suspend this ThreadContext while the syscall is pending.
|
||||
tc->suspend();
|
||||
|
||||
DPRINTF_SYSCALL(Base, "%s needs retry.\n", name());
|
||||
setupRetry(tc);
|
||||
return;
|
||||
}
|
||||
|
||||
handleReturn(tc, retval);
|
||||
}
|
||||
|
||||
void
|
||||
SyscallDesc::retrySyscall(ThreadContext *tc)
|
||||
{
|
||||
DPRINTF_SYSCALL(Base, "Retrying %s...\n", dumper(name(), tc));
|
||||
|
||||
SyscallReturn retval = executor(this, tc);
|
||||
|
||||
if (retval.needsRetry()) {
|
||||
DPRINTF_SYSCALL(Base, "%s still needs retry.\n", name());
|
||||
setupRetry(tc);
|
||||
return;
|
||||
}
|
||||
|
||||
// We're done retrying, so reactivate this ThreadContext.
|
||||
tc->activate();
|
||||
|
||||
handleReturn(tc, retval);
|
||||
}
|
||||
|
||||
void
|
||||
SyscallDesc::setupRetry(ThreadContext *tc)
|
||||
{
|
||||
// Create an event which will retry the system call later.
|
||||
auto retry = [this, tc]() { retrySyscall(tc); };
|
||||
auto *event = new EventFunctionWrapper(retry, name(), true);
|
||||
|
||||
// Schedule it in about 100 CPU cycles. That will give other contexts
|
||||
// a chance to execute a bit of code before trying again.
|
||||
auto *cpu = tc->getCpuPtr();
|
||||
curEventQueue()->schedule(event,
|
||||
curTick() + cpu->cyclesToTicks(Cycles(100)));
|
||||
}
|
||||
|
||||
void
|
||||
SyscallDesc::handleReturn(ThreadContext *tc, const SyscallReturn &ret)
|
||||
{
|
||||
if (ret.suppressed()) {
|
||||
DPRINTF_SYSCALL(Base, "No return value.\n", name());
|
||||
} else {
|
||||
returnInto(tc, retval);
|
||||
DPRINTF_SYSCALL(Base, "Returned %d.\n", retval.encodedValue());
|
||||
returnInto(tc, ret);
|
||||
DPRINTF_SYSCALL(Base, "Returned %d.\n", ret.encodedValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -95,11 +95,16 @@ class SyscallDesc
|
||||
_name(name), _num(num), executor(exec), dumper(dump)
|
||||
{}
|
||||
|
||||
void retrySyscall(ThreadContext *tc);
|
||||
|
||||
private:
|
||||
/** System call name (e.g., open, mmap, clone, socket, etc.) */
|
||||
std::string _name;
|
||||
int _num;
|
||||
|
||||
void setupRetry(ThreadContext *tc);
|
||||
void handleReturn(ThreadContext *tc, const SyscallReturn &ret);
|
||||
|
||||
/** Mechanism for ISAs to connect to the emul function definitions */
|
||||
Executor executor;
|
||||
Dumper dumper;
|
||||
|
||||
Reference in New Issue
Block a user