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