syscall_emul: [patch 10/22] refactor fdentry and add fdarray class
authorBrandon Potter <brandon.potter@amd.com>
Wed, 9 Nov 2016 20:27:42 +0000 (14:27 -0600)
committerBrandon Potter <brandon.potter@amd.com>
Wed, 9 Nov 2016 20:27:42 +0000 (14:27 -0600)
Several large changes happen in this patch.

The FDEntry class is rewritten so that file descriptors now correspond to
types: 'File' which is normal file-backed file with the file open on the
host machine, 'Pipe' which is a pipe that has been opened on the host machine,
and 'Device' which does not have an open file on the host yet acts as a pseudo
device with which to issue ioctls. Other types which might be added in the
future are directory entries and sockets (off the top of my head).

The FDArray class was create to hold most of the file descriptor handling
that was stuffed into the Process class. It uses shared pointers and
the std::array type to hold the FDEntries mentioned above.

The changes to these two classes needed to be propagated out to the rest
of the code so there were quite a few changes for that. Also, comments were
added where I thought they were needed to help others and extend our
DOxygen coverage.

src/gpu-compute/cl_driver.cc
src/sim/SConscript
src/sim/fd_array.cc [new file with mode: 0644]
src/sim/fd_array.hh [new file with mode: 0644]
src/sim/fd_entry.cc
src/sim/fd_entry.hh
src/sim/process.cc
src/sim/process.hh
src/sim/syscall_emul.cc
src/sim/syscall_emul.hh

index 41ae3ab9a51b8199a5199332d33084ace9ecbe62..119091fc5eccc51540f9dc1766774134f784ee14 100644 (file)
@@ -35,6 +35,8 @@
 
 #include "gpu-compute/cl_driver.hh"
 
+#include <memory>
+
 #include "base/intmath.hh"
 #include "cpu/thread_context.hh"
 #include "gpu-compute/dispatcher.hh"
@@ -93,11 +95,10 @@ ClDriver::handshake(GpuDispatcher *_dispatcher)
 int
 ClDriver::open(Process *p, ThreadContext *tc, int mode, int flags)
 {
-    int fd = p->allocFD(-1, filename, 0, 0, false);
-    FDEntry *fde = p->getFDEntry(fd);
-    fde->driver = this;
-
-    return fd;
+    std::shared_ptr<DeviceFDEntry> fdp;
+    fdp = std::make_shared<DeviceFDEntry>(this, filename);
+    int tgt_fd = p->fds->allocFD(fdp);
+    return tgt_fd;
 }
 
 int
index 6b0b8430b43cad50349b3f5ade1e5bf10dba4e17..c36b33b51cb9a2931ce6ab6a3172b357f2d9bc56 100644 (file)
@@ -78,6 +78,7 @@ if env['TARGET_ISA'] != 'null':
     Source('aux_vector.cc')
     Source('faults.cc')
     Source('process.cc')
+    Source('fd_array.cc')
     Source('fd_entry.cc')
     Source('pseudo_inst.cc')
     Source('syscall_emul.cc')
