Revamp supported ops. Instead of just being supported or not, we now keep
[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   struct stat sbuf_;
40 };
41
42 void MappedFile::initialize() {
43   if (path_.exists()) {
44     info_ = new MappedFileInfo;
45     int mode = 0;
46     if (options_&READ_ACCESS) 
47       if (options_&WRITE_ACCESS)
48         mode = O_RDWR;
49       else
50         mode = O_RDONLY;
51     else if (options_&WRITE_ACCESS)
52       mode = O_WRONLY;
53     info_->fd_ = ::open(path_.c_str(),mode);
54     if (info_->fd_ < 0) {
55       delete info_;
56       info_ = 0;
57       ThrowErrno(std::string("Can't open file: ") + path_.toString());
58     }
59     struct stat sbuf;
60     if(::fstat(info_->fd_, &info_->sbuf_) < 0) {
61       ::close(info_->fd_);
62       delete info_;
63       info_ = 0;
64       ThrowErrno(std::string("Can't stat file: ") + path_.toString());
65     }
66   } else {
67     throw std::string("Can't open file: ") + path_.toString();
68   }
69 }
70
71 void MappedFile::terminate() {
72   assert(info_ && "MappedFile not initialized");
73   if (info_->fd_ >= 0)
74     ::close(info_->fd_);
75   delete info_;
76   info_ = 0;
77 }
78
79 void MappedFile::unmap() {
80   assert(info_ && "MappedFile not initialized");
81   if (isMapped()) {
82     if (options_ & WRITE_ACCESS)
83       ::msync(base_, info_->sbuf_.st_size, MS_SYNC);
84     ::munmap(base_, info_->sbuf_.st_size);
85   }
86 }
87
88 void* MappedFile::map() {
89   assert(info_ && "MappedFile not initialized");
90   if (!isMapped()) {
91     int prot = PROT_NONE;
92     int flags = 0;
93 #ifdef MAP_FILE
94     flags |= MAP_FILE;
95 #endif
96     if (options_ == 0) {
97       prot = PROT_READ;
98       flags = MAP_PRIVATE;
99     } else {
100       if (options_ & READ_ACCESS)
101         prot |= PROT_READ;
102       if (options_ & WRITE_ACCESS)
103         prot |= PROT_WRITE;
104       if (options_ & EXEC_ACCESS)
105         prot |= PROT_EXEC;
106       if (options_ & SHARED_MAPPING)
107         flags |= MAP_SHARED;
108       else
109         flags |= MAP_PRIVATE;
110     }
111     size_t map_size = ((info_->sbuf_.st_size / Process::GetPageSize())+1) *
112       Process::GetPageSize();
113
114     base_ = ::mmap(0, map_size, prot, flags, info_->fd_, 0);
115     if (base_ == MAP_FAILED)
116       ThrowErrno(std::string("Can't map file:") + path_.toString());
117   }
118   return base_;
119 }
120
121 size_t MappedFile::size() const {
122   assert(info_ && "MappedFile not initialized");
123   return info_->sbuf_.st_size;
124 }
125
126 void MappedFile::size(size_t new_size) {
127   assert(info_ && "MappedFile not initialized");
128
129   // Take the mapping out of memory
130   this->unmap();
131
132   // Adjust the current size to a page boundary
133   size_t cur_size = ((info_->sbuf_.st_size / Process::GetPageSize())+1) *
134     Process::GetPageSize();
135
136   // Adjust the new_size to a page boundary
137   new_size = ((new_size / Process::GetPageSize())+1) *
138     Process::GetPageSize();
139
140   // If the file needs to be extended
141   if (new_size > cur_size) {
142     // Ensure we can allocate at least the idodes necessary to handle the
143     // file size requested. 
144     ::lseek(info_->fd_, new_size, SEEK_SET);
145     ::write(info_->fd_, "\0", 1);
146   }
147
148   // Seek to current end of file. 
149   this->map();
150 }
151
152 }
153
154 // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab