* Add a std::ostream inserter for sys::Path
[oota-llvm.git] / lib / System / Unix / MappedFile.inc
1 //===- Unix/MappedFile.cpp - Unix MappedFile Implementation -----*- C++ -*-===//
2 // 
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by Reid Spencer and is distributed under the 
6 // University of Illinois Open Source License. See LICENSE.TXT for details.
7 // 
8 //===----------------------------------------------------------------------===//
9 //
10 // This file provides the generic Unix implementation of the MappedFile concept.
11 //
12 //===----------------------------------------------------------------------===//
13
14 //===----------------------------------------------------------------------===//
15 //=== WARNING: Implementation here must contain only generic UNIX code that
16 //===          is guaranteed to work on *all* UNIX variants.
17 //===----------------------------------------------------------------------===//
18
19 #include "llvm/System/Process.h"
20 #include "Unix.h"
21 #include <fcntl.h>
22 #include <sys/mman.h>
23
24 namespace llvm {
25 using namespace sys;
26
27 struct sys::MappedFileInfo {
28   int fd_;
29   struct stat sbuf_;
30 };
31
32 void MappedFile::initialize() {
33   if (path_.exists()) {
34     info_ = new MappedFileInfo;
35     int mode = 0;
36     if (options_&READ_ACCESS) 
37       if (options_&WRITE_ACCESS)
38         mode = O_RDWR;
39       else
40         mode = O_RDONLY;
41     else if (options_&WRITE_ACCESS)
42       mode = O_WRONLY;
43     info_->fd_ = ::open(path_.c_str(),mode);
44     if (info_->fd_ < 0) {
45       delete info_;
46       info_ = 0;
47       ThrowErrno(std::string("Can't open file: ") + path_.toString());
48     }
49     struct stat sbuf;
50     if(::fstat(info_->fd_, &info_->sbuf_) < 0) {
51       ::close(info_->fd_);
52       delete info_;
53       info_ = 0;
54       ThrowErrno(std::string("Can't stat file: ") + path_.toString());
55     }
56   } else {
57     throw std::string("Can't open file: ") + path_.toString();
58   }
59 }
60
61 void MappedFile::terminate() {
62   assert(info_ && "MappedFile not initialized");
63   if (info_->fd_ >= 0)
64     ::close(info_->fd_);
65   delete info_;
66   info_ = 0;
67 }
68
69 void MappedFile::unmap() {
70   assert(info_ && "MappedFile not initialized");
71   if (isMapped()) {
72     if (options_ & WRITE_ACCESS)
73       ::msync(base_, info_->sbuf_.st_size, MS_SYNC);
74     ::munmap(base_, info_->sbuf_.st_size);
75   }
76 }
77
78 void* MappedFile::map() {
79   assert(info_ && "MappedFile not initialized");
80   if (!isMapped()) {
81     int prot = PROT_NONE;
82     int flags = 0;
83 #ifdef MAP_FILE
84     flags |= MAP_FILE;
85 #endif
86     if (options_ == 0) {
87       prot = PROT_READ;
88       flags = MAP_PRIVATE;
89     } else {
90       if (options_ & READ_ACCESS)
91         prot |= PROT_READ;
92       if (options_ & WRITE_ACCESS)
93         prot |= PROT_WRITE;
94       if (options_ & EXEC_ACCESS)
95         prot |= PROT_EXEC;
96       if (options_ & SHARED_MAPPING)
97         flags |= MAP_SHARED;
98       else
99         flags |= MAP_PRIVATE;
100     }
101     size_t map_size = ((info_->sbuf_.st_size / Process::GetPageSize())+1) *
102       Process::GetPageSize();
103
104     base_ = ::mmap(0, map_size, prot, flags, info_->fd_, 0);
105     if (base_ == MAP_FAILED)
106       ThrowErrno(std::string("Can't map file:") + path_.toString());
107   }
108   return base_;
109 }
110
111 size_t MappedFile::size() const {
112   assert(info_ && "MappedFile not initialized");
113   return info_->sbuf_.st_size;
114 }
115
116 void MappedFile::size(size_t new_size) {
117   assert(info_ && "MappedFile not initialized");
118
119   // Take the mapping out of memory
120   this->unmap();
121
122   // Adjust the current size to a page boundary
123   size_t cur_size = ((info_->sbuf_.st_size / Process::GetPageSize())+1) *
124     Process::GetPageSize();
125
126   // Adjust the new_size to a page boundary
127   new_size = ((new_size / Process::GetPageSize())+1) *
128     Process::GetPageSize();
129
130   // If the file needs to be extended
131   if (new_size > cur_size) {
132     // Ensure we can allocate at least the idodes necessary to handle the
133     // file size requested. 
134     ::lseek(info_->fd_, new_size, SEEK_SET);
135     ::write(info_->fd_, "\0", 1);
136   }
137
138   // Seek to current end of file. 
139   this->map();
140 }
141
142 }
143
144 // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab