LLVM API Documentation
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 struct stat sbuf_; 00040 }; 00041 00042 void MappedFile::initialize() { 00043 if (path_.exists()) { 00044 info_ = new MappedFileInfo; 00045 int mode = 0; 00046 if (options_&READ_ACCESS) 00047 if (options_&WRITE_ACCESS) 00048 mode = O_RDWR; 00049 else 00050 mode = O_RDONLY; 00051 else if (options_&WRITE_ACCESS) 00052 mode = O_WRONLY; 00053 info_->fd_ = ::open(path_.c_str(),mode); 00054 00055 if (info_->fd_ < 0) { 00056 delete info_; 00057 info_ = 0; 00058 ThrowErrno(std::string("Can't open file: ") + path_.toString()); 00059 } 00060 struct stat sbuf; 00061 if(::fstat(info_->fd_, &info_->sbuf_) < 0) { 00062 ::close(info_->fd_); 00063 delete info_; 00064 info_ = 0; 00065 ThrowErrno(std::string("Can't stat file: ") + path_.toString()); 00066 } 00067 } else { 00068 throw std::string("Can't open file: ") + path_.toString(); 00069 } 00070 } 00071 00072 void MappedFile::terminate() { 00073 assert(info_ && "MappedFile not initialized"); 00074 if (info_->fd_ >= 0) 00075 ::close(info_->fd_); 00076 delete info_; 00077 info_ = 0; 00078 } 00079 00080 void MappedFile::unmap() { 00081 assert(info_ && "MappedFile not initialized"); 00082 if (isMapped()) { 00083 if (options_ & WRITE_ACCESS) 00084 ::msync(base_, info_->sbuf_.st_size, MS_SYNC); 00085 ::munmap(base_, info_->sbuf_.st_size); 00086 } 00087 } 00088 00089 void* MappedFile::map() { 00090 assert(info_ && "MappedFile not initialized"); 00091 if (!isMapped()) { 00092 int prot = PROT_NONE; 00093 int flags = 0; 00094 #ifdef MAP_FILE 00095 flags |= MAP_FILE; 00096 #endif 00097 if (options_ == 0) { 00098 prot = PROT_READ; 00099 flags = MAP_PRIVATE; 00100 } else { 00101 if (options_ & READ_ACCESS) 00102 prot |= PROT_READ; 00103 if (options_ & WRITE_ACCESS) 00104 prot |= PROT_WRITE; 00105 if (options_ & EXEC_ACCESS) 00106 prot |= PROT_EXEC; 00107 if (options_ & SHARED_MAPPING) 00108 flags |= MAP_SHARED; 00109 else 00110 flags |= MAP_PRIVATE; 00111 } 00112 size_t map_size = ((info_->sbuf_.st_size / Process::GetPageSize())+1) * 00113 Process::GetPageSize(); 00114 00115 base_ = ::mmap(0, map_size, prot, flags, info_->fd_, 0); 00116 if (base_ == MAP_FAILED) 00117 ThrowErrno(std::string("Can't map file:") + path_.toString()); 00118 } 00119 return base_; 00120 } 00121 00122 size_t MappedFile::size() const { 00123 assert(info_ && "MappedFile not initialized"); 00124 return info_->sbuf_.st_size; 00125 } 00126 00127 void MappedFile::size(size_t new_size) { 00128 assert(info_ && "MappedFile not initialized"); 00129 00130 // Take the mapping out of memory 00131 this->unmap(); 00132 00133 // Adjust the current size to a page boundary 00134 size_t cur_size = ((info_->sbuf_.st_size / Process::GetPageSize())+1) * 00135 Process::GetPageSize(); 00136 00137 // Adjust the new_size to a page boundary 00138 new_size = ((new_size / Process::GetPageSize())+1) * 00139 Process::GetPageSize(); 00140 00141 // If the file needs to be extended 00142 if (new_size > cur_size) { 00143 // Ensure we can allocate at least the idodes necessary to handle the 00144 // file size requested. 00145 ::lseek(info_->fd_, new_size, SEEK_SET); 00146 ::write(info_->fd_, "\0", 1); 00147 } 00148 00149 // Seek to current end of file. 00150 this->map(); 00151 } 00152 00153 } 00154