diff --git a/src/sim/fd_array.cc b/src/sim/fd_array.cc
new file mode 100644 (file)
index 0000000..d737070
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2016 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * For use for simulation and test purposes only
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Brandon Potter
+ */
+
+#include "sim/fd_array.hh"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <array>
+#include <memory>
+#include <string>
+
+#include "base/misc.hh"
+#include "params/Process.hh"
+#include "sim/fd_entry.hh"
+
+FDArray::FDArray(std::string const& input, std::string const& output,
+                 std::string const& errout)
+    : _input(input), _output(output), _errout(errout), _fdArray(),
+      imap {{"",       -1},
+            {"cin",    STDIN_FILENO},
+            {"stdin",  STDIN_FILENO}},
+      oemap{{"",       -1},
+            {"cout",   STDOUT_FILENO},
+            {"stdout", STDOUT_FILENO},
+            {"cerr",   STDERR_FILENO},
+            {"stderr", STDERR_FILENO}}
+{
+    int sim_fd;
+    std::map<std::string, int>::iterator it;
+
+    /**
+     * Search through the input options and setup the default fd if match is
+     * found; otherwise, open an input file and seek to location.
+     */
+    if ((it = imap.find(input)) != imap.end())
+        sim_fd = it->second;
+    else
+        sim_fd = openInputFile(input);
+
+    auto ffd = std::make_shared<FileFDEntry>(sim_fd, O_RDONLY, input, false);
+    _fdArray[STDIN_FILENO] = ffd;
+
+    /**
+     * Search through the output/error options and setup the default fd if
+     * match is found; otherwise, open an output file and seek to location.
+     */
+    if ((it = oemap.find(output)) != oemap.end())
+        sim_fd = it->second;
+    else
+        sim_fd = openOutputFile(output);
+
+    ffd = std::make_shared<FileFDEntry>(sim_fd, O_WRONLY | O_CREAT | O_TRUNC,
+                                        output, false);
+    _fdArray[STDOUT_FILENO] = ffd;
+
+    if (output == errout)
+        ; /* Reuse the same file descriptor if these match. */
+    else if ((it = oemap.find(errout)) != oemap.end())
+        sim_fd = it->second;
+    else
+        sim_fd = openOutputFile(errout);
+
+    ffd = std::make_shared<FileFDEntry>(sim_fd, O_WRONLY | O_CREAT | O_TRUNC,
+                                        errout, false);
+    _fdArray[STDERR_FILENO] = ffd;
+}
+
+void
+FDArray::updateFileOffsets()
+{
+    for (auto& fdp : _fdArray) {
+        /**
+         * It only makes sense to check the offsets if the file descriptor
+         * type is 'File' (which indicates that this file is backed by a
+         * file on the host). If the type is File, then record the offset.
+         */
+        auto ffd = std::dynamic_pointer_cast<FileFDEntry>(fdp);
+
+        if (!ffd)
+            continue;
+
+        /**
+         * Use lseek with SEEK_CUR with offset 0 to figure out where the
+         * offset currently resides and pass that back to our setter.
+         */
+        int sim_fd = ffd->getSimFD();
+        ffd->setFileOffset(lseek(sim_fd, 0, SEEK_CUR));
+    }
+}
+
+void
+FDArray::restoreFileOffsets()
+{
+    /**
+     * Use this lambda to highlight what we mean to do with the seek.
+     * Notice that this either seeks correctly (sets the file location on the
+     * host) or it fails with a fatal. The error is fatal because it's not
+     * possible to guarantee that the simulation will proceed as it should
+     * have in the same way that it would have proceeded sans checkpoints.
+     */
+    void (*seek)(std::shared_ptr<FileFDEntry>)
+        = [] (std::shared_ptr<FileFDEntry> ffd)
+    {
+        if (lseek(ffd->getSimFD(), ffd->getFileOffset(), SEEK_SET) < 0)
+            fatal("Unable to seek to location in %s", ffd->getFileName());
+    };
+
+    std::map<std::string, int>::iterator it;
+
+    /**
+     * Search through the input options and set fd if match is found;
+     * otherwise, open an input file and seek to location.
+     * Check if user has specified a different input file, and if so, use it
+     * instead of the file specified in the checkpoint. This also resets the
+     * file offset from the checkpointed value
+     */
+    std::shared_ptr<FDEntry> stdin_fde = _fdArray[STDIN_FILENO];
+    auto stdin_ffd = std::dynamic_pointer_cast<FileFDEntry>(stdin_fde);
+
+    if (_input != stdin_ffd->getFileName()) {
+        warn("Using new input file (%s) rather than checkpointed (%s)\n",
+             _input, stdin_ffd->getFileName());
+        stdin_ffd->setFileName(_input);
+        stdin_ffd->setFileOffset(0);
+    }
+
+    if ((it = imap.find(stdin_ffd->getFileName())) != imap.end()) {
+        stdin_ffd->setSimFD(it->second);
+    } else {
+        stdin_ffd->setSimFD(openInputFile(stdin_ffd->getFileName()));
+        seek(stdin_ffd);
+    }
+
+    /**
+     * Search through the output options and set fd if match is found;
+     * otherwise, open an output file and seek to location.
+     * Check if user has specified a different output file, and if so, use it
+     * instead of the file specified in the checkpoint. This also resets the
+     * file offset from the checkpointed value
+     */
+    std::shared_ptr<FDEntry> stdout_fde = _fdArray[STDOUT_FILENO];
+    auto stdout_ffd = std::dynamic_pointer_cast<FileFDEntry>(stdout_fde);
+
+    if (_output != stdout_ffd->getFileName()) {
+        warn("Using new output file (%s) rather than checkpointed (%s)\n",
+             _output, stdout_ffd->getFileName());
+        stdout_ffd->setFileName(_output);
+        stdout_ffd->setFileOffset(0);
+    }
+
+    if ((it = oemap.find(stdout_ffd->getFileName())) != oemap.end()) {
+        stdout_ffd->setSimFD(it->second);
+    } else {
+        stdout_ffd->setSimFD(openOutputFile(stdout_ffd->getFileName()));
+        seek(stdout_ffd);
+    }
+
+    /**
+     * Search through the error options and set fd if match is found;
+     * otherwise, open an error file and seek to location.
+     * Check if user has specified a different error file, and if so, use it
+     * instead of the file specified in the checkpoint. This also resets the
+     * file offset from the checkpointed value
+     */
+    std::shared_ptr<FDEntry> stderr_fde = _fdArray[STDERR_FILENO];
+    auto stderr_ffd = std::dynamic_pointer_cast<FileFDEntry>(stderr_fde);
+
+    if (_errout != stderr_ffd->getFileName()) {
+        warn("Using new error file (%s) rather than checkpointed (%s)\n",
+             _errout, stderr_ffd->getFileName());
+        stderr_ffd->setFileName(_errout);
+        stderr_ffd->setFileOffset(0);
+    }
+
+    if (stdout_ffd->getFileName() == stderr_ffd->getFileName()) {
+        /* Reuse the same sim_fd file descriptor if these match. */
+        stderr_ffd->setSimFD(stdout_ffd->getSimFD());
+    } else if ((it = oemap.find(stderr_ffd->getFileName())) != oemap.end()) {
+        stderr_ffd->setSimFD(it->second);
+    } else {
+        stderr_ffd->setSimFD(openOutputFile(stderr_ffd->getFileName()));
+        seek(stderr_ffd);
+    }
+
+    for (int tgt_fd = 3; tgt_fd < _fdArray.size(); tgt_fd++) {
+        std::shared_ptr<FDEntry> fdp = _fdArray[tgt_fd];
+        if (!fdp)
+            continue;
+
+        /* Need to reconnect pipe ends. */
+        if (auto pfd = std::dynamic_pointer_cast<PipeFDEntry>(fdp)) {
+            /**
+             * Check which end of the pipe we are looking at; we only want
+             * to setup the pipe once so we arbitrarily choose the read
+             * end to be the end that sets up the pipe.
+             */
+            if (pfd->getEndType() == PipeFDEntry::EndType::write)
+                continue;
+
+            /* Setup the pipe or fatal out of the simulation. */
+            int fd_pair[2];
+            if (pipe(fd_pair) < 0)
+                fatal("Unable to create new pipe");
+
+            /**
+             * Reconstruct the ends of the pipe by reassigning the pipe
+             * that we created on the host. This one is the read end.
+             */
+            pfd->setSimFD(fd_pair[0]);
+
+            /**
+             * Grab the write end by referencing the read ends source and
+             * using that tgt_fd to index the array.
+             */
+            int prs = pfd->getPipeReadSource();
+            std::shared_ptr<FDEntry> write_fdp = _fdArray[prs];
+
+            /* Now cast it and make sure that we are still sane. */
+            auto write_pfd = std::dynamic_pointer_cast<PipeFDEntry>(write_fdp);
+
+            /* Hook up the write end back to the right side of the pipe. */
+            write_pfd->setSimFD(fd_pair[1]);
+        }
+
+        /* Need to reassign 'driver'. */
+        if (auto dfd = std::dynamic_pointer_cast<DeviceFDEntry>(fdp)) {
+            /**
+             * Yeah, how does one retain the entire driver state from this
+             * particular set of code? If you figure it out, add some code
+             * here to rectify the issue.
+             */
+            fatal("Unable to restore checkpoints with emulated drivers");
+        }
+
+        /* Need to open files and seek. */
+        if (auto ffd = std::dynamic_pointer_cast<FileFDEntry>(fdp)) {
+            /**
+             * Assume that this has the mode of an output file so there's no
+             * need to worry about properly recording the mode. If you're
+             * reading this and this happens to be your issue, at least be
+             * happy that you've discovered the issue (and not mad at me).
+             * Onward ho!
+             */
+            int sim_fd = openFile(ffd->getFileName(), ffd->getFlags(), 0664);
+            ffd->setSimFD(sim_fd);
+            seek(ffd);
+        }
+    }
+}
+
+int
+FDArray::allocFD(std::shared_ptr<FDEntry> in)
+{
+    for (int i = 0; i < _fdArray.size(); i++) {
+        std::shared_ptr<FDEntry> fdp = _fdArray[i];
+        if (!fdp) {
+            _fdArray[i] = in;
+            return i;
+        }
+    }
+    fatal("Out of target file descriptors");
+}
+
+int
+FDArray::openFile(std::string const& filename, int flags, mode_t mode) const
+{
+    int sim_fd = open(filename.c_str(), flags, mode);
+    if (sim_fd != -1)
+        return sim_fd;
+    fatal("Unable to open %s with mode %O", filename, mode);
+}
+
+int
+FDArray::openInputFile(std::string const& filename) const
+{
+    return openFile(filename, O_RDONLY, 00);
+}
+
+int
+FDArray::openOutputFile(std::string const& filename) const
+{
+    return openFile(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
+}
+
+std::shared_ptr<FDEntry>
+FDArray::getFDEntry(int tgt_fd)
+{
+    assert(0 <= tgt_fd && tgt_fd < _fdArray.size());
+    return _fdArray[tgt_fd];
+}
+
+int
+FDArray::closeFDEntry(int tgt_fd)
+{
+    if (tgt_fd >= _fdArray.size() || tgt_fd < 0)
+        return -EBADF;
+
+    int sim_fd = -1;
+    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>(_fdArray[tgt_fd]);
+    if (hbfdp)
+        sim_fd = hbfdp->getSimFD();
+
+    int status = 0;
+    if (sim_fd > 2)
+        status = close(sim_fd);
+
+    if (status == 0)
+        _fdArray[tgt_fd] = nullptr;
+
+    return status;
+}
diff --git a/src/sim/fd_array.hh b/src/sim/fd_array.hh
new file mode 100644 (file)
index 0000000..1d57c46
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * For use for simulation and test purposes only
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Brandon Potter
+ */
+
+#ifndef __FD_ARRAY_HH__
+#define __FD_ARRAY_HH__
+
+#include <array>
+#include <memory>
+#include <string>
+
+#include "sim/fd_entry.hh"
+
+class FDArray
+{
+  private:
+    static const int NUM_FDS = 1024;
+
+  public:
+    /**
+     * Initialize the file descriptor array and set the standard file
+     * descriptors to defaults or values passed in with the process
+     * params.
+     * @param input Used to initialize the stdin file descriptor
+     * @param output Used to initialize the stdout file descriptor
+     * @param errout Used to initialize the stderr file descriptor
+     */
+    FDArray(std::string const& input, std::string const& output,
+            std::string const& errout);
+
+    std::string _input;
+    std::string _output;
+    std::string _errout;
+
+    /**
+     * Figure out the file offsets for all currently open files and save them
+     * the offsets during the calls to drain by the owning process.
+     */
+    void updateFileOffsets();
+
+    /**
+     * Restore all offsets for currently open files during the unserialize
+     * phase for the owning process class.
+     */
+    void restoreFileOffsets();
+
+    /**
+     * Treat this object like a normal array in using the subscript operator
+     * to pull entries out of it.
+     * @param tgt_fd Use target file descriptors to index the array.
+     */
+    inline std::shared_ptr<FDEntry>
+    operator[](int tgt_fd)
+    {
+        return getFDEntry(tgt_fd);
+    }
+
+    /**
+     * Step through the file descriptor array and find the first available
+     * entry which is denoted as being free by being a 'nullptr'. That file
+     * descriptor entry is the new target file descriptor entry that we
+     * return as the return parameter.
+     * @param fdp Allocated beforehand and passed into this method;
+     * the fdp is meant to be a generic pointer capable of pointing to
+     * different types of file descriptors. Must cast the pointer to the
+     * correct type before dereferencing to access the needed fields.
+     */
+    int allocFD(std::shared_ptr<FDEntry> fdp);
+
+    /**
+     * Return the size of the _fdArray field
+     */
+    int getSize() const { return _fdArray.size(); }
+
+    /**
+     * Try to close the host file descriptor. If successful, set the
+     * specified file descriptor entry object pointer to nullptr.
+     * Used to "close" the target file descriptor.
+     * @param tgt_fd Use target file descriptors to index the array.
+     */
+    int closeFDEntry(int tgt_fd);
+
+  private:
+    /**
+     * Help clarify our intention when opening files in the init and
+     * restoration code. These are helper functions which are not meant to
+     * be exposed to other objects or files.
+     */
+    int openFile(std::string const& file_name, int flags, mode_t mode) const;
+    int openInputFile(std::string const& file_name) const;
+    int openOutputFile(std::string const& file_name) const;
+
+    /**
+     * Return the file descriptor entry object associated with the index
+     * provided. (The index is protected with bounds checking on the array
+     * size without the use of the array's at operator.)
+     * @param tgt_fd Use target file descriptors to index the array.
+     */
+    std::shared_ptr<FDEntry> getFDEntry(int tgt_fd);
+
+    /**
+     * Hold pointers to the file descriptor entries. The array size is
+     * statically defined by the operating system.
+     */
+    std::array<std::shared_ptr<FDEntry>, NUM_FDS> _fdArray;
+
+    /**
+     * Hold strings which represent the default values which are checked
+     * against to initialize the standard file descriptors. If the string
+     * provided doesn't hit against these maps, then a file is opened on the
+     * host instead of using the host's standard file descriptors.
+     */
+    std::map<std::string, int> imap;
+    std::map<std::string, int> oemap;
+};
+
+#endif // __FD_ARRAY_HH__
index 72975a7a6686cb512c5e629765bfb1344de453a5..65bf7a81c40b3533b076031927f796a8ce9afef6 100644 (file)
 /*
- * Copyright (c) 2015 Advanced Micro Devices, Inc.
- * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * Copyright (c) 2016 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * For use for simulation and test purposes only
  *
  * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
  *
- * Authors: Nathan Binkert
- *          Steve Reinhardt
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Brandon Potter
  */
 
-#include "base/misc.hh"
-#include "fd_entry.hh"
+#include "sim/fd_entry.hh"
 
-using namespace std;
+#include "sim/serialize.hh"
 
 void
 FDEntry::serialize(CheckpointOut &cp) const
 {
-    SERIALIZE_SCALAR(fd);
-    if (fd != -1) {
-        SERIALIZE_SCALAR(mode);
-        SERIALIZE_SCALAR(flags);
-        SERIALIZE_SCALAR(isPipe);
-        SERIALIZE_SCALAR(readPipeSource);
-        SERIALIZE_SCALAR(fileOffset);
-        SERIALIZE_SCALAR(filename);
-    }
-    if (driver)
-        warn("EmulatedDriver objects do not currently support checkpoints");
+    SERIALIZE_SCALAR(_closeOnExec);
 }
 
 void
 FDEntry::unserialize(CheckpointIn &cp)
 {
-    UNSERIALIZE_SCALAR(fd);
-    if (fd != -1) {
-        UNSERIALIZE_SCALAR(mode);
-        UNSERIALIZE_SCALAR(flags);
-        UNSERIALIZE_SCALAR(isPipe);
-        UNSERIALIZE_SCALAR(readPipeSource);
-        UNSERIALIZE_SCALAR(fileOffset);
-        UNSERIALIZE_SCALAR(filename);
-    }
-    driver = NULL;
+    UNSERIALIZE_SCALAR(_closeOnExec);
 }
 
-bool
-FDEntry::isFree()
+void
+FileFDEntry::serialize(CheckpointOut &cp) const
+{
+    SERIALIZE_SCALAR(_closeOnExec);
+    SERIALIZE_SCALAR(_flags);
+    SERIALIZE_SCALAR(_fileName);
+    SERIALIZE_SCALAR(_fileOffset);
+}
+
+void
+FileFDEntry::unserialize(CheckpointIn &cp)
+{
+    UNSERIALIZE_SCALAR(_closeOnExec);
+    UNSERIALIZE_SCALAR(_flags);
+    UNSERIALIZE_SCALAR(_fileName);
+    UNSERIALIZE_SCALAR(_fileOffset);
+}
+
+void
+PipeFDEntry::serialize(CheckpointOut &cp) const
+{
+    SERIALIZE_SCALAR(_closeOnExec);
+    SERIALIZE_SCALAR(_flags);
+    //SERIALIZE_SCALAR(_pipeEndType);
+}
+
+void
+PipeFDEntry::unserialize(CheckpointIn &cp)
 {
-    return (fd == -1 && driver == NULL);
+    UNSERIALIZE_SCALAR(_closeOnExec);
+    UNSERIALIZE_SCALAR(_flags);
+    //UNSERIALIZE_SCALAR(_pipeEndType);
 }
 
 void
-FDEntry::set(int sim_fd, const string name, int flags, int mode, bool pipe)
+DeviceFDEntry::serialize(CheckpointOut &cp) const
 {
-    fd = sim_fd;
-    filename = name;
-    this->flags = flags;
-    this->mode = mode;
-    isPipe = pipe;
-    fileOffset = 0;
-    readPipeSource = 0;
-    driver = NULL;
+    SERIALIZE_SCALAR(_closeOnExec);
+    //SERIALIZE_SCALAR(_driver);
+    SERIALIZE_SCALAR(_fileName);
 }
 
 void
-FDEntry::reset()
+DeviceFDEntry::unserialize(CheckpointIn &cp)
 {
-    set(-1, "", 0, 0, false);
+    UNSERIALIZE_SCALAR(_closeOnExec);
+    //UNSERIALIZE_SCALAR(_driver);
+    UNSERIALIZE_SCALAR(_fileName);
 }
index fd68ba50b378feb2e77e82fd244aac272d4e8cd3..950d1b74094f71df9167c1eb299163ba383feaff 100644 (file)
@@ -1,37 +1,42 @@
 /*
- * Copyright (c) 2015 Advanced Micro Devices, Inc.
- * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * Copyright (c) 2016 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * For use for simulation and test purposes only
  *
  * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
  *
- * Authors: Nathan Binkert
- *          Steve Reinhardt
+ * Author: Brandon Potter
  */
 
 #ifndef __FD_ENTRY_HH__
 #define __FD_ENTRY_HH__
 
+#include <memory>
 #include <ostream>
 #include <string>
 
 class EmulatedDriver;
 
 /**
- * FDEntry is used to manage a single file descriptor mapping and metadata
- * for processes.
- * Note that the fields are all declared publicly since system calls have a
- * habit of only needing to access a single field at a time and accessor
- * methods seem like overkill.
+ * Holds a single file descriptor mapping and that mapping's data for
+ * processes running in syscall emulation mode.
  */
 class FDEntry : public Serializable
 {
   public:
-    /**
-     * Constructor contains default values
-     * The file descriptor is free.
-     */
-    FDEntry()
-        : fd(-1), mode(0), flags(0), isPipe(false), readPipeSource(0),
-          fileOffset(0), filename(""), driver(NULL)
+    FDEntry(bool close_on_exec = false)
+        : _closeOnExec(close_on_exec)
+    { }
+
+    virtual std::shared_ptr<FDEntry> clone() const = 0;
+
+    inline bool getCOE() const { return _closeOnExec; }
+
+    inline void setCOE(bool close_on_exec) { _closeOnExec = close_on_exec; }
+
+    virtual void serialize(CheckpointOut &cp) const;
+    virtual void unserialize(CheckpointIn &cp);
+
+  protected:
+    bool _closeOnExec;
+};
+
+/**
+ * Extends the base class to include a host-backed file descriptor field
+ * that records the integer used to represent the file descriptor on the host
+ * and the file's flags.
+ */
+class HBFDEntry: public FDEntry
+{
+  public:
+    HBFDEntry(int flags, int sim_fd, bool close_on_exec = false)
+        : FDEntry(close_on_exec), _flags(flags), _simFD(sim_fd)
     { }
 
+    inline int getFlags() const { return _flags; }
+    inline int getSimFD() const { return _simFD; }
+
+    inline void setFlags(int flags) { _flags = flags; }
+    inline void setSimFD(int sim_fd) { _simFD = sim_fd; }
+
+  protected:
+    int _flags;
+    int _simFD;
+};
+
+/**
+ * Holds file descriptors for host-backed files; host-backed files are
+ * files which were opened on the physical machine where the simulation
+ * is running (probably the thing on/under your desk). All regular files
+ * are redirected to make it appear that the file descriptor assignment
+ * starts at file descriptor '3' (not including stdin, stdout, stderr) and
+ * then grows upward.
+ */
+class FileFDEntry: public HBFDEntry
+{
+  public:
+    FileFDEntry(int sim_fd, int flags, std::string const& file_name,
+                uint64_t file_offset, bool close_on_exec = false)
+        : HBFDEntry(flags, sim_fd, close_on_exec),
+          _fileName(file_name), _fileOffset(file_offset)
+    { }
+
+    FileFDEntry(FileFDEntry const& reg, bool close_on_exec = false)
+        : HBFDEntry(reg._flags, reg._simFD, close_on_exec),
+          _fileName(reg._fileName), _fileOffset(reg._fileOffset)
+    { }
+
+    inline std::shared_ptr<FDEntry>
+    clone() const override
+    {
+        return std::make_shared<FileFDEntry>(*this);
+    }
+
+    inline std::string getFileName() const { return _fileName; }
+    inline uint64_t getFileOffset() const { return _fileOffset; }
+
+    inline void setFileName(std::string file_name) { _fileName = file_name; }
+    inline void setFileOffset (uint64_t f_off) { _fileOffset = f_off; }
+
+    void serialize(CheckpointOut &cp) const override;
+    void unserialize(CheckpointIn &cp) override;
+
+  private:
+    std::string _fileName;
+    uint64_t _fileOffset;
+};
+
+/**
+ * Holds the metadata needed to maintain the mappings for file descriptors
+ * allocated with the pipe() system calls and its variants.
+ */
+class PipeFDEntry: public HBFDEntry
+{
+  public:
+    enum EndType {
+        read = 0,
+        write = 1
+    };
+
+    PipeFDEntry(int sim_fd, int flags, EndType pipe_end_type,
+                bool close_on_exec = false)
+        : HBFDEntry(flags, sim_fd, close_on_exec), _pipeReadSource(-1),
+          _pipeEndType(pipe_end_type)
+    { }
+
+    PipeFDEntry(PipeFDEntry const& pipe, bool close_on_exec = false)
+        : HBFDEntry(pipe._flags, pipe._simFD, close_on_exec),
+          _pipeReadSource(pipe._pipeReadSource),
+          _pipeEndType(pipe._pipeEndType)
+    { }
+
+    inline std::shared_ptr<FDEntry>
+    clone() const override
+    {
+        return std::make_shared<PipeFDEntry>(*this);
+    }
+
+    inline EndType getEndType() const { return _pipeEndType; }
+    inline int getPipeReadSource() const { return _pipeReadSource; }
+
+    inline void setPipeReadSource(int tgt_fd) { _pipeReadSource = tgt_fd; }
+    inline void setEndType(EndType type) { _pipeEndType = type; }
+
+    void serialize(CheckpointOut &cp) const override;
+    void unserialize(CheckpointIn &cp) override;
+
+  private:
+    int _pipeReadSource;
+    EndType _pipeEndType;
+};
+
+/**
+ * Holds file descriptors needed to simulate devices opened with pseudo
+ * files (commonly with calls to ioctls).
+ */
+class DeviceFDEntry : public FDEntry
+{
+  public:
+    DeviceFDEntry(EmulatedDriver *driver, std::string const& file_name,
+                  bool close_on_exec = false)
+        : FDEntry(close_on_exec), _driver(driver), _fileName(file_name)
+    { }
+
+    DeviceFDEntry(DeviceFDEntry const& dev, bool close_on_exec = false)
+        : FDEntry(close_on_exec), _driver(dev._driver),
+          _fileName(dev._fileName)
+    { }
+
+    std::shared_ptr<FDEntry>
+    clone() const override
+    {
+        return std::make_shared<DeviceFDEntry>(*this);
+    }
+
+    inline EmulatedDriver *getDriver() const { return _driver; }
+    inline std::string getFileName() const { return _fileName; }
+
     void serialize(CheckpointOut &cp) const override;
     void unserialize(CheckpointIn &cp) override;
 
-    /**
-     * Check if the target file descriptor is in use.
-     * @return value denoting if target file descriptor already used
-     */
-    bool isFree();
-
-    /**
-     * Fill in members for this file descriptor entry.
-     * @param sim_fd host file descriptor
-     * @param name filename string
-     * @param flags current flags of the file descriptor
-     * @param mode current mode of the file descriptor
-     * @param pipe denotes whether the file descriptor belongs to a pipe
-     */
-    void set(int sim_fd, const std::string name, int flags, int mode,
-             bool pipe);
-
-    /** Reset members to their default values. */
-    void reset();
-
-    int fd;
-    int mode;
-    int flags;
-    bool isPipe;
-    int readPipeSource;
-    uint64_t fileOffset;
-    std::string filename;
-    EmulatedDriver *driver;
+  private:
+    EmulatedDriver *_driver;
+    std::string _fileName;
 };
 
 #endif // __FD_ENTRY_HH__
index 9510fd71db17094c93799b1a7ce32cce96d79b58..4c44f408625b0481d32f14575b1ac86ef70395ac 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  * Copyright (c) 2012 ARM Limited
  * All rights reserved
  *
@@ -41,6 +41,7 @@
  * Authors: Nathan Binkert
  *          Steve Reinhardt
  *          Ali Saidi
+ *          Brandon Potter
  */
 
 #include "sim/process.hh"
@@ -63,6 +64,8 @@
 #include "mem/se_translating_port_proxy.hh"
 #include "params/Process.hh"
 #include "sim/emul_driver.hh"
+#include "sim/fd_array.hh"
+#include "sim/fd_entry.hh"
 #include "sim/syscall_desc.hh"
 #include "sim/system.hh"
 
 using namespace std;
 using namespace TheISA;
 
-static int
-openFile(const string& filename, int flags, mode_t mode)
-{
-    int sim_fd = open(filename.c_str(), flags, mode);
-    if (sim_fd != -1)
-        return sim_fd;
-    fatal("Unable to open %s with mode %O", filename, mode);
-}
-
-static int
-openInputFile(const string &filename)
-{
-    return openFile(filename, O_RDONLY, 0);
-}
-
-static int
-openOutputFile(const string &filename)
-{
-    return openFile(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
-}
-
 Process::Process(ProcessParams * params, ObjectFile * obj_file)
     : SimObject(params), system(params->system),
       brk_point(0), stack_base(0), stack_size(0), stack_min(0),
@@ -124,58 +106,16 @@ Process::Process(ProcessParams * params, ObjectFile * obj_file)
         static_cast<PageTableBase *>(new FuncPageTable(name(), params->pid))),
       initVirtMem(system->getSystemPort(), this,
                   SETranslatingPortProxy::Always),
-      fd_array(make_shared<array<FDEntry, NUM_FDS>>()),
-      imap {{"",       -1},
-            {"cin",    STDIN_FILENO},
-            {"stdin",  STDIN_FILENO}},
-      oemap{{"",       -1},
-            {"cout",   STDOUT_FILENO},
-            {"stdout", STDOUT_FILENO},
-            {"cerr",   STDERR_FILENO},
-            {"stderr", STDERR_FILENO}},
       objFile(obj_file),
       argv(params->cmd), envp(params->env), cwd(params->cwd),
       executable(params->executable),
       _uid(params->uid), _euid(params->euid),
       _gid(params->gid), _egid(params->egid),
       _pid(params->pid), _ppid(params->ppid),
-      drivers(params->drivers)
+      drivers(params->drivers),
+      fds(make_shared<FDArray>(params->input, params->output, params->errout))
 {
-    int sim_fd;
-    std::map<string,int>::iterator it;
-
-    // Search through the input options and set fd if match is found;
-    // otherwise, open an input file and seek to location.
-    FDEntry *fde_stdin = getFDEntry(STDIN_FILENO);
-    if ((it = imap.find(params->input)) != imap.end())
-        sim_fd = it->second;
-    else
-        sim_fd = openInputFile(params->input);
-    fde_stdin->set(sim_fd, params->input, O_RDONLY, -1, false);
-
-    // Search through the output/error options and set fd if match is found;
-    // otherwise, open an output file and seek to location.
-    FDEntry *fde_stdout = getFDEntry(STDOUT_FILENO);
-    if ((it = oemap.find(params->output)) != oemap.end())
-        sim_fd = it->second;
-    else
-        sim_fd = openOutputFile(params->output);
-    fde_stdout->set(sim_fd, params->output, O_WRONLY | O_CREAT | O_TRUNC,
-                    0664, false);
-
-    FDEntry *fde_stderr = getFDEntry(STDERR_FILENO);
-    if (params->output == params->errout)
-        // Reuse the same file descriptor if these match.
-        sim_fd = fde_stdout->fd;
-    else if ((it = oemap.find(params->errout)) != oemap.end())
-        sim_fd = it->second;
-    else
-        sim_fd = openOutputFile(params->errout);
-    fde_stderr->set(sim_fd, params->errout, O_WRONLY | O_CREAT | O_TRUNC,
-                    0664, false);
-
     mmap_end = 0;
-    // other parameters will be initialized when the program is loaded
 
     // load up symbols, if any... these may be used for debugging or
     // profiling.
@@ -204,12 +144,6 @@ Process::regStats()
         ;
 }
 
-void
-Process::inheritFDArray(Process *p)
-{
-    fd_array = p->fd_array;
-}
-
 ThreadContext *
 Process::findFreeContext()
 {
@@ -239,57 +173,10 @@ Process::initState()
 DrainState
 Process::drain()
 {
-    findFileOffsets();
+    fds->updateFileOffsets();
     return DrainState::Drained;
 }
 
-int
-Process::allocFD(int sim_fd, const string& filename, int flags, int mode,
-                 bool pipe)
-{
-    for (int free_fd = 0; free_fd < fd_array->size(); free_fd++) {
-        FDEntry *fde = getFDEntry(free_fd);
-        if (fde->isFree()) {
-            fde->set(sim_fd, filename, flags, mode, pipe);
-            return free_fd;
-        }
-    }
-
-    fatal("Out of target file descriptors");
-}
-
-void
-Process::resetFDEntry(int tgt_fd)
-{
-    FDEntry *fde = getFDEntry(tgt_fd);
-    assert(fde->fd > -1);
-
-    fde->reset();
-}
-
-int
-Process::getSimFD(int tgt_fd)
-{
-    FDEntry *entry = getFDEntry(tgt_fd);
-    return entry ? entry->fd : -1;
-}
-
-FDEntry *
-Process::getFDEntry(int tgt_fd)
-{
-    assert(0 <= tgt_fd && tgt_fd < fd_array->size());
-    return &(*fd_array)[tgt_fd];
-}
-
-int
-Process::getTgtFD(int sim_fd)
-{
-    for (int index = 0; index < fd_array->size(); index++)
-        if ((*fd_array)[index].fd == sim_fd)
-            return index;
-    return -1;
-}
-
 void
 Process::allocateMem(Addr vaddr, int64_t size, bool clobber)
 {
@@ -324,127 +211,6 @@ Process::fixupStackFault(Addr vaddr)
     return false;
 }
 
-void
-Process::fixFileOffsets()
-{
-    auto seek = [] (FDEntry *fde)
-    {
-        if (lseek(fde->fd, fde->fileOffset, SEEK_SET) < 0)
-            fatal("Unable to see to location in %s", fde->filename);
-    };
-
-    std::map<string,int>::iterator it;
-
-    // Search through the input options and set fd if match is found;
-    // otherwise, open an input file and seek to location.
-    FDEntry *fde_stdin = getFDEntry(STDIN_FILENO);
-
-    // Check if user has specified a different input file, and if so, use it
-    // instead of the file specified in the checkpoint. This also resets the
-    // file offset from the checkpointed value
-    string new_in = ((ProcessParams*)params())->input;
-    if (new_in != fde_stdin->filename) {
-        warn("Using new input file (%s) rather than checkpointed (%s)\n",
-             new_in, fde_stdin->filename);
-        fde_stdin->filename = new_in;
-        fde_stdin->fileOffset = 0;
-    }
-
-    if ((it = imap.find(fde_stdin->filename)) != imap.end()) {
-        fde_stdin->fd = it->second;
-    } else {
-        fde_stdin->fd = openInputFile(fde_stdin->filename);
-        seek(fde_stdin);
-    }
-
-    // Search through the output/error options and set fd if match is found;
-    // otherwise, open an output file and seek to location.
-    FDEntry *fde_stdout = getFDEntry(STDOUT_FILENO);
-
-    // Check if user has specified a different output file, and if so, use it
-    // instead of the file specified in the checkpoint. This also resets the
-    // file offset from the checkpointed value
-    string new_out = ((ProcessParams*)params())->output;
-    if (new_out != fde_stdout->filename) {
-        warn("Using new output file (%s) rather than checkpointed (%s)\n",
-             new_out, fde_stdout->filename);
-        fde_stdout->filename = new_out;
-        fde_stdout->fileOffset = 0;
-    }
-
-    if ((it = oemap.find(fde_stdout->filename)) != oemap.end()) {
-        fde_stdout->fd = it->second;
-    } else {
-        fde_stdout->fd = openOutputFile(fde_stdout->filename);
-        seek(fde_stdout);
-    }
-
-    FDEntry *fde_stderr = getFDEntry(STDERR_FILENO);
-
-    // Check if user has specified a different error file, and if so, use it
-    // instead of the file specified in the checkpoint. This also resets the
-    // file offset from the checkpointed value
-    string new_err = ((ProcessParams*)params())->errout;
-    if (new_err != fde_stderr->filename) {
-        warn("Using new error file (%s) rather than checkpointed (%s)\n",
-             new_err, fde_stderr->filename);
-        fde_stderr->filename = new_err;
-        fde_stderr->fileOffset = 0;
-    }
-
-    if (fde_stdout->filename == fde_stderr->filename) {
-        // Reuse the same file descriptor if these match.
-        fde_stderr->fd = fde_stdout->fd;
-    } else if ((it = oemap.find(fde_stderr->filename)) != oemap.end()) {
-        fde_stderr->fd = it->second;
-    } else {
-        fde_stderr->fd = openOutputFile(fde_stderr->filename);
-        seek(fde_stderr);
-    }
-
-    for (int tgt_fd = 3; tgt_fd < fd_array->size(); tgt_fd++) {
-        FDEntry *fde = getFDEntry(tgt_fd);
-        if (fde->fd == -1)
-            continue;
-
-        if (fde->isPipe) {
-            if (fde->filename == "PIPE-WRITE")
-                continue;
-            assert(fde->filename == "PIPE-READ");
-
-            int fds[2];
-            if (pipe(fds) < 0)
-                fatal("Unable to create new pipe");
-
-            fde->fd = fds[0];
-
-            FDEntry *fde_write = getFDEntry(fde->readPipeSource);
-            assert(fde_write->filename == "PIPE-WRITE");
-            fde_write->fd = fds[1];
-        } else {
-            fde->fd = openFile(fde->filename.c_str(), fde->flags, fde->mode);
-            seek(fde);
-        }
-    }
-}
-
-void
-Process::findFileOffsets()
-{
-    for (auto& fde : *fd_array) {
-        if (fde.fd != -1)
-            fde.fileOffset = lseek(fde.fd, 0, SEEK_CUR);
-    }
-}
-
-void
-Process::setReadPipeSource(int read_pipe_fd, int source_fd)
-{
-    FDEntry *fde = getFDEntry(read_pipe_fd);
-    assert(source_fd >= -1);
-    fde->readPipeSource = source_fd;
-}
-
 void
 Process::serialize(CheckpointOut &cp) const
 {
@@ -455,9 +221,16 @@ Process::serialize(CheckpointOut &cp) const
     SERIALIZE_SCALAR(next_thread_stack_base);
     SERIALIZE_SCALAR(mmap_end);
     pTable->serialize(cp);
-    for (int x = 0; x < fd_array->size(); x++) {
-        (*fd_array)[x].serializeSection(cp, csprintf("FDEntry%d", x));
-    }
+    /**
+     * Checkpoints for file descriptors currently do not work. Need to
+     * come back and fix them at a later date.
+     */
+
+    warn("Checkpoints for file descriptors currently do not work.");
+#if 0
+    for (int x = 0; x < fds->getSize(); x++)
+        (*fds)[x].serializeSection(cp, csprintf("FDEntry%d", x));
+#endif
 
 }
 
@@ -471,11 +244,16 @@ Process::unserialize(CheckpointIn &cp)
     UNSERIALIZE_SCALAR(next_thread_stack_base);
     UNSERIALIZE_SCALAR(mmap_end);
     pTable->unserialize(cp);
-    for (int x = 0; x < fd_array->size(); x++) {
-        FDEntry *fde = getFDEntry(x);
-        fde->unserializeSection(cp, csprintf("FDEntry%d", x));
-    }
-    fixFileOffsets();
+    /**
+     * Checkpoints for file descriptors currently do not work. Need to
+     * come back and fix them at a later date.
+     */
+    warn("Checkpoints for file descriptors currently do not work.");
+#if 0
+    for (int x = 0; x < fds->getSize(); x++)
+        (*fds)[x]->unserializeSection(cp, csprintf("FDEntry%d", x));
+    fds->restoreFileOffsets();
+#endif
     // The above returns a bool so that you could do something if you don't
     // find the param in the checkpoint if you wanted to, like set a default
     // but in this case we'll just stick with the instantiated value if not
index dde1316284524532992d94b6ed5218cdf3f0e5d5..2191c3cd022a2a144edccbc71efeb967197935bc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  * Copyright (c) 2001-2005 The Regents of The University of Michigan
  * All rights reserved.
  *
@@ -28,6 +28,7 @@
  *
  * Authors: Nathan Binkert
  *          Steve Reinhardt
+ *          Brandon Potter
  */
 
 #ifndef __PROCESS_HH__
@@ -35,7 +36,6 @@
 
 #include <inttypes.h>
 
-#include <array>
 #include <map>
 #include <string>
 #include <vector>
@@ -45,6 +45,7 @@
 #include "base/types.hh"
 #include "config/the_isa.hh"
 #include "mem/se_translating_port_proxy.hh"
+#include "sim/fd_array.hh"
 #include "sim/fd_entry.hh"
 #include "sim/sim_object.hh"
 
@@ -115,42 +116,9 @@ class Process : public SimObject
     Addr getStartPC();
     ObjectFile *getInterpreter();
 
-    // inherit file descriptor map from another process (necessary for clone)
-    void inheritFDArray(Process *p);
-
     // override of virtual SimObject method: register statistics
     void regStats() override;
 
-    // generate new target fd for sim_fd
-    int allocFD(int sim_fd, const std::string& filename, int flags, int mode,
-                bool pipe);
-
-    // disassociate target fd with simulator fd and cleanup subsidiary fields
-    void resetFDEntry(int tgt_fd);
-
-    // look up simulator fd for given target fd
-    int getSimFD(int tgt_fd);
-
-    // look up fd entry for a given target fd
-    FDEntry *getFDEntry(int tgt_fd);
-
-    // look up target fd for given host fd
-    // Assumes a 1:1 mapping between target file descriptor and host file
-    // descriptor. Given the current API, this must be true given that it's
-    // not possible to map multiple target file descriptors to the same host
-    // file descriptor
-    int getTgtFD(int sim_fd);
-
-    // fix all offsets for currently open files and save them
-    void fixFileOffsets();
-
-    // find all offsets for currently open files and save them
-    void findFileOffsets();
-
-    // set the source of this read pipe for a checkpoint resume
-    void setReadPipeSource(int read_pipe_fd, int source_fd);
-
-
     void allocateMem(Addr vaddr, int64_t size, bool clobber = false);
 
     /// Attempt to fix up a fault at vaddr by allocating a page on the stack.
@@ -216,15 +184,6 @@ class Process : public SimObject
 
     SETranslatingPortProxy initVirtMem; // memory proxy for initial image load
 
-    static const int NUM_FDS = 1024;
-
-    // File descriptor remapping support.
-    std::shared_ptr<std::array<FDEntry, NUM_FDS>> fd_array;
-
-    // Standard file descriptor options for initialization and checkpoints.
-    std::map<std::string, int> imap;
-    std::map<std::string, int> oemap;
-
     ObjectFile *objFile;
     std::vector<std::string> argv;
     std::vector<std::string> envp;
@@ -243,6 +202,8 @@ class Process : public SimObject
 
     // Emulated drivers available to this process
     std::vector<EmulatedDriver *> drivers;
+
+    std::shared_ptr<FDArray> fds;
 };
 
 #endif // __PROCESS_HH__
index d77901fa7d7b7f90033b106fe2b6b661c9cfe770..f4bfca6c2bdbdbc014bdae3a213507ee0876b886 100644 (file)
@@ -172,16 +172,7 @@ closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
     int index = 0;
     int tgt_fd = p->getSyscallArg(tc, index);
 
-    int sim_fd = p->getSimFD(tgt_fd);
-    if (sim_fd < 0)
-        return -EBADF;
-
-    int status = 0;
-    if (sim_fd > 2)
-        status = close(sim_fd);
-    if (status >= 0)
-        p->resetFDEntry(tgt_fd);
-    return status;
+    return p->fds->closeFDEntry(tgt_fd);
 }
 
 
