91b92ece5a5a227e96b69a06f3f79a5091d63762
[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 "Unix.h"
20 #include "llvm/System/Process.h"
21
22 #ifdef HAVE_FCNTL_H
23 #include <fcntl.h>
24 #endif
25
26 #ifdef HAVE_SYS_MMAN_H
27 #include <sys/mman.h>
28 #endif
29
30 #ifdef HAVE_SYS_STAT_H
31 #include <sys/stat.h>
32 #endif
33
34 namespace llvm {
35 using namespace sys;
36
37 struct sys::MappedFileInfo {
38   int   FD;
39   off_t Size;
40 };
41
42 bool MappedFile::initialize(std::string* ErrMsg) {
43   int mode = 0;
44   if (options_ & READ_ACCESS) 
45     if (options_ & WRITE_ACCESS)
46       mode = O_RDWR;
47     else
48       mode = O_RDONLY;
49   else if (options_ & WRITE_ACCESS)
50     mode = O_WRONLY;
51
52   int FD = ::open(path_.c_str(), mode);
53   if (FD < 0) {
54     MakeErrMsg(ErrMsg, "can't open file '" + path_.toString() + "'");
55     return true;
56   } 
57   const FileStatus *Status = path_.getFileStatus(false, ErrMsg);
58   if (!Status) {
59     ::close(FD);
60     return true;
61   }
62   info_ = new MappedFileInfo;
63   info_->FD = FD;
64   info_->Size = Status->getSize();
65   return false;
66 }
67
68 void MappedFile::terminate() {
69   assert(info_ && "MappedFile not initialized");
70   ::close(info_->FD);
71   delete info_;
72   info_ = 0;
73 }
74
75 void MappedFile::unmap() {
76   assert(info_ && "MappedFile not initialized");
77   if (isMapped()) {
78     if (options_ & WRITE_ACCESS)
79       ::msync(base_, info_->Size, MS_SYNC);
80     ::munmap(base_, info_->Size);
81     base_ = 0;  // Mark this as non-mapped.
82   }
83 }
84
85 void* MappedFile::map(std::string* ErrMsg) {
86   assert(info_ && "MappedFile not initialized");
87   if (!isMapped()) {
88     int prot = PROT_NONE;
89     int flags = 0;
90 #ifdef MAP_FILE
91     flags |= MAP_FILE;
92 #endif
93     if (options_ == 0) {
94       prot = PROT_READ;
95       flags = MAP_PRIVATE;
96     } else {
97       if (options_ & READ_ACCESS)
98         prot |= PROT_READ;
99       if (options_ & WRITE_ACCESS)
100         prot |= PROT_WRITE;
101       if (options_ & EXEC_ACCESS)
102         prot |= PROT_EXEC;
103       if (options_ & SHARED_MAPPING)
104         flags |= MAP_SHARED;
105       else
106         flags |= MAP_PRIVATE;
107     }
108     size_t map_size = ((info_->Size / Process::GetPageSize())+1) *
109       Process::GetPageSize();
110
111     base_ = ::mmap(0, map_size, prot, flags, info_->FD, 0);
112     if (base_ == MAP_FAILED) {
113       MakeErrMsg(ErrMsg, "Can't map file:" + path_.toString());
114       return 0;
115     }
116   }
117   return base_;
118 }
119
120 size_t MappedFile::size() const {
121   assert(info_ && "MappedFile not initialized");
122   return info_->Size;
123 }
124
125 bool MappedFile::size(size_t new_size, std::string* ErrMsg) {
126   assert(info_ && "MappedFile not initialized");
127
128   // Take the mapping out of memory
129   this->unmap();
130
131   // Adjust the current size to a page boundary
132   size_t cur_size = ((info_->Size / Process::GetPageSize())+1) *
133     Process::GetPageSize();
134
135   // Adjust the new_size to a page boundary
136   new_size = ((new_size / Process::GetPageSize())+1) *
137     Process::GetPageSize();
138
139   // If the file needs to be extended
140   if (new_size > cur_size) {
141     // Ensure we can allocate at least the idodes necessary to handle the
142     // file size requested. 
143     if ((off_t)-1 == ::lseek(info_->FD, new_size, SEEK_SET))
144       return MakeErrMsg(ErrMsg, "Can't lseek: ");
145     if (-1 == ::write(info_->FD, "\0", 1))
146       return MakeErrMsg(ErrMsg, "Can't write: ");
147   }
148
149   // Put the mapping back into memory.
150   return this->map(ErrMsg);
151 }
152
153 }
154