summaryrefslogtreecommitdiff
path: root/src/sim/syscall_emul.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/sim/syscall_emul.cc')
-rw-r--r--src/sim/syscall_emul.cc75
1 files changed, 49 insertions, 26 deletions
diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc
index 25e0b6856..fbfe21a93 100644
--- a/src/sim/syscall_emul.cc
+++ b/src/sim/syscall_emul.cc
@@ -102,28 +102,6 @@ exitImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
System *sys = tc->getSystemPtr();
- int activeContexts = 0;
- for (auto &system: sys->systemList)
- activeContexts += system->numRunningContexts();
- if (activeContexts == 1) {
- /**
- * Even though we are terminating the final thread context, dist-gem5
- * requires the simulation to remain active and provide
- * synchronization messages to the switch process. So we just halt
- * the last thread context and return. The simulation will be
- * terminated by dist-gem5 in a coordinated manner once all nodes
- * have signaled their readiness to exit. For non dist-gem5
- * simulations, readyToExit() always returns true.
- */
- if (!DistIface::readyToExit(0)) {
- tc->halt();
- return status;
- }
-
- exitSimLoop("exiting with last active thread context", status & 0xff);
- return status;
- }
-
if (group)
*p->exitGroup = true;
@@ -146,16 +124,34 @@ exitImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
if (walk->pid() == p->tgid())
tg_lead = walk;
- if ((sys->threadContexts[i]->status() != ThreadContext::Halted)
- && (walk != p)) {
+ if ((sys->threadContexts[i]->status() != ThreadContext::Halted) &&
+ (sys->threadContexts[i]->status() != ThreadContext::Halting) &&
+ (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;
+ if (walk->tgid() == p->tgid()) {
+ /**
+ * If p is trying to exit_group and both walk and p are in
+ * the same thread group (i.e., sharing the same tgid),
+ * we need to halt walk's thread context. After all threads
+ * except p are halted, p becomes the last thread in the
+ * group.
+ *
+ * If p is not doing exit_group and there exists another
+ * active thread context in the group, last_thread is
+ * set to false to prevent the parent thread from killing
+ * all threads in the group.
+ */
+ if (*(p->exitGroup)) {
+ sys->threadContexts[i]->halt();
+ } else {
+ last_thread = false;
+ }
+ }
/**
* A corner case exists which involves execve(). After execve(),
@@ -189,6 +185,33 @@ exitImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
}
tc->halt();
+
+ /**
+ * check to see if there is no more active thread in the system. If so,
+ * exit the simulation loop
+ */
+ int activeContexts = 0;
+ for (auto &system: sys->systemList)
+ activeContexts += system->numRunningContexts();
+
+ if (activeContexts == 0) {
+ /**
+ * Even though we are terminating the final thread context, dist-gem5
+ * requires the simulation to remain active and provide
+ * synchronization messages to the switch process. So we just halt
+ * the last thread context and return. The simulation will be
+ * terminated by dist-gem5 in a coordinated manner once all nodes
+ * have signaled their readiness to exit. For non dist-gem5
+ * simulations, readyToExit() always returns true.
+ */
+ if (!DistIface::readyToExit(0)) {
+ return status;
+ }
+
+ exitSimLoop("exiting with last active thread context", status & 0xff);
+ return status;
+ }
+
return status;
}