@@ -192,12 +183,13 @@ readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
     int tgt_fd = p->getSyscallArg(tc, index);
     Addr bufPtr = p->getSyscallArg(tc, index);
     int nbytes = p->getSyscallArg(tc, index);
-    BufferArg bufArg(bufPtr, nbytes);
 
-    int sim_fd = p->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
+    if (!hbfdp)
         return -EBADF;
+    int sim_fd = hbfdp->getSimFD();
 
+    BufferArg bufArg(bufPtr, nbytes);
     int bytes_read = read(sim_fd, bufArg.bufferPtr(), nbytes);
 
     if (bytes_read > 0)
@@ -213,12 +205,13 @@ writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
     int tgt_fd = p->getSyscallArg(tc, index);
     Addr bufPtr = p->getSyscallArg(tc, index);
     int nbytes = p->getSyscallArg(tc, index);
-    BufferArg bufArg(bufPtr, nbytes);
 
-    int sim_fd = p->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
+    if (!hbfdp)
         return -EBADF;
+    int sim_fd = hbfdp->getSimFD();
 
+    BufferArg bufArg(bufPtr, nbytes);
     bufArg.copyIn(tc->getMemProxy());
 
     int bytes_written = write(sim_fd, bufArg.bufferPtr(), nbytes);
