sim-se: add syscalls related to polling
authorBrandon Potter <brandon.potter@amd.com>
Wed, 18 Apr 2018 18:57:57 +0000 (14:57 -0400)
committerAnthony Gutierrez <anthony.gutierrez@amd.com>
Tue, 22 Jan 2019 02:05:48 +0000 (02:05 +0000)
Fix poll so that it will use the syscall retry capability
instead of causing a blocking call.

Add the accept and wait4 system calls.

Add polling to read to remove deadlocks that occur in the
event queue that are caused by blocking system calls.

Modify the write system call to return an error number in
case of error.

Change-Id: I0b4091a2e41e4187ebf69d63e0088f988f37d5da
Reviewed-on: https://gem5-review.googlesource.com/c/12115
Reviewed-by: Anthony Gutierrez <anthony.gutierrez@amd.com>
Maintainer: Anthony Gutierrez <anthony.gutierrez@amd.com>

13 files changed:
src/arch/alpha/linux/process.cc
src/arch/arm/freebsd/process.cc
src/arch/arm/linux/process.cc
src/arch/mips/linux/process.cc
src/arch/power/linux/process.cc
src/arch/riscv/linux/process.cc
src/arch/sparc/linux/syscalls.cc
src/arch/sparc/solaris/process.cc
src/arch/x86/linux/process.cc
src/kern/linux/linux.hh
src/sim/fd_entry.hh
src/sim/syscall_emul.cc
src/sim/syscall_emul.hh

