LLVM API Documentation

Unix/MappedFile.inc

Go to the documentation of this file.
00001 //===- Unix/MappedFile.cpp - Unix MappedFile Implementation -----*- C++ -*-===//
00002 // 
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file was developed by Reid Spencer and is distributed under the 
00006 // University of Illinois Open Source License. See LICENSE.TXT for details.
00007 // 
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file provides the generic Unix implementation of the MappedFile concept.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 //===----------------------------------------------------------------------===//
00015 //=== WARNING: Implementation here must contain only generic UNIX code that
00016 //===          is guaranteed to work on *all* UNIX variants.
00017 //===----------------------------------------------------------------------===//
00018 
00019 #include "Unix.h"
00020 #include "llvm/System/Process.h"
00021 
00022 #ifdef HAVE_FCNTL_H
00023 #include <fcntl.h>
00024 #endif
00025 
00026 #ifdef HAVE_SYS_MMAN_H
00027 #include <sys/mman.h>
00028 #endif
00029 
00030 #ifdef HAVE_SYS_STAT_H
00031 #include <sys/stat.h>
00032 #endif
00033 
00034 namespace llvm {
00035 using namespace sys;
00036 
00037 struct sys::MappedFileInfo {
00038   int   FD;
00039   off_t Size;
00040 };
00041 
00042 void MappedFile::initialize() {
00043   int mode = 0;
00044   if (options_ & READ_ACCESS) 
00045     if (options_ & WRITE_ACCESS)
00046       mode = O_RDWR;
00047     else
00048       mode = O_RDONLY;
00049   else if (options_ & WRITE_ACCESS)
00050     mode = O_WRONLY;
00051 
00052   int FD = ::open(path_.c_str(), mode);
00053   if (FD < 0)
00054     ThrowErrno(std::string("Can't open file: ") + path_.toString());
00055 
00056   struct stat sbuf;
00057   if(::fstat(FD, &sbuf) < 0) {
00058     ::close(FD);
00059     ThrowErrno(std::string("Can't stat file: ") + path_.toString());
00060   }
00061   info_ = new MappedFileInfo;
00062   info_->FD = FD;
00063   info_->Size = sbuf.st_size;
00064 }
00065 
00066 void MappedFile::terminate() {
00067   assert(info_ && "MappedFile not initialized");
00068   ::close(info_->FD);
00069   delete info_;
00070   info_ = 0;
00071 }
00072 
00073 void MappedFile::unmap() {
00074   assert(info_ && "MappedFile not initialized");
00075   if (isMapped()) {
00076     if (options_ & WRITE_ACCESS)
00077       ::msync(base_, info_->Size, MS_SYNC);
00078     ::munmap(base_, info_->Size);
00079   }
00080 }
00081 
00082 void* MappedFile::map() {
00083   assert(info_ && "MappedFile not initialized");
00084   if (!isMapped()) {
00085     int prot = PROT_NONE;
00086     int flags = 0;
00087 #ifdef MAP_FILE
00088     flags |= MAP_FILE;
00089 #endif
00090     if (options_ == 0) {
00091       prot = PROT_READ;
00092       flags = MAP_PRIVATE;
00093     } else {
00094       if (options_ & READ_ACCESS)
00095         prot |= PROT_READ;
00096       if (options_ & WRITE_ACCESS)
00097         prot |= PROT_WRITE;
00098       if (options_ & EXEC_ACCESS)
00099         prot |= PROT_EXEC;
00100       if (options_ & SHARED_MAPPING)
00101         flags |= MAP_SHARED;
00102       else
00103         flags |= MAP_PRIVATE;
00104     }
00105     size_t map_size = ((info_->Size / Process::GetPageSize())+1) *
00106       Process::GetPageSize();
00107 
00108     base_ = ::mmap(0, map_size, prot, flags, info_->FD, 0);
00109     if (base_ == MAP_FAILED)
00110       ThrowErrno(std::string("Can't map file:") + path_.toString());
00111   }
00112   return base_;
00113 }
00114 
00115 size_t MappedFile::size() const {
00116   assert(info_ && "MappedFile not initialized");
00117   return info_->Size;
00118 }
00119 
00120 void MappedFile::size(size_t new_size) {
00121   assert(info_ && "MappedFile not initialized");
00122 
00123   // Take the mapping out of memory
00124   this->unmap();
00125 
00126   // Adjust the current size to a page boundary
00127   size_t cur_size = ((info_->Size / Process::GetPageSize())+1) *
00128     Process::GetPageSize();
00129 
00130   // Adjust the new_size to a page boundary
00131   new_size = ((new_size / Process::GetPageSize())+1) *
00132     Process::GetPageSize();
00133 
00134   // If the file needs to be extended
00135   if (new_size > cur_size) {
00136     // Ensure we can allocate at least the idodes necessary to handle the
00137     // file size requested. 
00138     ::lseek(info_->FD, new_size, SEEK_SET);
00139     ::write(info_->FD, "\0", 1);
00140   }
00141 
00142   // Seek to current end of file. 
00143   this->map();
00144 }
00145 
00146 }
00147