1
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 // Copyright 2005-2010 Google, Inc.
15 // Author: sorenj@google.com (Jeffrey Sorensen)
16
17 #include <fst/mapped-file.h>
18
19 #include <errno.h>
20 #include <fcntl.h>
21
22 namespace fst {
23
24 // Alignment required for mapping structures (in bytes.) Regions of memory
25 // that are not aligned upon a 128 bit boundary will be read from the file
26 // instead. This is consistent with the alignment boundary set in the
27 // const and compact fst code.
28 const int MappedFile::kArchAlignment = 16;
29
MappedFile(const MemoryRegion & region)30 MappedFile::MappedFile(const MemoryRegion ®ion) : region_(region) { }
31
~MappedFile()32 MappedFile::~MappedFile() {
33 if (region_.size != 0) {
34 if (region_.mmap != NULL) {
35 VLOG(1) << "munmap'ed " << region_.size << " bytes at " << region_.mmap;
36 if (munmap(region_.mmap, region_.size) != 0) {
37 LOG(ERROR) << "failed to unmap region: "<< strerror(errno);
38 }
39 } else {
40 operator delete(region_.data);
41 }
42 }
43 }
44
Allocate(size_t size)45 MappedFile* MappedFile::Allocate(size_t size) {
46 MemoryRegion region;
47 region.data = size == 0 ? NULL : operator new(size);
48 region.mmap = NULL;
49 region.size = size;
50 return new MappedFile(region);
51 }
52
Borrow(void * data)53 MappedFile* MappedFile::Borrow(void *data) {
54 MemoryRegion region;
55 region.data = data;
56 region.mmap = data;
57 region.size = 0;
58 return new MappedFile(region);
59 }
60
Map(istream * s,const FstReadOptions & opts,size_t size)61 MappedFile* MappedFile::Map(istream* s, const FstReadOptions &opts,
62 size_t size) {
63 std::streampos spos = s->tellg();
64 if (opts.mode == FstReadOptions::MAP && spos >= 0 &&
65 spos % kArchAlignment == 0) {
66 size_t pos = spos;
67 int fd = open(opts.source.c_str(), O_RDONLY);
68 if (fd != -1) {
69 int pagesize = getpagesize();
70 off_t offset = pos % pagesize;
71 off_t upsize = size + offset;
72 void *map = mmap(0, upsize, PROT_READ, MAP_SHARED, fd, pos - offset);
73 char *data = reinterpret_cast<char*>(map);
74 if (close(fd) == 0 && map != MAP_FAILED) {
75 MemoryRegion region;
76 region.mmap = map;
77 region.size = upsize;
78 region.data = reinterpret_cast<void*>(data + offset);
79 MappedFile *mmf = new MappedFile(region);
80 s->seekg(pos + size, ios::beg);
81 if (s) {
82 VLOG(1) << "mmap'ed region of " << size << " at offset " << pos
83 << " from " << opts.source.c_str() << " to addr " << map;
84 return mmf;
85 }
86 delete mmf;
87 } else {
88 LOG(INFO) << "Mapping of file failed: " << strerror(errno);
89 }
90 }
91 }
92 // If all else fails resort to reading from file into allocated buffer.
93 if (opts.mode != FstReadOptions::READ) {
94 LOG(WARNING) << "File mapping at offset " << spos << " of file "
95 << opts.source << " could not be honored, reading instead.";
96 }
97 MappedFile* mf = Allocate(size);
98 if (!s->read(reinterpret_cast<char*>(mf->mutable_data()), size)) {
99 delete mf;
100 return NULL;
101 }
102 return mf;
103 }
104
105 } // namespace fst
106