| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * 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. |
| */ |
| |
| #ifndef ART_SRC_MEM_MAP_H_ |
| #define ART_SRC_MEM_MAP_H_ |
| |
| #include <sys/mman.h> |
| |
| #include "utils.h" |
| |
| namespace art { |
| |
| // Used to keep track of mmap segments. |
| class MemMap { |
| public: |
| |
| // Request an anonymous region of a specified length. |
| // |
| // On success, returns returns a MemMap instance. On failure, returns a NULL; |
| static MemMap* Map(size_t length, int prot) { |
| return Map(NULL, length, prot); |
| } |
| |
| // Request an anonymous region of a specified length and a requested base address. |
| // |
| // On success, returns returns a MemMap instance. On failure, returns a NULL; |
| static MemMap* Map(byte* addr, size_t length, int prot) { |
| CHECK_NE(0U, length); |
| CHECK_NE(0, prot); |
| size_t page_aligned_size = RoundUp(length, kPageSize); |
| byte* actual = reinterpret_cast<byte*>(mmap(addr, |
| page_aligned_size, |
| prot, |
| MAP_PRIVATE | MAP_ANONYMOUS, |
| -1, |
| 0)); |
| if (actual == MAP_FAILED) { |
| PLOG(ERROR) << "mmap failed"; |
| return NULL; |
| } |
| return new MemMap(actual, length, actual, page_aligned_size); |
| } |
| |
| // Map part of a file, taking care of non-page aligned offsets. The |
| // "start" offset is absolute, not relative. |
| // |
| // On success, returns returns a MemMap instance. On failure, returns a NULL; |
| static MemMap* Map(size_t length, int prot, int flags, int fd, off_t start) { |
| return Map(NULL, length, prot, flags, fd, start); |
| } |
| |
| // Map part of a file, taking care of non-page aligned offsets. The |
| // "start" offset is absolute, not relative. This version allows |
| // requesting a specific address for the base of the mapping. |
| // |
| // On success, returns returns a MemMap instance. On failure, returns a NULL; |
| static MemMap* Map(byte* addr, size_t length, int prot, int flags, int fd, off_t start) { |
| CHECK_NE(0U, length); |
| CHECK_NE(0, prot); |
| CHECK(flags & MAP_SHARED || flags & MAP_PRIVATE); |
| // adjust to be page-aligned |
| int page_offset = start % kPageSize; |
| off_t page_aligned_offset = start - page_offset; |
| size_t page_aligned_size = RoundUp(length + page_offset, kPageSize); |
| byte* actual = reinterpret_cast<byte*>(mmap(addr, |
| page_aligned_size, |
| prot, |
| flags, |
| fd, |
| page_aligned_offset)); |
| if (actual == MAP_FAILED) { |
| PLOG(ERROR) << "mmap failed"; |
| return NULL; |
| } |
| return new MemMap(actual + page_offset, length, actual, page_aligned_size); |
| } |
| |
| ~MemMap() { |
| Unmap(); |
| } |
| |
| // Release a memory mapping, returning true on success or it was previously unmapped. |
| bool Unmap() { |
| if (base_addr_ == NULL && base_length_ == 0) { |
| return true; |
| } |
| int result = munmap(base_addr_, base_length_); |
| base_addr_ = NULL; |
| base_length_ = 0; |
| if (result == -1) { |
| return false; |
| } |
| return true; |
| } |
| |
| byte* GetAddress() const { |
| return addr_; |
| } |
| |
| size_t GetLength() const { |
| return length_; |
| } |
| |
| byte* GetLimit() const { |
| return addr_ + length_; |
| } |
| |
| private: |
| MemMap(byte* addr, size_t length, void* base_addr, size_t base_length) |
| : addr_(addr), length_(length), base_addr_(base_addr), base_length_(base_length) { |
| CHECK(addr_ != NULL); |
| CHECK(length_ != 0); |
| CHECK(base_addr_ != NULL); |
| CHECK(base_length_ != 0); |
| }; |
| |
| byte* addr_; // start of data |
| size_t length_; // length of data |
| |
| void* base_addr_; // page-aligned base address |
| size_t base_length_; // length of mapping |
| }; |
| |
| } // namespace art |
| |
| #endif // ART_SRC_MEM_MAP_H_ |