@@ -237,9 +230,10 @@ lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
     uint64_t offs = p->getSyscallArg(tc, index);
     int whence = p->getSyscallArg(tc, index);
 
-    int sim_fd = p->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
+    if (!ffdp)
         return -EBADF;
+    int sim_fd = ffdp->getSimFD();
 
     off_t result = lseek(sim_fd, offs, whence);
 
@@ -257,9 +251,10 @@ _llseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
     Addr result_ptr = p->getSyscallArg(tc, index);
     int whence = p->getSyscallArg(tc, index);
 
-    int sim_fd = p->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
+    if (!ffdp)
         return -EBADF;
+    int sim_fd = ffdp->getSimFD();
 
     uint64_t offset = (offset_high << 32) | offset_low;
 
@@ -322,7 +317,7 @@ getcwdFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
         strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
         result = cwd.length();
     } else {
-        if (getcwd((char *)buf.bufferPtr(), size) != NULL) {
+        if (getcwd((char *)buf.bufferPtr(), size)) {
             result = strlen((char *)buf.bufferPtr());
         } else {
             result = -1;
@@ -484,16 +479,16 @@ truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 }
 
 SyscallReturn
-ftruncateFunc(SyscallDesc *desc, int num,
-              Process *process, ThreadContext *tc)
+ftruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 {
     int index = 0;
-    int tgt_fd = process->getSyscallArg(tc, index);
-    off_t length = process->getSyscallArg(tc, index);
+    int tgt_fd = p->getSyscallArg(tc, index);
+    off_t length = p->getSyscallArg(tc, index);
 
-    int sim_fd = process->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
+    if (!ffdp)
         return -EBADF;
+    int sim_fd = ffdp->getSimFD();
 
     int result = ftruncate(sim_fd, length);
     return (result == -1) ? -errno : result;
@@ -523,16 +518,16 @@ truncate64Func(SyscallDesc *desc, int num,
 }
 
 SyscallReturn
-ftruncate64Func(SyscallDesc *desc, int num,
-                Process *process, ThreadContext *tc)
+ftruncate64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 {
     int index = 0;
-    int tgt_fd = process->getSyscallArg(tc, index);
-    int64_t length = process->getSyscallArg(tc, index, 64);
+    int tgt_fd = p->getSyscallArg(tc, index);
+    int64_t length = p->getSyscallArg(tc, index, 64);
 
-    int sim_fd = process->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
+    if (!ffdp)
         return -EBADF;
+    int sim_fd = ffdp->getSimFD();
 
 #if NO_STAT64
     int result = ftruncate(sim_fd, length);
@@ -576,19 +571,20 @@ chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 }
 
 SyscallReturn
-fchownFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
+fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 {
     int index = 0;
-    int tgt_fd = process->getSyscallArg(tc, index);
+    int tgt_fd = p->getSyscallArg(tc, index);
 
-    int sim_fd = process->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
+    if (!ffdp)
         return -EBADF;
+    int sim_fd = ffdp->getSimFD();
 
     /* XXX endianess */
-    uint32_t owner = process->getSyscallArg(tc, index);
+    uint32_t owner = p->getSyscallArg(tc, index);
     uid_t hostOwner = owner;
-    uint32_t group = process->getSyscallArg(tc, index);
+    uint32_t group = p->getSyscallArg(tc, index);
     gid_t hostGroup = group;
 
     int result = fchown(sim_fd, hostOwner, hostGroup);
@@ -596,36 +592,47 @@ fchownFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
 }
 
 
+/**
+ * TODO: there's a bit more involved here since file descriptors created with
+ * dup are supposed to share a file description. So, there is a problem with
+ * maintaining fields like file offset or flags since an update to such a
+ * field won't be reflected in the metadata for the fd entries that we
+ * maintain to hold metadata for checkpoint restoration.
+ */
 SyscallReturn
-dupFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
+dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 {
     int index = 0;
-    int tgt_fd = process->getSyscallArg(tc, index);
+    int tgt_fd = p->getSyscallArg(tc, index);
 
-    int sim_fd = process->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
+    if (!old_hbfdp)
         return -EBADF;
-
-    FDEntry *fde = process->getFDEntry(tgt_fd);
+    int sim_fd = old_hbfdp->getSimFD();
 
     int result = dup(sim_fd);
-    return (result == -1) ? -errno :
-        process->allocFD(result, fde->filename, fde->flags, fde->mode, false);
+    int local_errno = errno;
+
+    std::shared_ptr<FDEntry> new_fdep = old_hbfdp->clone();
+    auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(new_fdep);
+    new_hbfdp->setSimFD(result);
+
+    return (result == -1) ? -local_errno : p->fds->allocFD(new_fdep);
 }
 
 
 SyscallReturn
-fcntlFunc(SyscallDesc *desc, int num, Process *process,
-          ThreadContext *tc)
+fcntlFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 {
     int index = 0;
-    int tgt_fd = process->getSyscallArg(tc, index);
+    int tgt_fd = p->getSyscallArg(tc, index);
 
-    int sim_fd = process->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
+    if (!hbfdp)
         return -EBADF;
+    int sim_fd = hbfdp->getSimFD();
 
-    int cmd = process->getSyscallArg(tc, index);
+    int cmd = p->getSyscallArg(tc, index);
     switch (cmd) {
       case 0: // F_DUPFD
         // if we really wanted to support this, we'd need to do it
@@ -659,17 +666,17 @@ fcntlFunc(SyscallDesc *desc, int num, Process *process,
 }
 
 SyscallReturn
-fcntl64Func(SyscallDesc *desc, int num, Process *process,
-            ThreadContext *tc)
+fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 {
     int index = 0;
-    int tgt_fd = process->getSyscallArg(tc, index);
+    int tgt_fd = p->getSyscallArg(tc, index);
 
-    int sim_fd = process->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
+    if (!hbfdp)
         return -EBADF;
+    int sim_fd = hbfdp->getSimFD();
 
-    int cmd = process->getSyscallArg(tc, index);
+    int cmd = p->getSyscallArg(tc, index);
     switch (cmd) {
       case 33: //F_GETLK64
         warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd);
@@ -694,21 +701,32 @@ SyscallReturn
 pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
                ThreadContext *tc)
 {
-    int fds[2], sim_fds[2];
-    int pipe_retval = pipe(fds);
+    int sim_fds[2], tgt_fds[2];
 
-    if (pipe_retval < 0) {
-        // error
+    int pipe_retval = pipe(sim_fds);
+    if (pipe_retval < 0)
         return pipe_retval;
-    }
 
-    sim_fds[0] = process->allocFD(fds[0], "PIPE-READ", O_WRONLY, -1, true);
-    sim_fds[1] = process->allocFD(fds[1], "PIPE-WRITE", O_RDONLY, -1, true);
+    auto rend = PipeFDEntry::EndType::read;
+    auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend);
+
+    auto wend = PipeFDEntry::EndType::write;
+    auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend);
+
+    tgt_fds[0] = process->fds->allocFD(rpfd);
+    tgt_fds[1] = process->fds->allocFD(wpfd);
 
-    process->setReadPipeSource(sim_fds[0], sim_fds[1]);
-    // Alpha Linux convention for pipe() is that fd[0] is returned as
-    // the return value of the function, and fd[1] is returned in r20.
-    tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]);
+    /**
+     * Now patch the read object to record the target file descriptor chosen
+     * as the write end of the pipe.
+     */
+    rpfd->setPipeReadSource(tgt_fds[1]);
+
+    /**
+     * Alpha Linux convention for pipe() is that fd[0] is returned as
+     * the return value of the function, and fd[1] is returned in r20.
+     */
+    tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]);
     return sim_fds[0];
 }
 
