summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarc Orr <marc.orr@gmail.com>2012-07-10 22:51:54 -0700
committerMarc Orr <marc.orr@gmail.com>2012-07-10 22:51:54 -0700
commit387f843d513dd80554cb6361da36ba805dfbcea2 (patch)
tree17c32aeac4482a5e451af779f412cd8f94ea81f7 /src
parent52540b1b785aac9b307dfcc976527d94899deb94 (diff)
downloadgem5-387f843d513dd80554cb6361da36ba805dfbcea2.tar.xz
syscall emulation: Add the futex system call.
Diffstat (limited to 'src')
-rw-r--r--src/arch/alpha/linux/linux.hh4
-rw-r--r--src/arch/x86/linux/syscalls.cc2
-rw-r--r--src/kern/linux/linux.hh6
-rw-r--r--src/sim/syscall_emul.hh81
-rw-r--r--src/sim/system.hh3
5 files changed, 95 insertions, 1 deletions
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<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),
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 <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
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<uint64_t, std::list<ThreadContext *> * > futexMap;
+
};