syscall emulation: Add the futex system call.
This commit is contained in:
parent
52540b1b78
commit
387f843d51
5 changed files with 95 additions and 1 deletions
|
@ -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__
|
||||
|
|
|
@ -415,7 +415,7 @@ SyscallDesc X86_64LinuxProcess::syscallDescs[] = {
|
|||
/* 199 */ SyscallDesc("fremovexattr", unimplementedFunc),
|
||||
/* 200 */ SyscallDesc("tkill", unimplementedFunc),
|
||||
/* 201 */ SyscallDesc("time", timeFunc<X86Linux64>),
|
||||
/* 202 */ SyscallDesc("futex", ignoreFunc),
|
||||
/* 202 */ SyscallDesc("futex", futexFunc<X86Linux64>),
|
||||
/* 203 */ SyscallDesc("sched_setaffinity", unimplementedFunc),
|
||||
/* 204 */ SyscallDesc("sched_getaffinity", unimplementedFunc),
|
||||
/* 205 */ SyscallDesc("set_thread_area", unimplementedFunc),
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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 <class OS>
|
||||
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<uint64_t, std::list<ThreadContext *> * >
|
||||
&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<ThreadContext *> * tcWaitList;
|
||||
if (futex_map.count(uaddr)) {
|
||||
tcWaitList = futex_map.find(uaddr)->second;
|
||||
} else {
|
||||
tcWaitList = new std::list<ThreadContext *>();
|
||||
futex_map.insert(std::pair< uint64_t,
|
||||
std::list<ThreadContext *> * >(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<ThreadContext *> * 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
|
||||
|
|
|
@ -400,6 +400,9 @@ class System : public MemObject
|
|||
|
||||
static void printSystems();
|
||||
|
||||
// For futex system call
|
||||
std::map<uint64_t, std::list<ThreadContext *> * > futexMap;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue