diff options
author | Brandon Potter <Brandon.Potter@amd.com> | 2017-03-01 14:52:23 -0600 |
---|---|---|
committer | Brandon Potter <Brandon.Potter@amd.com> | 2017-03-09 22:42:45 +0000 |
commit | 2c1286865fc2542a0586ca4ff40b00765d17b348 (patch) | |
tree | 320c9e379c843a49a49555ccc4e075d3a3d4bf1e /src/sim/syscall_emul.cc | |
parent | 6f7bf1b11fd9a2d7c2007fd0aca3ffa4885a215e (diff) | |
download | gem5-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.cc | 144 |
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) { |