blob: dcfd1892f84c72be7be425782626e9f1753ddc26 [file] [log] [blame]
Reid Spencer97374922004-10-04 11:08:32 +00001//===- Unix/MappedFile.cpp - Unix MappedFile Implementation -----*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner4ee451d2007-12-29 20:36:04 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Reid Spencer97374922004-10-04 11:08:32 +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
Reid Spencer97374922004-10-04 11:08:32 +000019#include "Unix.h"
Reid Spencercdf54d02004-12-27 06:16:52 +000020#include "llvm/System/Process.h"
21
22#ifdef HAVE_FCNTL_H
Tanya Lattnerc5a0bbf2004-10-05 00:51:26 +000023#include <fcntl.h>
Reid Spencercdf54d02004-12-27 06:16:52 +000024#endif
25
26#ifdef HAVE_SYS_MMAN_H
Reid Spencer97374922004-10-04 11:08:32 +000027#include <sys/mman.h>
Reid Spencercdf54d02004-12-27 06:16:52 +000028#endif
29
30#ifdef HAVE_SYS_STAT_H
31#include <sys/stat.h>
32#endif
Reid Spencer97374922004-10-04 11:08:32 +000033
Chris Lattner540630f2008-04-01 00:53:25 +000034using namespace llvm;
Reid Spencer97374922004-10-04 11:08:32 +000035using namespace sys;
36
Chris Lattner540630f2008-04-01 00:53:25 +000037namespace llvm {
38 namespace sys {
39 struct MappedFileInfo {
40 int FD;
41 off_t Size;
42 };
43 }
44}
Reid Spencer97374922004-10-04 11:08:32 +000045
Reid Spencer6d045fc2006-08-22 16:04:22 +000046bool MappedFile::initialize(std::string* ErrMsg) {
Chris Lattnerc22c7d32006-07-18 06:52:52 +000047 int mode = 0;
Chris Lattner540630f2008-04-01 00:53:25 +000048 if (Options & READ_ACCESS)
49 if (Options & WRITE_ACCESS)
Chris Lattnerc22c7d32006-07-18 06:52:52 +000050 mode = O_RDWR;
51 else
52 mode = O_RDONLY;
Chris Lattner540630f2008-04-01 00:53:25 +000053 else if (Options & WRITE_ACCESS)
Chris Lattnerc22c7d32006-07-18 06:52:52 +000054 mode = O_WRONLY;
Chris Lattnerc22c7d32006-07-18 06:52:52 +000055
Chris Lattner540630f2008-04-01 00:53:25 +000056 int FD = ::open(Path.c_str(), mode);
Reid Spencer6d045fc2006-08-22 16:04:22 +000057 if (FD < 0) {
Chris Lattner540630f2008-04-01 00:53:25 +000058 MakeErrMsg(ErrMsg, "can't open file '" + Path.toString() + "'");
Reid Spencer6d045fc2006-08-22 16:04:22 +000059 return true;
60 }
Chris Lattner540630f2008-04-01 00:53:25 +000061 const FileStatus *Status = Path.getFileStatus(false, ErrMsg);
Reid Spencer1ea733d2007-03-29 19:11:22 +000062 if (!Status) {
Chris Lattnercca68fa2006-07-18 06:57:51 +000063 ::close(FD);
Reid Spencer6d045fc2006-08-22 16:04:22 +000064 return true;
Reid Spencer97374922004-10-04 11:08:32 +000065 }
Chris Lattner540630f2008-04-01 00:53:25 +000066 MapInfo = new MappedFileInfo();
67 MapInfo->FD = FD;
68 MapInfo->Size = Status->getSize();
Reid Spencer6d045fc2006-08-22 16:04:22 +000069 return false;
Reid Spencer97374922004-10-04 11:08:32 +000070}
71
72void MappedFile::terminate() {
Chris Lattner540630f2008-04-01 00:53:25 +000073 assert(MapInfo && "MappedFile not initialized");
74 ::close(MapInfo->FD);
75 delete MapInfo;
76 MapInfo = 0;
Reid Spencer97374922004-10-04 11:08:32 +000077}
78
79void MappedFile::unmap() {
Chris Lattner540630f2008-04-01 00:53:25 +000080 assert(MapInfo && "MappedFile not initialized");
81 if (!isMapped()) return;
82
83 if (Options & WRITE_ACCESS)
84 ::msync(BasePtr, MapInfo->Size, MS_SYNC);
85 ::munmap(BasePtr, MapInfo->Size);
86 BasePtr = 0; // Mark this as non-mapped.
Reid Spencer97374922004-10-04 11:08:32 +000087}
88
Reid Spencer6d045fc2006-08-22 16:04:22 +000089void* MappedFile::map(std::string* ErrMsg) {
Chris Lattner540630f2008-04-01 00:53:25 +000090 assert(MapInfo && "MappedFile not initialized");
91 if (isMapped()) return BasePtr;
92
93 int prot = PROT_NONE;
94 int flags = 0;
Chris Lattner341e1da2004-10-05 00:46:21 +000095#ifdef MAP_FILE
Chris Lattner540630f2008-04-01 00:53:25 +000096 flags |= MAP_FILE;
Chris Lattner341e1da2004-10-05 00:46:21 +000097#endif
Chris Lattner540630f2008-04-01 00:53:25 +000098 if (Options == 0) {
99 prot = PROT_READ;
100 flags = MAP_PRIVATE;
101 } else {
102 if (Options & READ_ACCESS)
103 prot |= PROT_READ;
104 if (Options & WRITE_ACCESS)
105 prot |= PROT_WRITE;
106 if (Options & EXEC_ACCESS)
107 prot |= PROT_EXEC;
108 if (Options & SHARED_MAPPING)
109 flags |= MAP_SHARED;
110 else
111 flags |= MAP_PRIVATE;
Reid Spencer97374922004-10-04 11:08:32 +0000112 }
Chris Lattner540630f2008-04-01 00:53:25 +0000113 size_t map_size = ((MapInfo->Size / Process::GetPageSize())+1) *
114 Process::GetPageSize();
115
116 BasePtr = ::mmap(0, map_size, prot, flags, MapInfo->FD, 0);
117 if (BasePtr == MAP_FAILED) {
118 MakeErrMsg(ErrMsg, "Can't map file:" + Path.toString());
119 return 0;
120 }
121 return BasePtr;
Reid Spencer97374922004-10-04 11:08:32 +0000122}
123
Reid Spencer56c3ed82004-12-13 02:58:51 +0000124size_t MappedFile::size() const {
Chris Lattner540630f2008-04-01 00:53:25 +0000125 assert(MapInfo && "MappedFile not initialized");
126 return MapInfo->Size;
Reid Spencer97374922004-10-04 11:08:32 +0000127}
128
Chris Lattner540630f2008-04-01 00:53:25 +0000129bool MappedFile::resize(size_t new_size, std::string* ErrMsg) {
130 assert(MapInfo && "MappedFile not initialized");
Reid Spencer97374922004-10-04 11:08:32 +0000131
132 // Take the mapping out of memory
Chris Lattner540630f2008-04-01 00:53:25 +0000133 unmap();
Reid Spencer97374922004-10-04 11:08:32 +0000134
135 // Adjust the current size to a page boundary
Chris Lattner540630f2008-04-01 00:53:25 +0000136 size_t cur_size = ((MapInfo->Size / Process::GetPageSize())+1) *
Reid Spencer97374922004-10-04 11:08:32 +0000137 Process::GetPageSize();
138
139 // Adjust the new_size to a page boundary
140 new_size = ((new_size / Process::GetPageSize())+1) *
141 Process::GetPageSize();
142
143 // If the file needs to be extended
144 if (new_size > cur_size) {
145 // Ensure we can allocate at least the idodes necessary to handle the
146 // file size requested.
Chris Lattner540630f2008-04-01 00:53:25 +0000147 if ((off_t)-1 == ::lseek(MapInfo->FD, new_size, SEEK_SET))
Reid Spencer05545752006-08-25 21:37:17 +0000148 return MakeErrMsg(ErrMsg, "Can't lseek: ");
Chris Lattner540630f2008-04-01 00:53:25 +0000149 if (-1 == ::write(MapInfo->FD, "\0", 1))
Reid Spencer05545752006-08-25 21:37:17 +0000150 return MakeErrMsg(ErrMsg, "Can't write: ");
Reid Spencer97374922004-10-04 11:08:32 +0000151 }
152
Reid Spencer6d045fc2006-08-22 16:04:22 +0000153 // Put the mapping back into memory.
Chris Lattner540630f2008-04-01 00:53:25 +0000154 return map(ErrMsg);
Reid Spencer97374922004-10-04 11:08:32 +0000155}