syscall emulation: Add the futex system call.
authorMarc Orr <marc.orr@gmail.com>
Wed, 11 Jul 2012 05:51:54 +0000 (22:51 -0700)
committerMarc Orr <marc.orr@gmail.com>
Wed, 11 Jul 2012 05:51:54 +0000 (22:51 -0700)
src/arch/alpha/linux/linux.hh
src/arch/x86/linux/syscalls.cc
src/kern/linux/linux.hh
src/sim/syscall_emul.hh
src/sim/system.hh

index 3304816c34864f3c62d458b34ece7557f6ad2f5f..6197b8d456a2707b8483d27c5cc6edbe25b5dbb3 100644 (file)
@@ -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__
index 119152e867d0cd4b40daa9c8b6b4aa977962c0cd..e9322f5eb775307762d247523a5b16d0cbf5d86c 100644 (file)
@@ -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),
index 30ebdbb4a8821698715145bf371addee8b303839..5721e5a58c6f5230b5866f97157db85988387565 100644 (file)
@@ -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__
index 87899abca34bda7168f5f134fe120689f5ba2bd5..c174fde576ce4252f04379d66a89572ad48fa044 100644 (file)
@@ -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
index 6dc8d73e0cb752a2ba895ef9b0c892c38bafe31c..4348ecaca4a699f98703632bf6f6ab77fdf5cba5 100644 (file)
@@ -400,6 +400,9 @@ class System : public MemObject
 
     static void printSystems();
 
+    // For futex system call
+    std::map<uint64_t, std::list<ThreadContext *> * > futexMap;
+
 
 };