@@ -828,7 +846,7 @@ cloneFunc(SyscallDesc *desc, int callnum, Process *process,
     }
 
     ThreadContext* ctc; // child thread context
-    if ( ( ctc = process->findFreeContext() ) != NULL ) {
+    if ((ctc = process->findFreeContext())) {
         DPRINTF(SyscallVerbose, " Found unallocated thread context\n");
 
         ctc->clearArchRegs();
@@ -890,21 +908,21 @@ cloneFunc(SyscallDesc *desc, int callnum, Process *process,
 }
 
 SyscallReturn
-fallocateFunc(SyscallDesc *desc, int callnum, Process *process,
-              ThreadContext *tc)
+fallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
 {
 #if NO_FALLOCATE
     warn("Host OS cannot support calls to fallocate. Ignoring syscall");
 #else
     int index = 0;
-    int tgt_fd = process->getSyscallArg(tc, index);
-    int mode = process->getSyscallArg(tc, index);
-    off_t offset = process->getSyscallArg(tc, index);
-    off_t len = process->getSyscallArg(tc, index);
+    int tgt_fd = p->getSyscallArg(tc, index);
+    int mode = p->getSyscallArg(tc, index);
+    off_t offset = p->getSyscallArg(tc, index);
+    off_t len = p->getSyscallArg(tc, index);
 
-    int sim_fd = process->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
+    if (!ffdp)
         return -EBADF;
+    int sim_fd = ffdp->getSimFD();
 
     int result = fallocate(sim_fd, mode, offset, len);
     if (result < 0)
index c75784f79833cd6e7e6ef7f47fbfc900ffa637ce..376ae6f32c2dd495a628fe3658585258386bdd4d 100644 (file)
@@ -78,6 +78,7 @@
 #include <unistd.h>
 
 #include <cerrno>
+#include <memory>
 #include <string>
 
 #include "base/intmath.hh"
@@ -570,31 +571,35 @@ copyOutStatfsBuf(SETranslatingPortProxy &mem, Addr addr,
 /// not TTYs to provide repeatable results.
 template <class OS>
 SyscallReturn
-ioctlFunc(SyscallDesc *desc, int callnum, Process *process,
-          ThreadContext *tc)
+ioctlFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
 {
     int index = 0;
-    int tgt_fd = process->getSyscallArg(tc, index);
-    unsigned req = process->getSyscallArg(tc, index);
+    int tgt_fd = p->getSyscallArg(tc, index);
+    unsigned req = p->getSyscallArg(tc, index);
 
     DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req);
 
-    FDEntry *fde = process->getFDEntry(tgt_fd);
+    if (OS::isTtyReq(req))
+        return -ENOTTY;
 
-    if (fde == NULL) {
-        // doesn't map to any simulator fd: not a valid target fd
+    auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]);
+    if (!dfdp)
         return -EBADF;
-    }
 
-    if (fde->driver != NULL) {
-        return fde->driver->ioctl(process, tc, req);
-    }
-
-    if (OS::isTtyReq(req)) {
-        return -ENOTTY;
-    }
+    /**
+     * If the driver is valid, issue the ioctl through it. Otherwise,
+     * there's an implicit assumption that the device is a TTY type and we
+     * return that we do not have a valid TTY.
+     */
+    EmulatedDriver *emul_driver = dfdp->getDriver();
+    if (emul_driver)
+        return emul_driver->ioctl(p, tc, req);
 
-    warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n",
+    /**
+     * For lack of a better return code, return ENOTTY. Ideally, we should
+     * return something better here, but at least we issue the warning.
+     */
+    warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n",
          tgt_fd, req, tc->pcState());
     return -ENOTTY;
 }
