| |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // Copyright 2005-2010 Google, Inc. |
| // Author: sorenj@google.com (Jeffrey Sorensen) |
| |
| #include <fst/mapped-file.h> |
| |
| #include <errno.h> |
| #include <fcntl.h> |
| |
| namespace fst { |
| |
| // Alignment required for mapping structures (in bytes.) Regions of memory |
| // that are not aligned upon a 128 bit boundary will be read from the file |
| // instead. This is consistent with the alignment boundary set in the |
| // const and compact fst code. |
| const int MappedFile::kArchAlignment = 16; |
| |
| MappedFile::MappedFile(const MemoryRegion ®ion) : region_(region) { } |
| |
| MappedFile::~MappedFile() { |
| if (region_.size != 0) { |
| if (region_.mmap != NULL) { |
| VLOG(1) << "munmap'ed " << region_.size << " bytes at " << region_.mmap; |
| if (munmap(region_.mmap, region_.size) != 0) { |
| LOG(ERROR) << "failed to unmap region: "<< strerror(errno); |
| } |
| } else { |
| operator delete(region_.data); |
| } |
| } |
| } |
| |
| MappedFile* MappedFile::Allocate(size_t size) { |
| MemoryRegion region; |
| region.data = size == 0 ? NULL : operator new(size); |
| region.mmap = NULL; |
| region.size = size; |
| return new MappedFile(region); |
| } |
| |
| MappedFile* MappedFile::Borrow(void *data) { |
| MemoryRegion region; |
| region.data = data; |
| region.mmap = data; |
| region.size = 0; |
| return new MappedFile(region); |
| } |
| |
| MappedFile* MappedFile::Map(istream* s, const FstReadOptions &opts, |
| size_t size) { |
| std::streampos spos = s->tellg(); |
| if (opts.mode == FstReadOptions::MAP && spos >= 0 && |
| spos % kArchAlignment == 0) { |
| size_t pos = spos; |
| int fd = open(opts.source.c_str(), O_RDONLY); |
| if (fd != -1) { |
| int pagesize = getpagesize(); |
| off_t offset = pos % pagesize; |
| off_t upsize = size + offset; |
| void *map = mmap(0, upsize, PROT_READ, MAP_SHARED, fd, pos - offset); |
| char *data = reinterpret_cast<char*>(map); |
| if (close(fd) == 0 && map != MAP_FAILED) { |
| MemoryRegion region; |
| region.mmap = map; |
| region.size = upsize; |
| region.data = reinterpret_cast<void*>(data + offset); |
| MappedFile *mmf = new MappedFile(region); |
| s->seekg(pos + size, ios::beg); |
| if (s) { |
| VLOG(1) << "mmap'ed region of " << size << " at offset " << pos |
| << " from " << opts.source.c_str() << " to addr " << map; |
| return mmf; |
| } |
| delete mmf; |
| } else { |
| LOG(INFO) << "Mapping of file failed: " << strerror(errno); |
| } |
| } |
| } |
| // If all else fails resort to reading from file into allocated buffer. |
| if (opts.mode != FstReadOptions::READ) { |
| LOG(WARNING) << "File mapping at offset " << spos << " of file " |
| << opts.source << " could not be honored, reading instead."; |
| } |
| MappedFile* mf = Allocate(size); |
| if (!s->read(reinterpret_cast<char*>(mf->mutable_data()), size)) { |
| delete mf; |
| return NULL; |
| } |
| return mf; |
| } |
| |
| } // namespace fst |