diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc --- a/src/sim/syscall_emul.cc +++ b/src/sim/syscall_emul.cc @@ -171,16 +171,23 @@ { int index = 0; int tgt_fd = p->getSyscallArg(tc, index); + int sim_fd; - int sim_fd = p->getSimFD(tgt_fd); - if (sim_fd < 0) + FDEntryPtr fdp = p->fds[tgt_fd]; + + if (std::dynamic_pointer_cast(fdp) != nullptr) { + p->fds[tgt_fd] = nullptr; + return 0; + } + + if (fdp == nullptr || (sim_fd = fdp->getSimFD()) < 0) return -EBADF; int status = 0; if (sim_fd > 2) status = close(sim_fd); if (status >= 0) - p->resetFDEntry(tgt_fd); + p->fds[tgt_fd] = nullptr; return status; } @@ -193,9 +200,11 @@ Addr bufPtr = p->getSyscallArg(tc, index); int nbytes = p->getSyscallArg(tc, index); BufferArg bufArg(bufPtr, nbytes); + int sim_fd; - int sim_fd = p->getSimFD(tgt_fd); - if (sim_fd < 0) + FDEntryPtr fdp = p->fds[tgt_fd]; + + if (fdp == nullptr || (sim_fd = fdp->getSimFD()) < 0) return -EBADF; int bytes_read = read(sim_fd, bufArg.bufferPtr(), nbytes); @@ -214,9 +223,11 @@ Addr bufPtr = p->getSyscallArg(tc, index); int nbytes = p->getSyscallArg(tc, index); BufferArg bufArg(bufPtr, nbytes); + int sim_fd; - int sim_fd = p->getSimFD(tgt_fd); - if (sim_fd < 0) + FDEntryPtr fdp = p->fds[tgt_fd]; + + if (fdp == nullptr || (sim_fd = fdp->getSimFD()) < 0) return -EBADF; bufArg.copyIn(tc->getMemProxy()); @@ -236,9 +247,11 @@ int tgt_fd = p->getSyscallArg(tc, index); uint64_t offs = p->getSyscallArg(tc, index); int whence = p->getSyscallArg(tc, index); + int sim_fd; - int sim_fd = p->getSimFD(tgt_fd); - if (sim_fd < 0) + FileFDPtr ffd = std::dynamic_pointer_cast(p->fds[tgt_fd]); + + if (ffd == nullptr || (sim_fd = ffd->getSimFD()) < 0) return -EBADF; off_t result = lseek(sim_fd, offs, whence); @@ -256,9 +269,11 @@ uint32_t offset_low = p->getSyscallArg(tc, index); Addr result_ptr = p->getSyscallArg(tc, index); int whence = p->getSyscallArg(tc, index); + int sim_fd; - int sim_fd = p->getSimFD(tgt_fd); - if (sim_fd < 0) + FileFDPtr ffd = std::dynamic_pointer_cast(p->fds[tgt_fd]); + + if (ffd == nullptr || (sim_fd = ffd->getSimFD()) < 0) return -EBADF; uint64_t offset = (offset_high << 32) | offset_low; @@ -484,15 +499,16 @@ } 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; - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + FileFDPtr ffd = std::dynamic_pointer_cast(p->fds[tgt_fd]); + + if (ffd == nullptr || (sim_fd = ffd->getSimFD()) < 0) return -EBADF; int result = ftruncate(sim_fd, length); @@ -523,15 +539,16 @@ } 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; - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + FileFDPtr ffd = std::dynamic_pointer_cast(p->fds[tgt_fd]); + + if (ffd == nullptr || (sim_fd = ffd->getSimFD()) < 0) return -EBADF; #if NO_STAT64 @@ -576,19 +593,21 @@ } 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; - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + FileFDPtr ffd = std::dynamic_pointer_cast(p->fds[tgt_fd]); + + if (ffd == nullptr || (sim_fd = ffd->getSimFD()) < 0) return -EBADF; /* 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 +615,54 @@ } +/** + * 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) { int index = 0; int tgt_fd = process->getSyscallArg(tc, index); - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + FDEntryPtr old_fdp = process->fds[tgt_fd]; + + if (dynamic_pointer_cast(old_fdp) != nullptr) return -EBADF; - FDEntry *fde = process->getFDEntry(tgt_fd); + int sim_fd; + if (old_fdp == nullptr || (sim_fd = old_fdp->getSimFD()) < 0) + return -EBADF; int result = dup(sim_fd); - return (result == -1) ? -errno : - process->allocFD(result, fde->filename, fde->flags, fde->mode, false); + int local_errno = errno; + + FDEntryPtr new_fdp = old_fdp->clone(); + new_fdp->setSimFD(result); + + return (result == -1) ? -local_errno : process->fds.allocFD(new_fdp); } 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) + FDEntryPtr fdp = p->fds[tgt_fd]; + + if (dynamic_pointer_cast(fdp) != nullptr) return -EBADF; - int cmd = process->getSyscallArg(tc, index); + int sim_fd; + if (fdp == nullptr || (sim_fd = fdp->getSimFD()) < 0) + return -EBADF; + + 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 +696,21 @@ } 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) + FDEntryPtr fdp = p->fds[tgt_fd]; + + if (dynamic_pointer_cast(fdp) != nullptr) return -EBADF; - int cmd = process->getSyscallArg(tc, index); + int sim_fd = fdp->getSimFD(); + if (fdp == nullptr || (sim_fd = fdp->getSimFD()) < 0) + return -EBADF; + + 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 +735,34 @@ 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]; + int pipe_retval = pipe(sim_fds); if (pipe_retval < 0) { - // error 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); + PipeFDPtr read_pfd; + read_pfd = make_shared(sim_fds[0], O_WRONLY, + PipeFDEntry::EndType::read, true); - process->setReadPipeSource(sim_fds[0], sim_fds[1]); + PipeFDPtr write_pfd; + write_pfd = make_shared(sim_fds[1], O_RDONLY, + PipeFDEntry::EndType::write, true); + + /* Assign the pfds to the fd object and retrieve designated tgt_fds. */ + tgt_fds[0] = process->fds.allocFD(read_pfd); + tgt_fds[1] = process->fds.allocFD(write_pfd); + + /** + * Now patch the read object to record the target file descriptor chosen + * as the write end of the pipe. + */ + read_pfd->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, sim_fds[1]); + tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]); return sim_fds[0]; } diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh --- a/src/sim/syscall_emul.hh +++ b/src/sim/syscall_emul.hh @@ -67,6 +67,7 @@ #include #include +#include #include #include "base/intmath.hh" @@ -79,6 +80,7 @@ #include "cpu/thread_context.hh" #include "mem/page_table.hh" #include "sim/emul_driver.hh" +#include "sim/fd_entry.hh" #include "sim/process.hh" #include "sim/syscall_debug_macros.hh" #include "sim/syscall_emul_buf.hh" @@ -520,22 +522,35 @@ DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); - FDEntry *fde = process->getFDEntry(tgt_fd); + /** + * It only makes sense to call an ioctl on a device backed file. Grab the + * file descriptor from the file descriptor array owned by the object and + * then cast it into a DeviceFDEntry type. + */ + FDEntryPtr fdp = process->fds[tgt_fd]; + DeviceFDPtr dfd = std::dynamic_pointer_cast(fdp); - if (fde == NULL) { - // doesn't map to any simulator fd: not a valid target fd + if (dfd == nullptr) return -EBADF; + + /** + * 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 = dfd->getDriver(); + if (emul_driver != nullptr) { + return emul_driver->ioctl(process, tc, req); } - if (fde->driver != NULL) { - return fde->driver->ioctl(process, tc, req); - } + if (OS::isTtyReq(req)) + return -ENOTTY; - if (OS::isTtyReq(req)) { - return -ENOTTY; - } - - 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; } @@ -612,7 +627,9 @@ if (fd == -1) return -local_errno; - return process->allocFD(fd, path.c_str(), hostFlags, mode, false); + FileFDPtr ffd = + std::make_shared(fd, hostFlags, path.c_str(), false); + return process->fds.allocFD(ffd); } /// Target open() handler. @@ -767,15 +784,16 @@ /// Target fchmod() handler. template 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; - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + FileFDPtr ffd = std::dynamic_pointer_cast(p->fds[tgt_fd]); + + if (ffd == nullptr || (sim_fd = ffd->getSimFD()) < 0) return -EBADF; mode_t hostMode = 0; @@ -961,15 +979,16 @@ /// Target fstat64() handler. template 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; - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + FileFDPtr ffd = std::dynamic_pointer_cast(p->fds[tgt_fd]); + + if (ffd == nullptr || (sim_fd = ffd->getSimFD()) < 0) return -EBADF; #if NO_STAT64 @@ -1055,17 +1074,18 @@ /// Target fstat() handler. template 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); + int sim_fd; DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + FileFDPtr ffd = std::dynamic_pointer_cast(p->fds[tgt_fd]); + + if (ffd == nullptr || (sim_fd = ffd->getSimFD()) < 0) return -EBADF; struct stat hostBuf; @@ -1113,15 +1133,16 @@ /// Target fstatfs() handler. template 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; - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + FileFDPtr ffd = std::dynamic_pointer_cast(p->fds[tgt_fd]); + + if (ffd == nullptr || (sim_fd = ffd->getSimFD()) < 0) return -EBADF; struct statfs hostBuf; @@ -1139,29 +1160,33 @@ /// Target writev() handler. template 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; - int sim_fd = process->getSimFD(tgt_fd); - if (sim_fd < 0) + FDEntryPtr fdp = p->fds[tgt_fd]; + + if (std::dynamic_pointer_cast(fdp) != nullptr) return -EBADF; - SETranslatingPortProxy &p = tc->getMemProxy(); - uint64_t tiov_base = process->getSyscallArg(tc, index); - size_t count = process->getSyscallArg(tc, index); + if (fdp == nullptr || (sim_fd = fdp->getSimFD()) < 0) + return -EBADF; + + 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); @@ -1233,20 +1258,38 @@ 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) + /** + * First grab the correct file descriptor from file descriptor object. + * Still do not know if this file descriptor points to a driver or a + * regular file descriptor (backed by host file) at this point. + */ + FDEntryPtr fdp = p->fds[tgt_fd]; + if (fdp == nullptr) return -EBADF; - if (fde->driver != NULL) { - return fde->driver->mmap(p, tc, start, length, prot, + /** + * Cast the file descriptor into a device file descriptor type and + * then call the driver's mmap implementation if the file descriptor + * is a driver type. + */ + DeviceFDPtr dfd; + if ((dfd = std::dynamic_pointer_cast(fdp)) != nullptr) { + EmulatedDriver *emul_driver = dfd->getDriver(); + return emul_driver->mmap(p, tc, start, length, prot, tgt_flags, tgt_fd, offset); } - sim_fd = fde->fd; - if (sim_fd < 0) + /** + * By this point, we should be sure that the file descriptor is a + * regular file descriptor. + */ + FileFDPtr ffd = std::dynamic_pointer_cast(fdp); + + if (ffd == nullptr) return -EBADF; + sim_fd = ffd->getSimFD(); + pmap = (decltype(pmap))mmap(NULL, length, PROT_READ, MAP_PRIVATE, sim_fd, offset); @@ -1330,9 +1373,10 @@ Addr pc = tc->pcState().pc(); if (pc >= text_start && pc < text_end) { - FDEntry *fde = p->getFDEntry(tgt_fd); - - ObjectFile *lib = createObjectFile(fde->filename); + FDEntryPtr fdp = p->fds[tgt_fd]; + FileFDPtr ffd = + std::dynamic_pointer_cast(fdp); + ObjectFile *lib = createObjectFile(ffd->getFileName()); if (lib) { lib->loadAllSymbols(debugSymbolTable, @@ -1358,9 +1402,11 @@ Addr bufPtr = p->getSyscallArg(tc, index); int nbytes = p->getSyscallArg(tc, index); int offset = p->getSyscallArg(tc, index); + int sim_fd; - int sim_fd = p->getSimFD(tgt_fd); - if (sim_fd < 0) + FileFDPtr ffd = std::dynamic_pointer_cast(p->fds[tgt_fd]); + + if (ffd == nullptr || (sim_fd = ffd->getSimFD()) < 0) return -EBADF; BufferArg bufArg(bufPtr, nbytes); diff --git a/src/sim/process.hh b/src/sim/process.hh --- a/src/sim/process.hh +++ b/src/sim/process.hh @@ -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 -#include #include #include #include @@ -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 @@ 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 @@ SETranslatingPortProxy initVirtMem; // memory proxy for initial image load - static const int NUM_FDS = 1024; - - // File descriptor remapping support. - std::shared_ptr> fd_array; - - // Standard file descriptor options for initialization and checkpoints. - std::map imap; - std::map oemap; - ObjectFile *objFile; std::vector argv; std::vector envp; @@ -243,6 +202,8 @@ // Emulated drivers available to this process std::vector drivers; + + FDArray fds; }; #endif // __PROCESS_HH__ diff --git a/src/sim/process.cc b/src/sim/process.cc --- a/src/sim/process.cc +++ b/src/sim/process.cc @@ -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" @@ -95,27 +98,6 @@ 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), @@ -128,58 +110,16 @@ static_cast(new FuncPageTable(name(), _pid))), initVirtMem(system->getSystemPort(), this, SETranslatingPortProxy::Always), - fd_array(make_shared>()), - 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(params->input, params->output, params->errout) { - int sim_fd; - std::map::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. @@ -208,12 +148,6 @@ ; } -void -Process::inheritFDArray(Process *p) -{ - fd_array = p->fd_array; -} - ThreadContext * Process::findFreeContext() { @@ -243,57 +177,10 @@ 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) { @@ -329,91 +216,6 @@ } 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::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(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); - 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); - 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 { SERIALIZE_SCALAR(brk_point); @@ -423,9 +225,14 @@ 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)); - } +#if 0 + /** + * Checkpoints for file descriptors currently do not work. Need to + * come back and fix them at a later date. + */ + for (int x = 0; x < fds.getSize(); x++) + fds[x].serializeSection(cp, csprintf("FDEntry%d", x)); +#endif } @@ -439,11 +246,15 @@ 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(); +#if 0 + /** + * Checkpoints for file descriptors currently do not work. Need to + * come back and fix them at a later date. + */ + 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 diff --git a/src/sim/fd_entry.hh b/src/sim/fd_entry.hh --- a/src/sim/fd_entry.hh +++ b/src/sim/fd_entry.hh @@ -1,94 +1,205 @@ /* - * 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: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * Authors: Nathan Binkert - * Steve Reinhardt + * 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_ENTRY_HH__ #define __FD_ENTRY_HH__ +#include #include #include #include "sim/serialize.hh" class EmulatedDriver; +class FDEntry; +class FileFDEntry; +class PipeFDEntry; +class DeviceFDEntry; + +typedef std::shared_ptr FDEntryPtr; +typedef std::shared_ptr FileFDPtr; +typedef std::shared_ptr PipeFDPtr; +typedef std::shared_ptr DeviceFDPtr; /** - * 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, int sim_fd = -1) + : _closeOnExec(close_on_exec), _simFD(sim_fd) { } + virtual ~FDEntry() { } + + virtual FDEntryPtr clone() const = 0; + + bool getCOE() const { return _closeOnExec; } + int getSimFD() const { return _simFD; } + + void setCOE(bool close_on_exec) { _closeOnExec = close_on_exec; } + void setSimFD(int sim_fd) { _simFD = sim_fd; } + + virtual void serialize(CheckpointOut &cp) const; + virtual void unserialize(CheckpointIn &cp); + + protected: + bool _closeOnExec; + 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 FDEntry +{ + public: + FileFDEntry(int sim_fd, int flags, const std::string& file_name, + uint64_t file_offset, bool close_on_exec = false) + : FDEntry(close_on_exec, sim_fd), _flags(flags), _fileName(file_name), + _fileOffset(file_offset) + { } + + FileFDEntry(const FileFDEntry& reg, bool close_on_exec = false) + : FDEntry(close_on_exec, reg._simFD), _flags(reg._flags), + _fileName(reg._fileName), _fileOffset(reg._fileOffset) + { } + + ~FileFDEntry() { } + + FDEntryPtr clone() const { return std::make_shared(*this); } + + int getFlags() const { return _flags; } + std::string getFileName() const { return _fileName; } + uint64_t getFileOffset() const { return _fileOffset; } + + void setFlags(int flags) { _flags = flags; } + void setFileOffset (uint64_t file_offset) { _fileOffset = file_offset; } + 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(); + private: + int _flags; + std::string _fileName; + uint64_t _fileOffset; +}; - /** - * 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); +/** + * Holds the metadata needed to maintain the mappings for file descriptors + * allocated with the pipe() system calls and its variants. + */ +class PipeFDEntry: public FDEntry +{ + public: + enum EndType { + read = 0, + write = 1 + }; - /** Reset members to their default values. */ - void reset(); + PipeFDEntry(int sim_fd, int flags, EndType pipe_end_type, + bool close_on_exec = false) + : FDEntry(close_on_exec, sim_fd), _flags(flags), _pipeReadSource(-1), + _pipeEndType(pipe_end_type) + { } - int fd; - int mode; - int flags; - bool isPipe; - int readPipeSource; - uint64_t fileOffset; - std::string filename; - EmulatedDriver *driver; + PipeFDEntry(const PipeFDEntry& pipe, bool close_on_exec = false) + : FDEntry(close_on_exec, pipe._simFD), _flags(pipe._flags), + _pipeReadSource(pipe._pipeReadSource), + _pipeEndType(pipe._pipeEndType) + { } + + ~PipeFDEntry() { } + + FDEntryPtr clone() const { return std::make_shared(*this); } + + int getFlags() const { return _flags; } + EndType getEndType() const { return _pipeEndType; } + int getPipeReadSource() const { return _pipeReadSource; } + + void setFlags(int flags) { _flags = flags; } + void setPipeReadSource(int tgt_fd) { _pipeReadSource = tgt_fd; } + void setEndType(EndType type) { _pipeEndType = type; } + + void serialize(CheckpointOut &cp) const override; + void unserialize(CheckpointIn &cp) override; + + private: + int _flags; + 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, const std::string& file_name, + bool close_on_exec = false) + : FDEntry(close_on_exec), _driver(driver), _fileName(file_name) + { } + + DeviceFDEntry(const DeviceFDEntry& dev, bool close_on_exec = false) + : FDEntry(close_on_exec), _driver(dev._driver), + _fileName(dev._fileName) + { } + + ~DeviceFDEntry() { } + + FDEntryPtr clone() const + { return std::make_shared(*this); } + + EmulatedDriver *getDriver() const { return _driver; } + std::string getFileName() const { return _fileName; } + + void serialize(CheckpointOut &cp) const override; + void unserialize(CheckpointIn &cp) override; + + private: + EmulatedDriver *_driver; + std::string _fileName; }; #endif // __FD_ENTRY_HH__ diff --git a/src/sim/fd_entry.cc b/src/sim/fd_entry.cc --- a/src/sim/fd_entry.cc +++ b/src/sim/fd_entry.cc @@ -1,91 +1,100 @@ /* - * 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: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * Authors: Nathan Binkert - * Steve Reinhardt + * 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 "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; -} - -bool -FDEntry::isFree() -{ - return (fd == -1 && driver == NULL); + UNSERIALIZE_SCALAR(_closeOnExec); } void -FDEntry::set(int sim_fd, const string name, int flags, int mode, bool pipe) +FileFDEntry::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(_flags); + SERIALIZE_SCALAR(_fileName); + SERIALIZE_SCALAR(_fileOffset); } void -FDEntry::reset() +FileFDEntry::unserialize(CheckpointIn &cp) { - set(-1, "", 0, 0, false); + 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) +{ + UNSERIALIZE_SCALAR(_closeOnExec); + UNSERIALIZE_SCALAR(_flags); + //UNSERIALIZE_SCALAR(_pipeEndType); +} + +void +DeviceFDEntry::serialize(CheckpointOut &cp) const +{ + SERIALIZE_SCALAR(_closeOnExec); + //SERIALIZE_SCALAR(_driver); + SERIALIZE_SCALAR(_fileName); +} + +void +DeviceFDEntry::unserialize(CheckpointIn &cp) +{ + UNSERIALIZE_SCALAR(_closeOnExec); + //UNSERIALIZE_SCALAR(_driver); + UNSERIALIZE_SCALAR(_fileName); +} diff --git a/src/sim/fd_array.hh b/src/sim/fd_array.hh new file mode 100644 --- /dev/null +++ b/src/sim/fd_array.hh @@ -0,0 +1,149 @@ +/* + * 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 +#include +#include + +#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 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(); + + /** + * Share file descriptor array with another process by copying the value + * for the shared_pointer. Needed for the clone system call to make two + * processes point to the same object when the clone options specify + * that the file descriptors should be shared between the child and + * parent process. + * @param rhs_fds Passed from process which is not our owning process + */ + inline FDArray& + operator=(const FDArray &rhs_fds) + { + _fdArray = rhs_fds._fdArray; + return *this; + } + + /** + * Treat this object like a normal array by using the subscript operator + * to pull entries out of it. + * @param tgt_fd Use target file descriptors to index the array + */ + inline FDEntryPtr 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(FDEntryPtr fdp); + + /** + * Return the size of the _fdArray field + */ + int getSize() const { return _fdArray->size(); } + + 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(const std::string& file_name, int flags, mode_t mode); + int openInputFile(const std::string &file_name); + int openOutputFile(const std::string &file_name); + + /** + * 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.) This method is + * private as the usage of the subscript operator is preferred; however + * the subscript operator calls this as part of its implementation to + * provide the bounds checking. + * @param tgt_fd Use target file descriptors to index the array. + */ + FDEntryPtr getFDEntry(int tgt_fd); + + /** + * Hold pointers to the file descriptor entries. The array size is + * statically defined by the operating system. + */ + std::shared_ptr> _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 imap; + std::map oemap; +}; + +#endif // __FD_ARRAY_HH__ diff --git a/src/sim/fd_array.cc b/src/sim/fd_array.cc new file mode 100644 --- /dev/null +++ b/src/sim/fd_array.cc @@ -0,0 +1,293 @@ +/* + * 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 +#include + +#include +#include +#include + +#include "base/misc.hh" +#include "sim/fd_entry.hh" + +using namespace std; + +FDArray::FDArray(string input, string output, string errout) + : _fdArray(make_shared>()), + imap {{"", -1}, + {"cin", STDIN_FILENO}, + {"stdin", STDIN_FILENO}}, + oemap{{"", -1}, + {"cout", STDOUT_FILENO}, + {"stdout", STDOUT_FILENO}, + {"cerr", STDERR_FILENO}, + {"stderr", STDERR_FILENO}} +{ + FileFDPtr ffd; + map::iterator it; + int sim_fd; + + /** + * 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); + + ffd = make_shared(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 = make_shared(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 = make_shared(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. + */ + FileFDPtr ffd = dynamic_pointer_cast(fdp); + + if (ffd == nullptr) + 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. + */ + auto seek = [] (FileFDPtr ffd) + { + if (lseek(ffd->getSimFD(), ffd->getFileOffset(), SEEK_SET) < 0) + fatal("Unable to seek to location in %s", ffd->getFileName()); + }; + + map::iterator it; + + /** + * Search through the input options and set fd if match is found; + * otherwise, open an input file and seek to location. + */ + FileFDPtr stdin_ffd = + dynamic_pointer_cast((*_fdArray)[STDIN_FILENO]); + 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/error options and set fd if match is found; + * otherwise, open an output file and seek to location. + */ + FileFDPtr stdout_ffd = + dynamic_pointer_cast((*_fdArray)[STDOUT_FILENO]); + 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); + } + + FileFDPtr stderr_ffd = + dynamic_pointer_cast((*_fdArray)[STDERR_FILENO]); + 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++) { + FDEntryPtr fdp = (*_fdArray)[tgt_fd]; + if (fdp == nullptr) + continue; + + /* Need to reconnect pipe ends. */ + PipeFDPtr pfd = dynamic_pointer_cast(fdp); + if (pfd != nullptr) { + /** + * 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; + assert(pfd->getEndType() == PipeFDEntry::EndType::read); + assert(pfd->getPipeReadSource() != -1); + + /* 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. + */ + FDEntryPtr write_fdp = (*_fdArray)[pfd->getPipeReadSource()]; + assert(write_fdp != nullptr); + + /* Now cast it and make sure that we are still sane. */ + PipeFDPtr write_pfd = dynamic_pointer_cast(fdp); + assert(write_pfd->getEndType() == PipeFDEntry::EndType::write); + + /* Hook up the write end back to the right side of the pipe. */ + write_pfd->setSimFD(fd_pair[1]); + } + + /* Need to reassign 'driver'. */ + DeviceFDPtr dfd = dynamic_pointer_cast(fdp); + if (dfd != nullptr) { + /** + * 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. */ + FileFDPtr ffd = dynamic_pointer_cast(fdp); + if (ffd != nullptr) { + /** + * 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().c_str(), + ffd->getFlags(), 0664); + ffd->setSimFD(sim_fd); + seek(ffd); + } + } +} + +int +FDArray::allocFD(FDEntryPtr in) +{ + for (int i = 0; i < _fdArray->size(); i++) { + FDEntryPtr fdp = (*_fdArray)[i]; + if (fdp == nullptr) { + (*_fdArray)[i] = in; + return i; + } + } + fatal("Out of target file descriptors"); +} + +int +FDArray::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); +} + +int +FDArray::openInputFile(const string &filename) +{ + return openFile(filename, O_RDONLY, 00); +} + +int +FDArray::openOutputFile(const string &filename) +{ + return openFile(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664); +} + +FDEntryPtr +FDArray::getFDEntry(int tgt_fd) +{ + assert(0 <= tgt_fd && tgt_fd < _fdArray->size()); + return (*_fdArray)[tgt_fd]; +} diff --git a/src/sim/SConscript b/src/sim/SConscript --- a/src/sim/SConscript +++ b/src/sim/SConscript @@ -78,6 +78,7 @@ SimObject('Process.py') 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/gpu-compute/cl_driver.cc b/src/gpu-compute/cl_driver.cc --- a/src/gpu-compute/cl_driver.cc +++ b/src/gpu-compute/cl_driver.cc @@ -93,11 +93,9 @@ 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; + FDEntryPtr fdp = make_shared(this, filename); + int tgt_fd = p->allocFD(fdp); + return tgt_fd; } int diff --git a/src/kern/tru64/tru64.hh b/src/kern/tru64/tru64.hh --- a/src/kern/tru64/tru64.hh +++ b/src/kern/tru64/tru64.hh @@ -56,6 +56,8 @@ #include "cpu/base.hh" #include "debug/SyscallVerbose.hh" #include "sim/core.hh" +#include "sim/fd_array.hh" +#include "sim/fd_entry.hh" #include "sim/syscall_desc.hh" #include "sim/syscall_emul.hh" @@ -439,18 +441,26 @@ panic("getdirent not implemented on cygwin!"); #else int index = 0; - int fd = process->getSimFD(process->getSyscallArg(tc, index)); + int tgt_fd = process->getSyscallArg(tc, index); Addr tgt_buf = process->getSyscallArg(tc, index); int tgt_nbytes = process->getSyscallArg(tc, index); Addr tgt_basep = process->getSyscallArg(tc, index); + FDArray fda = process->fds; + FDEntryPtr fdp = fda[tgt_fd]; + FileFDPtr ffd = std::dynamic_pointer_cast(fdp); + assert(ffd != nullptr); + + int sim_fd = ffd->getSimFD(); + char * const host_buf = new char[tgt_nbytes]; // just pass basep through uninterpreted. TypedBufferArg basep(tgt_basep); basep.copyIn(tc->getMemProxy()); long host_basep = (off_t)htog((int64_t)*basep); - int host_result = getdirentries(fd, host_buf, tgt_nbytes, &host_basep); + int host_result = getdirentries(sim_fd, host_buf, tgt_nbytes, + &host_basep); // check for error if (host_result < 0) { # Node ID 7f3bf41cce5c71828ab9dc0247c44ce9ca5a0215 # Parent 19d45360c1ab03b2749573862a7131620d405d92 diff --git a/src/arch/sparc/process.hh b/src/arch/sparc/process.hh --- a/src/arch/sparc/process.hh +++ b/src/arch/sparc/process.hh @@ -74,8 +74,8 @@ { protected: - Sparc32Process(ProcessParams * params, ObjectFile *objFile) : - SparcProcess(params, objFile, 0) + Sparc32Process(ProcessParams * params, ObjectFile *objFile) + : SparcProcess(params, objFile, 0) { // Set up stack. On SPARC Linux, stack goes from the top of memory // downward, less the hole for the kernel address space. @@ -104,8 +104,8 @@ { protected: - Sparc64Process(ProcessParams * params, ObjectFile *objFile) : - SparcProcess(params, objFile, 2047) + Sparc64Process(ProcessParams * params, ObjectFile *objFile) + : SparcProcess(params, objFile, 2047) { // Set up stack. On SPARC Linux, stack goes from the top of memory // downward, less the hole for the kernel address space.