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.cc141
1 files changed, 46 insertions, 95 deletions
diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc
index c6b89b0c7..07899ec9a 100644
--- a/src/sim/syscall_emul.cc
+++ b/src/sim/syscall_emul.cc
@@ -74,18 +74,41 @@ ignoreFunc(SyscallDesc *desc, int callnum, Process *process,
return 0;
}
+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++;
+ }
+ if (tcWaitList->empty()) {
+ futex_map.erase(uaddr);
+ delete tcWaitList;
+ }
+ }
+ DPRINTF(SyscallVerbose, "exit: FUTEX_WAKE, activated %d waiting "
+ "thread contexts\n", wokenUp);
+}
SyscallReturn
-exitFunc(SyscallDesc *desc, int callnum, Process *process,
- ThreadContext *tc)
+exitFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
{
- if (process->system->numRunningContexts() == 1) {
- // Last running context... exit simulator
+ if (p->system->numRunningContexts() == 1 && !p->childClearTID) {
+ // Last running free-parent context; exit simulator.
int index = 0;
exitSimLoop("target called exit()",
- process->getSyscallArg(tc, index) & 0xff);
+ p->getSyscallArg(tc, index) & 0xff);
} else {
- // other running threads... just halt this one
+ if (p->childClearTID)
+ exitFutexWake(tc, p->childClearTID);
tc->halt();
}
@@ -130,11 +153,12 @@ brkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
// in Linux at least, brk(0) returns the current break value
// (note that the syscall and the glibc function have different behavior)
if (new_brk == 0)
- return p->brk_point;
+ return p->memState->brkPoint;
- if (new_brk > p->brk_point) {
+ if (new_brk > p->memState->brkPoint) {
// might need to allocate some new pages
- for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
+ for (ChunkGenerator gen(p->memState->brkPoint,
+ new_brk - p->memState->brkPoint,
PageBytes); !gen.done(); gen.next()) {
if (!p->pTable->translate(gen.addr()))
p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes);
@@ -159,12 +183,22 @@ brkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
}
}
- p->brk_point = new_brk;
+ p->memState->brkPoint = new_brk;
DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n",
- p->brk_point);
- return p->brk_point;
+ p->memState->brkPoint);
+ return p->memState->brkPoint;
}
+SyscallReturn
+setTidAddressFunc(SyscallDesc *desc, int callnum, Process *process,
+ ThreadContext *tc)
+{
+ int index = 0;
+ uint64_t tidPtr = process->getSyscallArg(tc, index);
+
+ process->childClearTID = tidPtr;
+ return process->pid();
+}
SyscallReturn
closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
@@ -860,89 +894,6 @@ getegidFunc(SyscallDesc *desc, int callnum, Process *process,
return process->egid();
}
-
-SyscallReturn
-cloneFunc(SyscallDesc *desc, int callnum, Process *process,
- ThreadContext *tc)
-{
- int index = 0;
- IntReg flags = process->getSyscallArg(tc, index);
- IntReg newStack = process->getSyscallArg(tc, index);
-
- DPRINTF(SyscallVerbose, "In sys_clone:\n");
- DPRINTF(SyscallVerbose, " Flags=%llx\n", flags);
- DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack);
-
-
- if (flags != 0x10f00) {
- warn("This sys_clone implementation assumes flags "
- "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD "
- "(0x10f00), and may not work correctly with given flags "
- "0x%llx\n", flags);
- }
-
- ThreadContext* ctc; // child thread context
- if ((ctc = process->findFreeContext())) {
- DPRINTF(SyscallVerbose, " Found unallocated thread context\n");
-
- ctc->clearArchRegs();
-
- // Arch-specific cloning code
- #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA
- // Cloning the misc. regs for these archs is enough
- TheISA::copyMiscRegs(tc, ctc);
- #elif THE_ISA == SPARC_ISA
- TheISA::copyRegs(tc, ctc);
-
- // TODO: Explain what this code actually does :-)
- ctc->setIntReg(NumIntArchRegs + 6, 0);
- ctc->setIntReg(NumIntArchRegs + 4, 0);
- ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2);
- ctc->setIntReg(NumIntArchRegs + 5, NWindows);
- ctc->setMiscReg(MISCREG_CWP, 0);
- ctc->setIntReg(NumIntArchRegs + 7, 0);
- ctc->setMiscRegNoEffect(MISCREG_TL, 0);
- ctc->setMiscReg(MISCREG_ASI, ASI_PRIMARY);
-
- for (int y = 8; y < 32; y++)
- ctc->setIntReg(y, tc->readIntReg(y));
- #elif THE_ISA == ARM_ISA
- TheISA::copyRegs(tc, ctc);
- #else
- fatal("sys_clone is not implemented for this ISA\n");
- #endif
-
- // Set up stack register
- ctc->setIntReg(TheISA::StackPointerReg, newStack);
-
- // Set up syscall return values in parent and child
- ctc->setIntReg(ReturnValueReg, 0); // return value, child
-
- // Alpha needs SyscallSuccessReg=0 in child
- #if THE_ISA == ALPHA_ISA
- ctc->setIntReg(TheISA::SyscallSuccessReg, 0);
- #endif
-
- // In SPARC/Linux, clone returns 0 on pseudo-return register if
- // parent, non-zero if child
- #if THE_ISA == SPARC_ISA
- tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0);
- ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
- #endif
-
- ctc->pcState(tc->nextInstAddr());
-
- ctc->activate();
-
- // Should return nonzero child TID in parent's syscall return register,
- // but for our pthread library any non-zero value will work
- return 1;
- } else {
- fatal("Called sys_clone, but no unallocated thread contexts found!\n");
- return 0;
- }
-}
-
SyscallReturn
fallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
{