blob: 03322ea5d9c4c2952b266099344eb7e5c81be5aa [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Mathias Agopian07952722009-05-19 19:08:10 -070030#include <binder/MemoryHeapPmem.h>
31#include <binder/MemoryHeapBase.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032
Kenny Rootbb9d3942011-02-16 10:13:53 -080033#ifdef HAVE_ANDROID_OS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034#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
Kenny Rootbb9d3942011-02-16 10:13:53 -080075#ifdef HAVE_ANDROID_OS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 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
Kenny Rootbb9d3942011-02-16 10:13:53 -0800110#ifdef HAVE_ANDROID_OS
Mathias Agopianaaf834a2009-05-22 19:00:22 -0700111 if (mSize != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 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)
Mathias Agopian6faf7892010-01-25 19:00:00 -0800130 : MemoryHeapBase()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131{
132 char const * const device = pmemHeap->getDevice();
Kenny Rootbb9d3942011-02-16 10:13:53 -0800133#ifdef HAVE_ANDROID_OS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 if (device) {
Dima Zavindfc72442009-11-02 16:02:43 -0800135 int fd = open(device, O_RDWR | (flags & NO_CACHING ? O_SYNC : 0));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 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{
Kenny Rootbb9d3942011-02-16 10:13:53 -0800190#ifdef HAVE_ANDROID_OS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 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{
Kenny Rootbb9d3942011-02-16 10:13:53 -0800208#ifdef HAVE_ANDROID_OS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 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