index dbfbcaf6a6ba69134adf48c336415db3120d585a..c1162bad0d810c6a842e2c79602747d13d7e60d7 100644 (file)
@@ -128,8 +128,8 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = {
     /*  0 */ SyscallDesc("osf_syscall", unimplementedFunc),
     /*  1 */ SyscallDesc("exit", exitFunc),
     /*  2 */ SyscallDesc("fork", unimplementedFunc),
-    /*  3 */ SyscallDesc("read", readFunc),
-    /*  4 */ SyscallDesc("write", writeFunc),
+    /*  3 */ SyscallDesc("read", readFunc<AlphaLinux>),
+    /*  4 */ SyscallDesc("write", writeFunc<AlphaLinux>),
     /*  5 */ SyscallDesc("osf_old_open", unimplementedFunc),
     /*  6 */ SyscallDesc("close", closeFunc),
     /*  7 */ SyscallDesc("osf_wait4", unimplementedFunc),
index 1ecbdd6786915cb2eaa321d209ec519f692f7df7..e6aa74068b590e2426f83a04ef432d68e709849a 100644 (file)
@@ -659,8 +659,8 @@ static SyscallDesc syscallDescs64[] = {
     /*    0 */ SyscallDesc("unused#000", unimplementedFunc),
     /*    1 */ SyscallDesc("exit", exitFunc),
     /*    2 */ SyscallDesc("unused#002", unimplementedFunc),
-    /*    3 */ SyscallDesc("read", readFunc),
-    /*    4 */ SyscallDesc("write", writeFunc),
+    /*    3 */ SyscallDesc("read", readFunc<ArmFreebsd64>),
+    /*    4 */ SyscallDesc("write", writeFunc<ArmFreebsd64>),
     /*    5 */ SyscallDesc("unused#005", unimplementedFunc),
     /*    6 */ SyscallDesc("unused#006", unimplementedFunc),
     /*    7 */ SyscallDesc("unused#007", unimplementedFunc),
index 61caa456b407af5be541ff0a982cda96502e9a3b..a7ec70e2506ac1d3a1f422f55dcc3b6b0cdb69b6 100644 (file)
@@ -126,8 +126,8 @@ static SyscallDesc syscallDescs32[] = {
     /*  0 */ SyscallDesc("syscall", unimplementedFunc),
     /*  1 */ SyscallDesc("exit", exitFunc),
     /*  2 */ SyscallDesc("fork", unimplementedFunc),
-    /*  3 */ SyscallDesc("read", readFunc),
-    /*  4 */ SyscallDesc("write", writeFunc),
+    /*  3 */ SyscallDesc("read", readFunc<ArmLinux32>),
+    /*  4 */ SyscallDesc("write", writeFunc<ArmLinux32>),
     /*  5 */ SyscallDesc("open", openFunc<ArmLinux32>),
     /*  6 */ SyscallDesc("close", closeFunc),
     /*  7 */ SyscallDesc("unused#7", unimplementedFunc),
@@ -567,8 +567,8 @@ static SyscallDesc syscallDescs64[] = {
     /*   61 */ SyscallDesc("getdents64", unimplementedFunc),
 #endif
     /*   62 */ SyscallDesc("llseek", lseekFunc),
-    /*   63 */ SyscallDesc("read", readFunc),
-    /*   64 */ SyscallDesc("write", writeFunc),
+    /*   63 */ SyscallDesc("read", readFunc<ArmLinux64>),
+    /*   64 */ SyscallDesc("write", writeFunc<ArmLinux64>),
     /*   65 */ SyscallDesc("readv", unimplementedFunc),
     /*   66 */ SyscallDesc("writev", writevFunc<ArmLinux64>),
     /*   67 */ SyscallDesc("pread64", unimplementedFunc),
index b36a26fbff6213befafc6a31bbd5940fd474ca97..b1c09a5f1cbea4b29b1f65f3821c6c8e6697439c 100644 (file)
@@ -141,8 +141,8 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = {
     /*  0 */ SyscallDesc("syscall", unimplementedFunc),
     /*  1 */ SyscallDesc("exit", exitFunc),
     /*  2 */ SyscallDesc("fork", unimplementedFunc),
-    /*  3 */ SyscallDesc("read", readFunc),
-    /*  4 */ SyscallDesc("write", writeFunc),
+    /*  3 */ SyscallDesc("read", readFunc<MipsLinux>),
+    /*  4 */ SyscallDesc("write", writeFunc<MipsLinux>),
     /*  5 */ SyscallDesc("open", openFunc<MipsLinux>),
     /*  6 */ SyscallDesc("close", closeFunc),
     /*  7 */ SyscallDesc("waitpid", unimplementedFunc),
index 801274969ed0686a5e666d8fb8b483e9fd02108f..f219852f827a974ade876095dcdcac68b0246cb4 100644 (file)
@@ -69,8 +69,8 @@ SyscallDesc PowerLinuxProcess::syscallDescs[] = {
     /*  0 */ SyscallDesc("syscall", unimplementedFunc),
     /*  1 */ SyscallDesc("exit", exitFunc),
     /*  2 */ SyscallDesc("fork", unimplementedFunc),
-    /*  3 */ SyscallDesc("read", readFunc),
-    /*  4 */ SyscallDesc("write", writeFunc),
+    /*  3 */ SyscallDesc("read", readFunc<PowerLinux>),
+    /*  4 */ SyscallDesc("write", writeFunc<PowerLinux>),
     /*  5 */ SyscallDesc("open", openFunc<PowerLinux>),
     /*  6 */ SyscallDesc("close", closeFunc),
     /*  7 */ SyscallDesc("waitpid", unimplementedFunc), //???
index 0f540af9d0bf75f118838d3145fb703a8b9765fa..6806079a3f1eca90c9e81555aabfe26f22cee91c 100644 (file)
@@ -133,8 +133,8 @@ std::map<int, SyscallDesc> RiscvLinuxProcess::syscallDescs = {
     {60,   SyscallDesc("quotactl")},
     {61,   SyscallDesc("getdents64")},
     {62,   SyscallDesc("lseek", lseekFunc)},
-    {63,   SyscallDesc("read", readFunc)},
-    {64,   SyscallDesc("write", writeFunc)},
+    {63,   SyscallDesc("read", readFunc<RiscvLinux>)},
+    {64,   SyscallDesc("write", writeFunc<RiscvLinux>)},
     {66,   SyscallDesc("writev", writevFunc<RiscvLinux>)},
     {67,   SyscallDesc("pread64")},
     {68,   SyscallDesc("pwrite64", pwrite64Func<RiscvLinux>)},
index 7fdc922ef690a3f194f8d24e666da194ca8164e9..ee8c60c45d4efde1aa1b86e198375fa33518acf0 100644 (file)
@@ -91,8 +91,8 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = {
     /*   0 */ SyscallDesc("restart_syscall", unimplementedFunc),
     /*   1 */ SyscallDesc("exit", exitFunc), // 32 bit
     /*   2 */ SyscallDesc("fork", unimplementedFunc),
-    /*   3 */ SyscallDesc("read", readFunc),
-    /*   4 */ SyscallDesc("write", writeFunc),
+    /*   3 */ SyscallDesc("read", readFunc<Sparc32Linux>),
+    /*   4 */ SyscallDesc("write", writeFunc<Sparc32Linux>),
     /*   5 */ SyscallDesc("open", openFunc<Sparc32Linux>), // 32 bit
     /*   6 */ SyscallDesc("close", closeFunc),
     /*   7 */ SyscallDesc("wait4", unimplementedFunc), // 32 bit
@@ -397,8 +397,8 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = {
     /*  0 */ SyscallDesc("restart_syscall", unimplementedFunc),
     /*  1 */ SyscallDesc("exit", exitFunc),
     /*  2 */ SyscallDesc("fork", unimplementedFunc),
-    /*  3 */ SyscallDesc("read", readFunc),
-    /*  4 */ SyscallDesc("write", writeFunc),
+    /*  3 */ SyscallDesc("read", readFunc<SparcLinux>),
+    /*  4 */ SyscallDesc("write", writeFunc<SparcLinux>),
     /*  5 */ SyscallDesc("open", openFunc<SparcLinux>),
     /*  6 */ SyscallDesc("close", closeFunc),
     /*  7 */ SyscallDesc("wait4", unimplementedFunc),
index 1afa35398e872886f25ef6e4bccc8554b2657a09..bcdd08814c442d1d1041226b570e72121c0267d3 100644 (file)
@@ -67,8 +67,8 @@ SyscallDesc SparcSolarisProcess::syscallDescs[] = {
     /* 0 */ SyscallDesc("syscall", unimplementedFunc),
     /* 1 */ SyscallDesc("exit", exitFunc),
     /* 2 */ SyscallDesc("fork", unimplementedFunc),
-    /* 3 */ SyscallDesc("read", readFunc),
-    /* 4 */ SyscallDesc("write", writeFunc),
+    /* 3 */ SyscallDesc("read", readFunc<SparcSolaris>),
+    /* 4 */ SyscallDesc("write", writeFunc<SparcSolaris>),
     /* 5 */ SyscallDesc("open", openFunc<SparcSolaris>),
     /* 6 */ SyscallDesc("close", closeFunc),
     /* 7 */ SyscallDesc("wait", unimplementedFunc),
index 65d0238f46fbf8d86e1f86f8b749a2a7899290a4..03a88fc6ee96996461dc8b7b376cb27330d5da73 100644 (file)
@@ -222,14 +222,14 @@ setThreadArea32Func(SyscallDesc *desc, int callnum,
 }
 
 static SyscallDesc syscallDescs64[] = {
-    /*   0 */ SyscallDesc("read", readFunc),
-    /*   1 */ SyscallDesc("write", writeFunc),
+    /*   0 */ SyscallDesc("read", readFunc<X86Linux64>),
+    /*   1 */ SyscallDesc("write", writeFunc<X86Linux64>),
     /*   2 */ SyscallDesc("open", openFunc<X86Linux64>),
     /*   3 */ SyscallDesc("close", closeFunc),
     /*   4 */ SyscallDesc("stat", stat64Func<X86Linux64>),
     /*   5 */ SyscallDesc("fstat", fstat64Func<X86Linux64>),
     /*   6 */ SyscallDesc("lstat", lstat64Func<X86Linux64>),
-    /*   7 */ SyscallDesc("poll", unimplementedFunc),
+    /*   7 */ SyscallDesc("poll", pollFunc<X86Linux64>),
     /*   8 */ SyscallDesc("lseek", lseekFunc),
     /*   9 */ SyscallDesc("mmap", mmapFunc<X86Linux64>),
     /*  10 */ SyscallDesc("mprotect", ignoreFunc),
@@ -245,7 +245,7 @@ static SyscallDesc syscallDescs64[] = {
     /*  20 */ SyscallDesc("writev", writevFunc<X86Linux64>),
     /*  21 */ SyscallDesc("access", ignoreFunc),
     /*  22 */ SyscallDesc("pipe", pipeFunc),
-    /*  23 */ SyscallDesc("select", unimplementedFunc),
+    /*  23 */ SyscallDesc("select", selectFunc<X86Linux64>),
     /*  24 */ SyscallDesc("sched_yield", ignoreFunc),
     /*  25 */ SyscallDesc("mremap", mremapFunc<X86Linux64>),
     /*  26 */ SyscallDesc("msync", unimplementedFunc),
@@ -265,7 +265,7 @@ static SyscallDesc syscallDescs64[] = {
     /*  40 */ SyscallDesc("sendfile", unimplementedFunc),
     /*  41 */ SyscallDesc("socket", socketFunc<X86Linux64>),
     /*  42 */ SyscallDesc("connect", connectFunc),
-    /*  43 */ SyscallDesc("accept", unimplementedFunc),
+    /*  43 */ SyscallDesc("accept", acceptFunc<X86Linux64>),
     /*  44 */ SyscallDesc("sendto", sendtoFunc),
     /*  45 */ SyscallDesc("recvfrom", recvfromFunc),
     /*  46 */ SyscallDesc("sendmsg", sendmsgFunc),
@@ -283,7 +283,7 @@ static SyscallDesc syscallDescs64[] = {
     /*  58 */ SyscallDesc("vfork", unimplementedFunc),
     /*  59 */ SyscallDesc("execve", execveFunc<X86Linux64>),
     /*  60 */ SyscallDesc("exit", exitFunc),
-    /*  61 */ SyscallDesc("wait4", unimplementedFunc),
+    /*  61 */ SyscallDesc("wait4", wait4Func<X86Linux64>),
     /*  62 */ SyscallDesc("kill", unimplementedFunc),
     /*  63 */ SyscallDesc("uname", unameFunc),
     /*  64 */ SyscallDesc("semget", unimplementedFunc),
@@ -558,8 +558,8 @@ static SyscallDesc syscallDescs32[] = {
     /*   0 */ SyscallDesc("restart_syscall", unimplementedFunc),
     /*   1 */ SyscallDesc("exit", exitFunc),
     /*   2 */ SyscallDesc("fork", unimplementedFunc),
-    /*   3 */ SyscallDesc("read", readFunc),
-    /*   4 */ SyscallDesc("write", writeFunc),
+    /*   3 */ SyscallDesc("read", readFunc<X86Linux32>),
+    /*   4 */ SyscallDesc("write", writeFunc<X86Linux32>),
     /*   5 */ SyscallDesc("open", openFunc<X86Linux32>),
     /*   6 */ SyscallDesc("close", closeFunc),
     /*   7 */ SyscallDesc("waitpid", unimplementedFunc),
@@ -637,7 +637,7 @@ static SyscallDesc syscallDescs32[] = {
     /*  79 */ SyscallDesc("settimeofday", unimplementedFunc),
     /*  80 */ SyscallDesc("getgroups", unimplementedFunc),
     /*  81 */ SyscallDesc("setgroups", unimplementedFunc),
-    /*  82 */ SyscallDesc("select", unimplementedFunc),
+    /*  82 */ SyscallDesc("select", selectFunc<X86Linux32>),
     /*  83 */ SyscallDesc("symlink", unimplementedFunc),
     /*  84 */ SyscallDesc("oldlstat", unimplementedFunc),
     /*  85 */ SyscallDesc("readlink", readlinkFunc),
@@ -669,7 +669,7 @@ static SyscallDesc syscallDescs32[] = {
     /* 111 */ SyscallDesc("vhangup", unimplementedFunc),
     /* 112 */ SyscallDesc("idle", unimplementedFunc),
     /* 113 */ SyscallDesc("vm86old", unimplementedFunc),
-    /* 114 */ SyscallDesc("wait4", unimplementedFunc),
+    /* 114 */ SyscallDesc("wait4", wait4Func<X86Linux32>),
     /* 115 */ SyscallDesc("swapoff", unimplementedFunc),
     /* 116 */ SyscallDesc("sysinfo", sysinfoFunc<X86Linux32>),
     /* 117 */ SyscallDesc("ipc", unimplementedFunc),
@@ -727,7 +727,7 @@ static SyscallDesc syscallDescs32[] = {
     /* 165 */ SyscallDesc("getresuid", unimplementedFunc),
     /* 166 */ SyscallDesc("vm86", unimplementedFunc),
     /* 167 */ SyscallDesc("query_module", unimplementedFunc),
-    /* 168 */ SyscallDesc("poll", unimplementedFunc),
+    /* 168 */ SyscallDesc("poll", pollFunc<X86Linux32>),
     /* 169 */ SyscallDesc("nfsservctl", unimplementedFunc),
     /* 170 */ SyscallDesc("setresgid", unimplementedFunc),
     /* 171 */ SyscallDesc("getresgid", unimplementedFunc),
index a1df99467bfc6c0e7005ef1a4a24fd9a5d896023..e559e0505a0609c300693622d62f1debb8b981f6 100644 (file)
@@ -153,6 +153,15 @@ class Linux : public OperatingSystem
         uint64_t iov_len;
     };
 
+    // For select().
+    // linux-3.14-src/include/uapi/linux/posix_types.h
+    struct fd_set{
+#ifndef LINUX__FD_SETSIZE
+#define LINUX__FD_SETSIZE 1024
+        unsigned long fds_bits[LINUX__FD_SETSIZE / (8 * sizeof(long))];
+#endif
+    };
+
     //@{
     /// ioctl() command codes.
     static const unsigned TGT_TCGETS     = 0x5401;
@@ -265,6 +274,14 @@ class Linux : public OperatingSystem
     static const unsigned TGT_CLONE_NEWPID          = 0x20000000;
     static const unsigned TGT_CLONE_NEWNET          = 0x40000000;
     static const unsigned TGT_CLONE_IO              = 0x80000000;
+
+    // linux-3.13-src/include/uapi/linux/wait.h
+    static const unsigned TGT_WNOHANG               = 0x00000001;
+    static const unsigned TGT_WUNTRACED             = 0x00000002;
+    static const unsigned TGT_WSTOPPED              = TGT_WUNTRACED;
+    static const unsigned TGT_WEXITED               = 0x00000004;
+    static const unsigned TGT_WCONTINUED            = 0x00000008;
+    static const unsigned TGT_WNOWAIT               = 0x01000000;
 };  // class Linux
 
 #endif // __LINUX_HH__
index 6b2b2daa8dd179d7699cc842c526565867d7a81f..15e174ae62fbe1cab2a9cfa88c716b3d1b6b7ab9 100644 (file)
@@ -231,7 +231,6 @@ class SocketFDEntry: public HBFDEntry
         return std::make_shared<SocketFDEntry>(*this);
     }
 
-  private:
     int _domain;
     int _type;
     int _protocol;
index 89f70a1cb49f898a7cbe7d9408b13ed21dc1d8ea..74ca1e924797fc4a7075d2207395e0396927cabc 100644 (file)
@@ -279,53 +279,6 @@ closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
     return p->fds->closeFDEntry(tgt_fd);
 }
 
-
-SyscallReturn
-readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
-{
-    int index = 0;
-    int tgt_fd = p->getSyscallArg(tc, index);
-    Addr buf_ptr = p->getSyscallArg(tc, index);
-    int nbytes = p->getSyscallArg(tc, index);
-
-    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
-    if (!hbfdp)
-        return -EBADF;
-    int sim_fd = hbfdp->getSimFD();
-
-    BufferArg bufArg(buf_ptr, nbytes);
-    int bytes_read = read(sim_fd, bufArg.bufferPtr(), nbytes);
-
-    if (bytes_read > 0)
-        bufArg.copyOut(tc->getMemProxy());
-
-    return bytes_read;
-}
-
-SyscallReturn
-writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
-{
-    int index = 0;
-    int tgt_fd = p->getSyscallArg(tc, index);
-    Addr buf_ptr = p->getSyscallArg(tc, index);
-    int nbytes = p->getSyscallArg(tc, index);
-
-    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
-    if (!hbfdp)
-        return -EBADF;
-    int sim_fd = hbfdp->getSimFD();
-
-    BufferArg bufArg(buf_ptr, nbytes);
-    bufArg.copyIn(tc->getMemProxy());
-
-    int bytes_written = write(sim_fd, bufArg.bufferPtr(), nbytes);
-
-    fsync(sim_fd);
-
-    return bytes_written;
-}
-
-
 SyscallReturn
 lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 {
index d882cf4faa973fda0364f97fad76d1c549b062f2..67fa9e3d39b86c2df8c9a2d1b6a76536ceba8b82 100644 (file)
@@ -78,6 +78,7 @@
 
 #endif
 #include <fcntl.h>
+#include <poll.h>
 #include <sys/mman.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
@@ -87,6 +88,7 @@
 #include <sys/mount.h>
 #endif
 #include <sys/time.h>
+#include <sys/types.h>
 #include <sys/uio.h>
 #include <unistd.h>
 
@@ -162,14 +164,6 @@ SyscallReturn brkFunc(SyscallDesc *desc, int num,
 SyscallReturn closeFunc(SyscallDesc *desc, int num,
                         Process *p, ThreadContext *tc);
 
-// Target read() handler.
-SyscallReturn readFunc(SyscallDesc *desc, int num,
-                       Process *p, ThreadContext *tc);
-
-/// Target write() handler.
-SyscallReturn writeFunc(SyscallDesc *desc, int num,
-                        Process *p, ThreadContext *tc);
-
 /// Target lseek() handler.
 SyscallReturn lseekFunc(SyscallDesc *desc, int num,
                         Process *p, ThreadContext *tc);
@@ -946,6 +940,80 @@ chmodFunc(SyscallDesc *desc, int callnum, Process *process,
     return 0;
 }
 
+template <class OS>
+SyscallReturn
+pollFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+    int index = 0;
+    Addr fdsPtr = p->getSyscallArg(tc, index);
+    int nfds = p->getSyscallArg(tc, index);
+    int tmout = p->getSyscallArg(tc, index);
+
+    BufferArg fdsBuf(fdsPtr, sizeof(struct pollfd) * nfds);
+    fdsBuf.copyIn(tc->getMemProxy());
+
+    /**
+     * Record the target file descriptors in a local variable. We need to
+     * replace them with host file descriptors but we need a temporary copy
+     * for later. Afterwards, replace each target file descriptor in the
+     * poll_fd array with its host_fd.
+     */
+    int temp_tgt_fds[nfds];
+    for (index = 0; index < nfds; index++) {
+        temp_tgt_fds[index] = ((struct pollfd *)fdsBuf.bufferPtr())[index].fd;
+        auto tgt_fd = temp_tgt_fds[index];
+        auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
+        if (!hbfdp)
+            return -EBADF;
+        auto host_fd = hbfdp->getSimFD();
+        ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = host_fd;
+    }
+
+    /**
+     * We cannot allow an infinite poll to occur or it will inevitably cause
+     * a deadlock in the gem5 simulator with clone. We must pass in tmout with
+     * a non-negative value, however it also makes no sense to poll on the
+     * underlying host for any other time than tmout a zero timeout.
+     */
+    int status;
+    if (tmout < 0) {
+        status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
+        if (status == 0) {
+            /**
+             * If blocking indefinitely, check the signal list to see if a
+             * signal would break the poll out of the retry cycle and try
+             * to return the signal interrupt instead.
+             */
+            System *sysh = tc->getSystemPtr();
+            std::list<BasicSignal>::iterator it;
+            for (it=sysh->signalList.begin(); it!=sysh->signalList.end(); it++)
+                if (it->receiver == p)
+                    return -EINTR;
+            return SyscallReturn::retry();
+        }
+    } else
+        status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
+
+    if (status == -1)
+        return -errno;
+
+    /**
+     * Replace each host_fd in the returned poll_fd array with its original
+     * target file descriptor.
+     */
+    for (index = 0; index < nfds; index++) {
+        auto tgt_fd = temp_tgt_fds[index];
+        ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = tgt_fd;
+    }
+
+    /**
+     * Copy out the pollfd struct because the host may have updated fields
+     * in the structure.
+     */
+    fdsBuf.copyOut(tc->getMemProxy());
+
+    return status;
+}
 
 /// Target fchmod() handler.
 template <class OS>
@@ -1269,7 +1337,6 @@ fstatFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
     return 0;
 }
 
-
 /// Target statfs() handler.
 template <class OS>
 SyscallReturn
@@ -2158,4 +2225,401 @@ socketpairFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
     return status;
 }
 
+template <class OS>
+SyscallReturn
+selectFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
+{
+    int retval;
+
+    int index = 0;
+    int nfds_t = p->getSyscallArg(tc, index);
+    Addr fds_read_ptr = p->getSyscallArg(tc, index);
+    Addr fds_writ_ptr = p->getSyscallArg(tc, index);
+    Addr fds_excp_ptr = p->getSyscallArg(tc, index);
+    Addr time_val_ptr = p->getSyscallArg(tc, index);
+
+    TypedBufferArg<typename OS::fd_set> rd_t(fds_read_ptr);
+    TypedBufferArg<typename OS::fd_set> wr_t(fds_writ_ptr);
+    TypedBufferArg<typename OS::fd_set> ex_t(fds_excp_ptr);
+    TypedBufferArg<typename OS::timeval> tp(time_val_ptr);
+
+    /**
+     * Host fields. Notice that these use the definitions from the system
+     * headers instead of the gem5 headers and libraries. If the host and
+     * target have different header file definitions, this will not work.
+     */
+    fd_set rd_h;
+    FD_ZERO(&rd_h);
+    fd_set wr_h;
+    FD_ZERO(&wr_h);
+    fd_set ex_h;
+    FD_ZERO(&ex_h);
+
+    /**
+     * Copy in the fd_set from the target.
+     */
+    if (fds_read_ptr)
+        rd_t.copyIn(tc->getMemProxy());
+    if (fds_writ_ptr)
+        wr_t.copyIn(tc->getMemProxy());
+    if (fds_excp_ptr)
+        ex_t.copyIn(tc->getMemProxy());
+
+    /**
+     * We need to translate the target file descriptor set into a host file
+     * descriptor set. This involves both our internal process fd array
+     * and the fd_set defined in Linux header files. The nfds field also
+     * needs to be updated as it will be only target specific after
+     * retrieving it from the target; the nfds value is expected to be the
+     * highest file descriptor that needs to be checked, so we need to extend
+     * it out for nfds_h when we do the update.
+     */
+    int nfds_h = 0;
+    std::map<int, int> trans_map;
+    auto try_add_host_set = [&](fd_set *tgt_set_entry,
+                                fd_set *hst_set_entry,
+                                int iter) -> bool
+    {
+        /**
+         * By this point, we know that we are looking at a valid file
+         * descriptor set on the target. We need to check if the target file
+         * descriptor value passed in as iter is part of the set.
+         */
+        if (FD_ISSET(iter, tgt_set_entry)) {
+            /**
+             * We know that the target file descriptor belongs to the set,
+             * but we do not yet know if the file descriptor is valid or
+             * that we have a host mapping. Check that now.
+             */
+            auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[iter]);
+            if (!hbfdp)
+                return true;
+            auto sim_fd = hbfdp->getSimFD();
+
+            /**
+             * Add the sim_fd to tgt_fd translation into trans_map for use
+             * later when we need to zero the target fd_set structures and
+             * then update them with hits returned from the host select call.
+             */
+            trans_map[sim_fd] = iter;
+
+            /**
+             * We know that the host file descriptor exists so now we check
+             * if we need to update the max count for nfds_h before passing
+             * the duplicated structure into the host.
+             */
+            nfds_h = std::max(nfds_h - 1, sim_fd + 1);
+
+            /**
+             * Add the host file descriptor to the set that we are going to
+             * pass into the host.
+             */
+            FD_SET(sim_fd, hst_set_entry);
+        }
+        return false;
+    };
+
+    for (int i = 0; i < nfds_t; i++) {
+        if (fds_read_ptr) {
+            bool ebadf = try_add_host_set((fd_set*)&*rd_t, &rd_h, i);
+            if (ebadf) return -EBADF;
+        }
+        if (fds_writ_ptr) {
+            bool ebadf = try_add_host_set((fd_set*)&*wr_t, &wr_h, i);
+            if (ebadf) return -EBADF;
+        }
+        if (fds_excp_ptr) {
+            bool ebadf = try_add_host_set((fd_set*)&*ex_t, &ex_h, i);
+            if (ebadf) return -EBADF;
+        }
+    }
+
+    if (time_val_ptr) {
+        /**
+         * It might be possible to decrement the timeval based on some
+         * derivation of wall clock determined from elapsed simulator ticks
+         * but that seems like overkill. Rather, we just set the timeval with
+         * zero timeout. (There is no reason to block during the simulation
+         * as it only decreases simulator performance.)
+         */
+        tp->tv_sec = 0;
+        tp->tv_usec = 0;
+
+        retval = select(nfds_h,
+                        fds_read_ptr ? &rd_h : nullptr,
+                        fds_writ_ptr ? &wr_h : nullptr,
+                        fds_excp_ptr ? &ex_h : nullptr,
+                        (timeval*)&*tp);
+    } else {
+        /**
+         * If the timeval pointer is null, setup a new timeval structure to
+         * pass into the host select call. Unfortunately, we will need to
+         * manually check the return value and throw a retry fault if the
+         * return value is zero. Allowing the system call to block will
+         * likely deadlock the event queue.
+         */
+        struct timeval tv = { 0, 0 };
+
+        retval = select(nfds_h,
+                        fds_read_ptr ? &rd_h : nullptr,
+                        fds_writ_ptr ? &wr_h : nullptr,
+                        fds_excp_ptr ? &ex_h : nullptr,
+                        &tv);
+
+        if (retval == 0) {
+            /**
+             * If blocking indefinitely, check the signal list to see if a
+             * signal would break the poll out of the retry cycle and try to
+             * return the signal interrupt instead.
+             */
+            for (auto sig : tc->getSystemPtr()->signalList)
+                if (sig.receiver == p)
+                    return -EINTR;
+            return SyscallReturn::retry();
+        }
+    }
+
+    if (retval == -1)
+        return -errno;
+
+    FD_ZERO((fd_set*)&*rd_t);
+    FD_ZERO((fd_set*)&*wr_t);
+    FD_ZERO((fd_set*)&*ex_t);
+
+    /**
+     * We need to translate the host file descriptor set into a target file
+     * descriptor set. This involves both our internal process fd array
+     * and the fd_set defined in header files.
+     */
+    for (int i = 0; i < nfds_h; i++) {
+        if (fds_read_ptr) {
+            if (FD_ISSET(i, &rd_h))
+                FD_SET(trans_map[i], (fd_set*)&*rd_t);
+        }
+
+        if (fds_writ_ptr) {
+            if (FD_ISSET(i, &wr_h))
+                FD_SET(trans_map[i], (fd_set*)&*wr_t);
+        }
+
+        if (fds_excp_ptr) {
+            if (FD_ISSET(i, &ex_h))
+                FD_SET(trans_map[i], (fd_set*)&*ex_t);
+        }
+    }
+
+    if (fds_read_ptr)
+        rd_t.copyOut(tc->getMemProxy());
+    if (fds_writ_ptr)
+        wr_t.copyOut(tc->getMemProxy());
+    if (fds_excp_ptr)
+        ex_t.copyOut(tc->getMemProxy());
+    if (time_val_ptr)
+        tp.copyOut(tc->getMemProxy());
+
+    return retval;
+}
+
+template <class OS>
+SyscallReturn
+readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+    int index = 0;
+    int tgt_fd = p->getSyscallArg(tc, index);
+    Addr buf_ptr = p->getSyscallArg(tc, index);
+    int nbytes = p->getSyscallArg(tc, index);
+
+    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
+    if (!hbfdp)
+        return -EBADF;
+    int sim_fd = hbfdp->getSimFD();
+
+    struct pollfd pfd;
+    pfd.fd = sim_fd;
+    pfd.events = POLLIN | POLLPRI;
+    if ((poll(&pfd, 1, 0) == 0)
+        && !(hbfdp->getFlags() & OS::TGT_O_NONBLOCK))
+        return SyscallReturn::retry();
+
+    BufferArg buf_arg(buf_ptr, nbytes);
+    int bytes_read = read(sim_fd, buf_arg.bufferPtr(), nbytes);
+
+    if (bytes_read > 0)
+        buf_arg.copyOut(tc->getMemProxy());
+
+    return (bytes_read == -1) ? -errno : bytes_read;
+}
+
+template <class OS>
+SyscallReturn
+writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+    int index = 0;
+    int tgt_fd = p->getSyscallArg(tc, index);
+    Addr buf_ptr = p->getSyscallArg(tc, index);
+    int nbytes = p->getSyscallArg(tc, index);
+
+    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
+    if (!hbfdp)
+        return -EBADF;
+    int sim_fd = hbfdp->getSimFD();
+
+    BufferArg buf_arg(buf_ptr, nbytes);
+    buf_arg.copyIn(tc->getMemProxy());
+
+    struct pollfd pfd;
+    pfd.fd = sim_fd;
+    pfd.events = POLLOUT;
+
+    /**
+     * We don't want to poll on /dev/random. The kernel will not enable the
+     * file descriptor for writing unless the entropy in the system falls
+     * below write_wakeup_threshold. This is not guaranteed to happen
+     * depending on host settings.
+     */
+    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(hbfdp);
+    if (ffdp && (ffdp->getFileName() != "/dev/random")) {
+        if (!poll(&pfd, 1, 0) && !(ffdp->getFlags() & OS::TGT_O_NONBLOCK))
+            return SyscallReturn::retry();
+    }
+
+    int bytes_written = write(sim_fd, buf_arg.bufferPtr(), nbytes);
+
+    if (bytes_written != -1)
+        fsync(sim_fd);
+
+    return (bytes_written == -1) ? -errno : bytes_written;
+}
+
+template <class OS>
+SyscallReturn
+wait4Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+    int index = 0;
+    pid_t pid = p->getSyscallArg(tc, index);
+    Addr statPtr = p->getSyscallArg(tc, index);
+    int options = p->getSyscallArg(tc, index);
+    Addr rusagePtr = p->getSyscallArg(tc, index);
+
+    if (rusagePtr)
+        DPRINTFR(SyscallVerbose,
+                 "%d: %s: syscall wait4: rusage pointer provided however "
+                 "functionality not supported. Ignoring rusage pointer.\n",
+                 curTick(), tc->getCpuPtr()->name());
+
+    /**
+     * Currently, wait4 is only implemented so that it will wait for children
+     * exit conditions which are denoted by a SIGCHLD signals posted into the
+     * system signal list. We return no additional information via any of the
+     * parameters supplied to wait4. If nothing is found in the system signal
+     * list, we will wait indefinitely for SIGCHLD to post by retrying the
+     * call.
+     */
+    System *sysh = tc->getSystemPtr();
+    std::list<BasicSignal>::iterator iter;
+    for (iter=sysh->signalList.begin(); iter!=sysh->signalList.end(); iter++) {
+        if (iter->receiver == p) {
+            if (pid < -1) {
+                if ((iter->sender->pgid() == -pid)
+                    && (iter->signalValue == OS::TGT_SIGCHLD))
+                    goto success;
+            } else if (pid == -1) {
+                if (iter->signalValue == OS::TGT_SIGCHLD)
+                    goto success;
+            } else if (pid == 0) {
+                if ((iter->sender->pgid() == p->pgid())
+                    && (iter->signalValue == OS::TGT_SIGCHLD))
+                    goto success;
+            } else {
+                if ((iter->sender->pid() == pid)
+                    && (iter->signalValue == OS::TGT_SIGCHLD))
+                    goto success;
+            }
+        }
+    }
+
+    return (options & OS::TGT_WNOHANG) ? 0 : SyscallReturn::retry();
+
+success:
+    // Set status to EXITED for WIFEXITED evaluations.
+    const int EXITED = 0;
+    BufferArg statusBuf(statPtr, sizeof(int));
+    *(int *)statusBuf.bufferPtr() = EXITED;
+    statusBuf.copyOut(tc->getMemProxy());
+
+    // Return the child PID.
+    pid_t retval = iter->sender->pid();
+    sysh->signalList.erase(iter);
+    return retval;
+}
+
+template <class OS>
+SyscallReturn
+acceptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+    struct sockaddr sa;
+    socklen_t addrLen;
+    int host_fd;
+    int index = 0;
+    int tgt_fd = p->getSyscallArg(tc, index);
+    Addr addrPtr = p->getSyscallArg(tc, index);
+    Addr lenPtr = p->getSyscallArg(tc, index);
+
+    BufferArg *lenBufPtr = nullptr;
+    BufferArg *addrBufPtr = nullptr;
+
+    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
+    if (!sfdp)
+        return -EBADF;
+    int sim_fd = sfdp->getSimFD();
+
+    /**
+     * We poll the socket file descriptor first to guarantee that we do not
+     * block on our accept call. The socket can be opened without the
+     * non-blocking flag (it blocks). This will cause deadlocks between
+     * communicating processes.
+     */
+    struct pollfd pfd;
+    pfd.fd = sim_fd;
+    pfd.events = POLLIN | POLLPRI;
+    if ((poll(&pfd, 1, 0) == 0)
+        && !(sfdp->getFlags() & OS::TGT_O_NONBLOCK))
+        return SyscallReturn::retry();
+
+    if (lenPtr) {
+        lenBufPtr = new BufferArg(lenPtr, sizeof(socklen_t));
+        lenBufPtr->copyIn(tc->getMemProxy());
+        memcpy(&addrLen, (socklen_t *)lenBufPtr->bufferPtr(),
+               sizeof(socklen_t));
+    }
+
+    if (addrPtr) {
+        addrBufPtr = new BufferArg(addrPtr, sizeof(struct sockaddr));
+        addrBufPtr->copyIn(tc->getMemProxy());
+        memcpy(&sa, (struct sockaddr *)addrBufPtr->bufferPtr(),
+               sizeof(struct sockaddr));
+    }
+
+    host_fd = accept(sim_fd, &sa, &addrLen);
+
+    if (host_fd == -1)
+        return -errno;
+
+    if (addrPtr) {
+        memcpy(addrBufPtr->bufferPtr(), &sa, sizeof(sa));
+        addrBufPtr->copyOut(tc->getMemProxy());
+        delete(addrBufPtr);
+    }
+
+    if (lenPtr) {
+        *(socklen_t *)lenBufPtr->bufferPtr() = addrLen;
+        lenBufPtr->copyOut(tc->getMemProxy());
+        delete(lenBufPtr);
+    }
+
+    auto afdp = std::make_shared<SocketFDEntry>(host_fd, sfdp->_domain,
+                                                sfdp->_type, sfdp->_protocol);
+    return p->fds->allocFD(afdp);
+}
+
 #endif // __SIM_SYSCALL_EMUL_HH__