diff --git a/src/arch/x86/linux/syscalls.cc b/src/arch/x86/linux/syscalls.cc --- a/src/arch/x86/linux/syscalls.cc +++ b/src/arch/x86/linux/syscalls.cc @@ -415,7 +415,7 @@ /* 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/sim/syscall_emul.hh b/src/sim/syscall_emul.hh --- a/src/sim/syscall_emul.hh +++ b/src/sim/syscall_emul.hh @@ -334,6 +334,10 @@ SyscallReturn cloneFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc); +/// Futex system call +SyscallReturn futexFunc(SyscallDesc *desc, int callnum, + LiveProcess *p, ThreadContext *tc); + /// 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/syscall_emul.cc b/src/sim/syscall_emul.cc --- a/src/sim/syscall_emul.cc +++ b/src/sim/syscall_emul.cc @@ -851,3 +851,92 @@ } } + +//sys_futex +//Implemented by Daniel Sanchez +//Used by printf's in multi-threaded apps + +//see +#ifndef FUTEX_WAIT +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +//#define EAGAIN 35 /* Try again */ alpha +#define EAGAIN 11 /* Try again */ +#define EWOULDBLOCK EAGAIN +#endif + +//Maintain a map on which thread contexts are waiting per mutex +static std::map * > futexMap; + +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; + + IntReg uaddr = process->getSyscallArg(tc, index_uaddr); + IntReg op = process->getSyscallArg(tc, index_op); + IntReg val = process->getSyscallArg(tc, index_val); + IntReg timeout = process->getSyscallArg(tc, index_timeout); + + DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n", + uaddr, op, val); + + if (op == 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(IntReg)]; + tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(IntReg)); + IntReg mem_val = *((uint32_t *)buf); + delete buf; + + if(val != mem_val) { + DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, " + "expected: %d\n", mem_val, val); + return -EWOULDBLOCK; + } + + // Queue the thread context + std::list * tcWaitList; + if (futexMap.count(uaddr)) { + tcWaitList = futexMap.find(uaddr)->second; + } else { + tcWaitList = new std::list(); + futexMap.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 == FUTEX_WAKE){ + int wokenUp = 0; + std::list * tcWaitList; + if (futexMap.count(uaddr)) { + tcWaitList = futexMap.find(uaddr)->second; + while (tcWaitList->size() > 0 && wokenUp < val) { + tcWaitList->front()->activate(); + tcWaitList->pop_front(); + wokenUp++; + } + if(tcWaitList->empty()) { + futexMap.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; + } + +}