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 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