@@ -645,7 +650,7 @@ openFunc(SyscallDesc *desc, int callnum, Process *process,
         }
 
         EmulatedDriver *drv = process->findDriver(filename);
-        if (drv != NULL) {
+        if (drv) {
             // the driver's open method will allocate a fd from the
             // process if necessary.
             return drv->open(process, tc, mode, hostFlags);
@@ -671,7 +676,9 @@ openFunc(SyscallDesc *desc, int callnum, Process *process,
     if (fd == -1)
         return -local_errno;
 
-    return process->allocFD(fd, path.c_str(), hostFlags, mode, false);
+    std::shared_ptr<FileFDEntry> ffdp =
+        std::make_shared<FileFDEntry>(fd, hostFlags, path.c_str(), false);
+    return process->fds->allocFD(ffdp);
 }
 
 /// Target open() handler.
@@ -827,28 +834,22 @@ chmodFunc(SyscallDesc *desc, int callnum, Process *process,
 /// Target fchmod() handler.
 template <class OS>
 SyscallReturn
-fchmodFunc(SyscallDesc *desc, int callnum, Process *process,
-           ThreadContext *tc)
+fchmodFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
 {
     int index = 0;
-    int tgt_fd = process->getSyscallArg(tc, index);
-    uint32_t mode = process->getSyscallArg(tc, index);
+    int tgt_fd = p->getSyscallArg(tc, index);
+    uint32_t mode = p->getSyscallArg(tc, index);
 
-    int sim_fd = process->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
+    if (!ffdp)
         return -EBADF;
+    int sim_fd = ffdp->getSimFD();
 
-    mode_t hostMode = 0;
+    mode_t hostMode = mode;
 
-    // XXX translate mode flags via OS::someting???
-    hostMode = mode;
-
-    // do the fchmod
     int result = fchmod(sim_fd, hostMode);
-    if (result < 0)
-        return -errno;
 
-    return 0;
+    return (result < 0) ? -errno : 0;
 }
 
 /// Target mremap() handler.
@@ -1021,16 +1022,16 @@ fstatat64Func(SyscallDesc *desc, int callnum, Process *process,
 /// Target fstat64() handler.
 template <class OS>
 SyscallReturn
-fstat64Func(SyscallDesc *desc, int callnum, Process *process,
-            ThreadContext *tc)
+fstat64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
 {
     int index = 0;
-    int tgt_fd = process->getSyscallArg(tc, index);
-    Addr bufPtr = process->getSyscallArg(tc, index);
+    int tgt_fd = p->getSyscallArg(tc, index);
+    Addr bufPtr = p->getSyscallArg(tc, index);
 
-    int sim_fd = process->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
+    if (!ffdp)
         return -EBADF;
+    int sim_fd = ffdp->getSimFD();
 
 #if NO_STAT64
     struct stat  hostBuf;
@@ -1115,18 +1116,18 @@ lstat64Func(SyscallDesc *desc, int callnum, Process *process,
 /// Target fstat() handler.
 template <class OS>
 SyscallReturn
-fstatFunc(SyscallDesc *desc, int callnum, Process *process,
-          ThreadContext *tc)
+fstatFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
 {
     int index = 0;
-    int tgt_fd = process->getSyscallArg(tc, index);
-    Addr bufPtr = process->getSyscallArg(tc, index);
+    int tgt_fd = p->getSyscallArg(tc, index);
+    Addr bufPtr = p->getSyscallArg(tc, index);
 
     DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd);
 
-    int sim_fd = process->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
+    if (!ffdp)
         return -EBADF;
+    int sim_fd = ffdp->getSimFD();
 
     struct stat hostBuf;
     int result = fstat(sim_fd, &hostBuf);
@@ -1176,16 +1177,16 @@ statfsFunc(SyscallDesc *desc, int callnum, Process *process,
 /// Target fstatfs() handler.
 template <class OS>
 SyscallReturn
-fstatfsFunc(SyscallDesc *desc, int callnum, Process *process,
-            ThreadContext *tc)
+fstatfsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
 {
     int index = 0;
-    int tgt_fd = process->getSyscallArg(tc, index);
-    Addr bufPtr = process->getSyscallArg(tc, index);
+    int tgt_fd = p->getSyscallArg(tc, index);
+    Addr bufPtr = p->getSyscallArg(tc, index);
 
-    int sim_fd = process->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
+    if (!ffdp)
         return -EBADF;
+    int sim_fd = ffdp->getSimFD();
 
     struct statfs hostBuf;
     int result = fstatfs(sim_fd, &hostBuf);
@@ -1202,29 +1203,29 @@ fstatfsFunc(SyscallDesc *desc, int callnum, Process *process,
 /// Target writev() handler.
 template <class OS>
 SyscallReturn
-writevFunc(SyscallDesc *desc, int callnum, Process *process,
-           ThreadContext *tc)
+writevFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
 {
     int index = 0;
-    int tgt_fd = process->getSyscallArg(tc, index);
+    int tgt_fd = p->getSyscallArg(tc, index);
 
-    int sim_fd = process->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
+    if (!hbfdp)
         return -EBADF;
+    int sim_fd = hbfdp->getSimFD();
 
-    SETranslatingPortProxy &p = tc->getMemProxy();
-    uint64_t tiov_base = process->getSyscallArg(tc, index);
-    size_t count = process->getSyscallArg(tc, index);
+    SETranslatingPortProxy &prox = tc->getMemProxy();
+    uint64_t tiov_base = p->getSyscallArg(tc, index);
+    size_t count = p->getSyscallArg(tc, index);
     struct iovec hiov[count];
     for (size_t i = 0; i < count; ++i) {
         typename OS::tgt_iovec tiov;
 
-        p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
-                   (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
+        prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
+                      (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
         hiov[i].iov_len = TheISA::gtoh(tiov.iov_len);
         hiov[i].iov_base = new char [hiov[i].iov_len];
-        p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
-                   hiov[i].iov_len);
+        prox.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
+                      hiov[i].iov_len);
     }
 
     int result = writev(sim_fd, hiov, count);
@@ -1296,19 +1297,19 @@ mmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
     int sim_fd = -1;
     uint8_t *pmap = nullptr;
     if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) {
-        // Check for EmulatedDriver mmap
-        FDEntry *fde = p->getFDEntry(tgt_fd);
-        if (fde == NULL)
-            return -EBADF;
+        std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
 
-        if (fde->driver != NULL) {
-            return fde->driver->mmap(p, tc, start, length, prot,
+        auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep);
+        if (dfdp) {
+            EmulatedDriver *emul_driver = dfdp->getDriver();
+            return emul_driver->mmap(p, tc, start, length, prot,
                                      tgt_flags, tgt_fd, offset);
         }
-        sim_fd = fde->fd;
 
-        if (sim_fd < 0)
+        auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
+        if (!ffdp)
             return -EBADF;
+        sim_fd = ffdp->getSimFD();
 
         pmap = (decltype(pmap))mmap(NULL, length, PROT_READ, MAP_PRIVATE,
                                     sim_fd, offset);
@@ -1393,9 +1394,9 @@ mmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
             Addr pc = tc->pcState().pc();
 
             if (pc >= text_start && pc < text_end) {
-                FDEntry *fde = p->getFDEntry(tgt_fd);
-
-                ObjectFile *lib = createObjectFile(fde->filename);
+                std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
+                auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
+                ObjectFile *lib = createObjectFile(ffdp->getFileName());
 
                 if (lib) {
                     lib->loadAllSymbols(debugSymbolTable,
@@ -1422,9 +1423,10 @@ pwrite64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
     int nbytes = p->getSyscallArg(tc, index);
     int offset = p->getSyscallArg(tc, index);
 
-    int sim_fd = p->getSimFD(tgt_fd);
-    if (sim_fd < 0)
+    auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]);
+    if (!ffdp)
         return -EBADF;
+    int sim_fd = ffdp->getSimFD();
 
     BufferArg bufArg(bufPtr, nbytes);
     bufArg.copyIn(tc->getMemProxy());