// 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