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