blob: 546a226ef3185e28abc61428ab1ce56d3e9e2461 [file] [log] [blame]
Dan Gohmanf17a25c2007-07-18 16:29:46 +00001//===- Unix/MappedFile.cpp - Unix MappedFile Implementation -----*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner081ce942007-12-29 20:36:04 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Dan Gohmanf17a25c2007-07-18 16:29:46 +00007//
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
34namespace llvm {
35using namespace sys;
36
37struct sys::MappedFileInfo {
38 int FD;
39 off_t Size;
40};
41
42bool 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
68void MappedFile::terminate() {
69 assert(info_ && "MappedFile not initialized");
70 ::close(info_->FD);
71 delete info_;
72 info_ = 0;
73}
74
75void 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
85void* 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
120size_t MappedFile::size() const {
121 assert(info_ && "MappedFile not initialized");
122 return info_->Size;
123}
124
125bool 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