12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/memory_mapped_file.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/mman.h> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/stat.h> 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <unistd.h> 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread_restrictions.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace base { 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0) { 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool MemoryMappedFile::MapFileRegionToMemory( 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const MemoryMappedFile::Region& region) { 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ThreadRestrictions::AssertIOAllowed(); 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) off_t map_start = 0; 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) size_t map_size = 0; 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int32 data_offset = 0; 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (region == MemoryMappedFile::Region::kWholeFile) { 285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int64 file_len = file_.GetLength(); 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (file_len == -1) { 305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DPLOG(ERROR) << "fstat " << file_.GetPlatformFile(); 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) map_size = static_cast<size_t>(file_len); 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) length_ = map_size; 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } else { 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // The region can be arbitrarily aligned. mmap, instead, requires both the 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // start and size to be page-aligned. Hence, we map here the page-aligned 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // outer region [|aligned_start|, |aligned_start| + |size|] which contains 395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // |region| and then add up the |data_offset| displacement. 405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int64 aligned_start = 0; 415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int64 aligned_size = 0; 425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CalculateVMAlignedBoundaries(region.offset, 435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) region.size, 445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &aligned_start, 455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &aligned_size, 465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &data_offset); 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Ensure that the casts in the mmap call below are sane. 495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (aligned_start < 0 || aligned_size < 0 || 505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) aligned_start > std::numeric_limits<off_t>::max() || 515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) static_cast<uint64>(aligned_size) > 525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::numeric_limits<size_t>::max() || 535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) static_cast<uint64>(region.size) > std::numeric_limits<size_t>::max()) { 545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DLOG(ERROR) << "Region bounds are not valid for mmap"; 555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) map_start = static_cast<off_t>(aligned_start); 595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) map_size = static_cast<size_t>(aligned_size); 605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) length_ = static_cast<size_t>(region.size); 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) data_ = static_cast<uint8*>(mmap(NULL, 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) map_size, 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PROT_READ, 665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) MAP_SHARED, 675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) file_.GetPlatformFile(), 685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) map_start)); 695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (data_ == MAP_FAILED) { 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DPLOG(ERROR) << "mmap " << file_.GetPlatformFile(); 715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) data_ += data_offset; 755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return true; 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void MemoryMappedFile::CloseHandles() { 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ThreadRestrictions::AssertIOAllowed(); 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (data_ != NULL) 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) munmap(data_, length_); 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) file_.Close(); 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) data_ = NULL; 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) length_ = 0; 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace base 90