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 22namespace 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. 28const int MappedFile::kArchAlignment = 16; 29 30MappedFile::MappedFile(const MemoryRegion ®ion) : region_(region) { } 31 32MappedFile::~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 45MappedFile* 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 53MappedFile* 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 61MappedFile* 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