From 387f843d513dd80554cb6361da36ba805dfbcea2 Mon Sep 17 00:00:00 2001 From: Marc Orr Date: Tue, 10 Jul 2012 22:51:54 -0700 Subject: [PATCH] syscall emulation: Add the futex system call. --- src/arch/alpha/linux/linux.hh | 4 ++ src/arch/x86/linux/syscalls.cc | 2 +- src/kern/linux/linux.hh | 6 +++ src/sim/syscall_emul.hh | 81 ++++++++++++++++++++++++++++++++++ src/sim/system.hh | 3 ++ 5 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/arch/alpha/linux/linux.hh b/src/arch/alpha/linux/linux.hh index 3304816c3..6197b8d45 100644 --- a/src/arch/alpha/linux/linux.hh +++ b/src/arch/alpha/linux/linux.hh @@ -142,6 +142,10 @@ class AlphaLinux : public Linux uint64_t freehigh; /* Available high memory size */ uint64_t mem_unit; /* Memory unit size in bytes */ } tgt_sysinfo; + + // For futex system call + static const unsigned TGT_EAGAIN = 35; + static const unsigned TGT_EWOULDBLOCK = TGT_EAGAIN; }; #endif // __ALPHA_ALPHA_LINUX_LINUX_HH__ diff --git a/src/arch/x86/linux/syscalls.cc b/src/arch/x86/linux/syscalls.cc index 119152e86..e9322f5eb 100644 --- a/src/arch/x86/linux/syscalls.cc +++ b/src/arch/x86/linux/syscalls.cc @@ -415,7 +415,7 @@ SyscallDesc X86_64LinuxProcess::syscallDescs[] = { /* 199 */ SyscallDesc("fremovexattr", unimplementedFunc), /* 200 */ SyscallDesc("tkill", unimplementedFunc), /* 201 */ SyscallDesc("time", timeFunc), - /* 202 */ SyscallDesc("futex", ignoreFunc), + /* 202 */ SyscallDesc("futex", futexFunc), /* 203 */ SyscallDesc("sched_setaffinity", unimplementedFunc), /* 204 */ SyscallDesc("sched_getaffinity", unimplementedFunc), /* 205 */ SyscallDesc("set_thread_area", unimplementedFunc), diff --git a/src/kern/linux/linux.hh b/src/kern/linux/linux.hh index 30ebdbb4a..5721e5a58 100644 --- a/src/kern/linux/linux.hh +++ b/src/kern/linux/linux.hh @@ -171,6 +171,12 @@ class Linux : public OperatingSystem static int openSpecialFile(std::string path, LiveProcess *process, ThreadContext *tc); static std::string procMeminfo(LiveProcess *process, ThreadContext *tc); + // For futex system call + static const unsigned TGT_FUTEX_WAIT = 0; + static const unsigned TGT_FUTEX_WAKE = 1; + static const unsigned TGT_EAGAIN = 11; + static const unsigned TGT_EWOULDBLOCK = TGT_EAGAIN; + }; // class Linux #endif // __LINUX_HH__ diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh index 87899abca..c174fde57 100644 --- a/src/sim/syscall_emul.hh +++ b/src/sim/syscall_emul.hh @@ -334,6 +334,87 @@ SyscallReturn getegidFunc(SyscallDesc *desc, int num, SyscallReturn cloneFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc); +/// Futex system call +/// Implemented by Daniel Sanchez +/// Used by printf's in multi-threaded apps +template +SyscallReturn +futexFunc(SyscallDesc *desc, int callnum, LiveProcess *process, + ThreadContext *tc) +{ + int index_uaddr = 0; + int index_op = 1; + int index_val = 2; + int index_timeout = 3; + + uint64_t uaddr = process->getSyscallArg(tc, index_uaddr); + int op = process->getSyscallArg(tc, index_op); + int val = process->getSyscallArg(tc, index_val); + uint64_t timeout = process->getSyscallArg(tc, index_timeout); + + std::map * > + &futex_map = tc->getSystemPtr()->futexMap; + + DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n", + uaddr, op, val); + + + if (op == OS::TGT_FUTEX_WAIT) { + if (timeout != 0) { + warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;" + "we'll wait indefinitely"); + } + + uint8_t *buf = new uint8_t[sizeof(int)]; + tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int)); + int mem_val = *((int *)buf); + delete buf; + + if(val != mem_val) { + DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, " + "expected: %d\n", mem_val, val); + return -OS::TGT_EWOULDBLOCK; + } + + // Queue the thread context + std::list * tcWaitList; + if (futex_map.count(uaddr)) { + tcWaitList = futex_map.find(uaddr)->second; + } else { + tcWaitList = new std::list(); + futex_map.insert(std::pair< uint64_t, + std::list * >(uaddr, tcWaitList)); + } + tcWaitList->push_back(tc); + DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling " + "thread context\n"); + tc->suspend(); + return 0; + } else if (op == OS::TGT_FUTEX_WAKE){ + int wokenUp = 0; + std::list * tcWaitList; + if (futex_map.count(uaddr)) { + tcWaitList = futex_map.find(uaddr)->second; + while (tcWaitList->size() > 0 && wokenUp < val) { + tcWaitList->front()->activate(); + tcWaitList->pop_front(); + wokenUp++; + } + if(tcWaitList->empty()) { + futex_map.erase(uaddr); + delete tcWaitList; + } + } + DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting " + "thread contexts\n", wokenUp); + return wokenUp; + } else { + warn("sys_futex: op %d is not implemented, just returning..."); + return 0; + } + +} + /// Pseudo Funcs - These functions use a different return convension, /// returning a second value in a register other than the normal return register diff --git a/src/sim/system.hh b/src/sim/system.hh index 6dc8d73e0..4348ecaca 100644 --- a/src/sim/system.hh +++ b/src/sim/system.hh @@ -400,6 +400,9 @@ class System : public MemObject static void printSystems(); + // For futex system call + std::map * > futexMap; + };