1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "MemoryHeapPmem" 18 19#include <stdlib.h> 20#include <stdint.h> 21#include <unistd.h> 22#include <fcntl.h> 23#include <errno.h> 24#include <sys/types.h> 25#include <sys/stat.h> 26#include <sys/ioctl.h> 27 28#include <cutils/log.h> 29 30#include <binder/MemoryHeapPmem.h> 31#include <binder/MemoryHeapBase.h> 32 33#if HAVE_ANDROID_OS 34#include <linux/android_pmem.h> 35#endif 36 37namespace android { 38 39// --------------------------------------------------------------------------- 40 41MemoryHeapPmem::MemoryPmem::MemoryPmem(const sp<MemoryHeapPmem>& heap) 42 : BnMemory(), mClientHeap(heap) 43{ 44} 45 46MemoryHeapPmem::MemoryPmem::~MemoryPmem() { 47 if (mClientHeap != NULL) { 48 mClientHeap->remove(this); 49 } 50} 51 52// --------------------------------------------------------------------------- 53 54class SubRegionMemory : public MemoryHeapPmem::MemoryPmem { 55public: 56 SubRegionMemory(const sp<MemoryHeapPmem>& heap, ssize_t offset, size_t size); 57 virtual ~SubRegionMemory(); 58 virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const; 59private: 60 friend class MemoryHeapPmem; 61 void revoke(); 62 size_t mSize; 63 ssize_t mOffset; 64}; 65 66SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap, 67 ssize_t offset, size_t size) 68 : MemoryHeapPmem::MemoryPmem(heap), mSize(size), mOffset(offset) 69{ 70#ifndef NDEBUG 71 void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + offset); 72 memset(start_ptr, 0xda, size); 73#endif 74 75#if HAVE_ANDROID_OS 76 if (size > 0) { 77 const size_t pagesize = getpagesize(); 78 size = (size + pagesize-1) & ~(pagesize-1); 79 int our_fd = heap->heapID(); 80 struct pmem_region sub = { offset, size }; 81 int err = ioctl(our_fd, PMEM_MAP, &sub); 82 LOGE_IF(err<0, "PMEM_MAP failed (%s), " 83 "mFD=%d, sub.offset=%lu, sub.size=%lu", 84 strerror(errno), our_fd, sub.offset, sub.len); 85} 86#endif 87} 88 89sp<IMemoryHeap> SubRegionMemory::getMemory(ssize_t* offset, size_t* size) const 90{ 91 if (offset) *offset = mOffset; 92 if (size) *size = mSize; 93 return getHeap(); 94} 95 96SubRegionMemory::~SubRegionMemory() 97{ 98 revoke(); 99} 100 101 102void SubRegionMemory::revoke() 103{ 104 // NOTE: revoke() doesn't need to be protected by a lock because it 105 // can only be called from MemoryHeapPmem::revoke(), which means 106 // that we can't be in ~SubRegionMemory(), or in ~SubRegionMemory(), 107 // which means MemoryHeapPmem::revoke() wouldn't have been able to 108 // promote() it. 109 110#if HAVE_ANDROID_OS 111 if (mSize != 0) { 112 const sp<MemoryHeapPmem>& heap(getHeap()); 113 int our_fd = heap->heapID(); 114 struct pmem_region sub; 115 sub.offset = mOffset; 116 sub.len = mSize; 117 int err = ioctl(our_fd, PMEM_UNMAP, &sub); 118 LOGE_IF(err<0, "PMEM_UNMAP failed (%s), " 119 "mFD=%d, sub.offset=%lu, sub.size=%lu", 120 strerror(errno), our_fd, sub.offset, sub.len); 121 mSize = 0; 122 } 123#endif 124} 125 126// --------------------------------------------------------------------------- 127 128MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap, 129 uint32_t flags) 130 : MemoryHeapBase() 131{ 132 char const * const device = pmemHeap->getDevice(); 133#if HAVE_ANDROID_OS 134 if (device) { 135 int fd = open(device, O_RDWR | (flags & NO_CACHING ? O_SYNC : 0)); 136 LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno)); 137 if (fd >= 0) { 138 int err = ioctl(fd, PMEM_CONNECT, pmemHeap->heapID()); 139 if (err < 0) { 140 LOGE("PMEM_CONNECT failed (%s), mFD=%d, sub-fd=%d", 141 strerror(errno), fd, pmemHeap->heapID()); 142 close(fd); 143 } else { 144 // everything went well... 145 mParentHeap = pmemHeap; 146 MemoryHeapBase::init(fd, 147 pmemHeap->getBase(), 148 pmemHeap->getSize(), 149 pmemHeap->getFlags() | flags, 150 device); 151 } 152 } 153 } 154#else 155 mParentHeap = pmemHeap; 156 MemoryHeapBase::init( 157 dup(pmemHeap->heapID()), 158 pmemHeap->getBase(), 159 pmemHeap->getSize(), 160 pmemHeap->getFlags() | flags, 161 device); 162#endif 163} 164 165MemoryHeapPmem::~MemoryHeapPmem() 166{ 167} 168 169sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size) 170{ 171 sp<MemoryPmem> memory = createMemory(offset, size); 172 if (memory != 0) { 173 Mutex::Autolock _l(mLock); 174 mAllocations.add(memory); 175 } 176 return memory; 177} 178 179sp<MemoryHeapPmem::MemoryPmem> MemoryHeapPmem::createMemory( 180 size_t offset, size_t size) 181{ 182 sp<SubRegionMemory> memory; 183 if (heapID() > 0) 184 memory = new SubRegionMemory(this, offset, size); 185 return memory; 186} 187 188status_t MemoryHeapPmem::slap() 189{ 190#if HAVE_ANDROID_OS 191 size_t size = getSize(); 192 const size_t pagesize = getpagesize(); 193 size = (size + pagesize-1) & ~(pagesize-1); 194 int our_fd = getHeapID(); 195 struct pmem_region sub = { 0, size }; 196 int err = ioctl(our_fd, PMEM_MAP, &sub); 197 LOGE_IF(err<0, "PMEM_MAP failed (%s), " 198 "mFD=%d, sub.offset=%lu, sub.size=%lu", 199 strerror(errno), our_fd, sub.offset, sub.len); 200 return -errno; 201#else 202 return NO_ERROR; 203#endif 204} 205 206status_t MemoryHeapPmem::unslap() 207{ 208#if HAVE_ANDROID_OS 209 size_t size = getSize(); 210 const size_t pagesize = getpagesize(); 211 size = (size + pagesize-1) & ~(pagesize-1); 212 int our_fd = getHeapID(); 213 struct pmem_region sub = { 0, size }; 214 int err = ioctl(our_fd, PMEM_UNMAP, &sub); 215 LOGE_IF(err<0, "PMEM_UNMAP failed (%s), " 216 "mFD=%d, sub.offset=%lu, sub.size=%lu", 217 strerror(errno), our_fd, sub.offset, sub.len); 218 return -errno; 219#else 220 return NO_ERROR; 221#endif 222} 223 224void MemoryHeapPmem::revoke() 225{ 226 SortedVector< wp<MemoryPmem> > allocations; 227 228 { // scope for lock 229 Mutex::Autolock _l(mLock); 230 allocations = mAllocations; 231 } 232 233 ssize_t count = allocations.size(); 234 for (ssize_t i=0 ; i<count ; i++) { 235 sp<MemoryPmem> memory(allocations[i].promote()); 236 if (memory != 0) 237 memory->revoke(); 238 } 239} 240 241void MemoryHeapPmem::remove(const wp<MemoryPmem>& memory) 242{ 243 Mutex::Autolock _l(mLock); 244 mAllocations.remove(memory); 245} 246 247// --------------------------------------------------------------------------- 248}; // namespace android 249