summaryrefslogtreecommitdiff
path: root/src/sim/syscall_emul.cc
diff options
context:
space:
mode:
authorBrandon Potter <Brandon.Potter@amd.com>2017-03-01 14:52:23 -0600
committerBrandon Potter <Brandon.Potter@amd.com>2017-03-09 22:42:45 +0000
commit2c1286865fc2542a0586ca4ff40b00765d17b348 (patch)
tree320c9e379c843a49a49555ccc4e075d3a3d4bf1e /src/sim/syscall_emul.cc
parent6f7bf1b11fd9a2d7c2007fd0aca3ffa4885a215e (diff)
downloadgem5-2c1286865fc2542a0586ca4ff40b00765d17b348.tar.xz
syscall-emul: Rewrite system call exit code
The changeset does a major refactor on the exit, exit_group, and futex system calls regarding exit functionality. A FutexMap class and related structures are added into a new file. This increases code clarity by encapsulating the futex operations and the futex state into an object. Several exit conditions were added to allow the simulator to end processes under certain conditions. Also, the simulation only exits now when all processes have finished executing. Change-Id: I1ee244caa9b5586fe7375e5b9b50fd3959b9655e Reviewed-on: https://gem5-review.googlesource.com/2269 Maintainer: Jason Lowe-Power <jason@lowepower.com> Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Diffstat (limited to 'src/sim/syscall_emul.cc')
-rw-r--r--src/sim/syscall_emul.cc144
1 files changed, 97 insertions, 47 deletions
diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc
index 1441592a8..4cf17a266 100644
--- a/src/sim/syscall_emul.cc
+++ b/src/sim/syscall_emul.cc
@@ -34,6 +34,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include <csignal>
#include <iostream>
#include <string>
@@ -75,67 +76,116 @@ ignoreFunc(SyscallDesc *desc, int callnum, Process *process,
}
static void
-exitFutexWake(ThreadContext *tc, uint64_t uaddr)
-{
- std::map<uint64_t, std::list<ThreadContext *> * >
- &futex_map = tc->getSystemPtr()->futexMap;
-
- int wokenUp = 0;
- std::list<ThreadContext *> * tcWaitList;
- if (futex_map.count(uaddr)) {
- tcWaitList = futex_map.find(uaddr)->second;
- if (tcWaitList->size() > 0) {
- tcWaitList->front()->activate();
- tcWaitList->pop_front();
- wokenUp++;
+exitFutexWake(ThreadContext *tc, Addr addr, uint64_t tgid)
+{
+ // Clear value at address pointed to by thread's childClearTID field.
+ BufferArg ctidBuf(addr, sizeof(long));
+ long *ctid = (long *)ctidBuf.bufferPtr();
+ *ctid = 0;
+ ctidBuf.copyOut(tc->getMemProxy());
+
+ FutexMap &futex_map = tc->getSystemPtr()->futexMap;
+ // Wake one of the waiting threads.
+ futex_map.wakeup(addr, tgid, 1);
+}
+
+static SyscallReturn
+exitImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
+ bool group)
+{
+ int index = 0;
+ int status = p->getSyscallArg(tc, index);
+
+ System *sys = tc->getSystemPtr();
+
+ int activeContexts = 0;
+ for (auto &system: sys->systemList)
+ activeContexts += system->numRunningContexts();
+ if (activeContexts == 1) {
+ exitSimLoop("exiting with last active thread context", status & 0xff);
+ return status;
+ }
+
+ if (group)
+ *p->exitGroup = true;
+
+ if (p->childClearTID)
+ exitFutexWake(tc, p->childClearTID, p->tgid());
+
+ bool last_thread = true;
+ Process *parent = nullptr, *tg_lead = nullptr;
+ for (int i = 0; last_thread && i < sys->numContexts(); i++) {
+ Process *walk;
+ if (!(walk = sys->threadContexts[i]->getProcessPtr()))
+ continue;
+
+ /**
+ * Threads in a thread group require special handing. For instance,
+ * we send the SIGCHLD signal so that it appears that it came from
+ * the head of the group. We also only delete file descriptors if
+ * we are the last thread in the thread group.
+ */
+ if (walk->pid() == p->tgid())
+ tg_lead = walk;
+
+ if ((sys->threadContexts[i]->status() != ThreadContext::Halted)
+ && (walk != p)) {
+ /**
+ * Check if we share thread group with the pointer; this denotes
+ * that we are not the last thread active in the thread group.
+ * Note that setting this to false also prevents further
+ * iterations of the loop.
+ */
+ if (walk->tgid() == p->tgid())
+ last_thread = false;
+
+ /**
+ * A corner case exists which involves execve(). After execve(),
+ * the execve will enable SIGCHLD in the process. The problem
+ * occurs when the exiting process is the root process in the
+ * system; there is no parent to receive the signal. We obviate
+ * this problem by setting the root process' ppid to zero in the
+ * Python configuration files. We really should handle the
+ * root/execve specific case more gracefully.
+ */
+ if (*p->sigchld && (p->ppid() != 0) && (walk->pid() == p->ppid()))
+ parent = walk;
}
- if (tcWaitList->empty()) {
- futex_map.erase(uaddr);
- delete tcWaitList;
+ }
+
+ if (last_thread) {
+ if (parent) {
+ assert(tg_lead);
+ sys->signalList.push_back(BasicSignal(tg_lead, parent, SIGCHLD));
+ }
+
+ /**
+ * Run though FD array of the exiting process and close all file
+ * descriptors except for the standard file descriptors.
+ * (The standard file descriptors are shared with gem5.)
+ */
+ for (int i = 0; i < p->fds->getSize(); i++) {
+ if ((*p->fds)[i])
+ p->fds->closeFDEntry(i);
}
}
- DPRINTF(SyscallVerbose, "exit: FUTEX_WAKE, activated %d waiting "
- "thread contexts\n", wokenUp);
+
+ tc->halt();
+ return status;
}
SyscallReturn
exitFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
{
- if (p->system->numRunningContexts() == 1 && !p->childClearTID) {
- // Last running free-parent context; exit simulator.
- int index = 0;
- exitSimLoop("target called exit()",
- p->getSyscallArg(tc, index) & 0xff);
- } else {
- if (p->childClearTID)
- exitFutexWake(tc, p->childClearTID);
- tc->halt();
- }
-
- return 1;
+ return exitImpl(desc, callnum, p, tc, false);
}
-
SyscallReturn
-exitGroupFunc(SyscallDesc *desc, int callnum, Process *process,
- ThreadContext *tc)
+exitGroupFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
{
- // halt all threads belonging to this process
- for (auto i: process->contextIds) {
- process->system->getThreadContext(i)->halt();
- }
-
- if (!process->system->numRunningContexts()) {
- // all threads belonged to this process... exit simulator
- int index = 0;
- exitSimLoop("target called exit()",
- process->getSyscallArg(tc, index) & 0xff);
- }
-
- return 1;
+ return exitImpl(desc, callnum, p, tc, true);
}
-
SyscallReturn
getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{