blob: 1e5a1cc9617cd9e667ce1297d1a13e8851404031 [file] [log] [blame]
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001/*
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 <utils/MemoryHeapPmem.h>
31#include <utils/MemoryHeapBase.h>
32
33#if HAVE_ANDROID_OS
34#include <linux/android_pmem.h>
35#endif
36
37namespace android {
38
39// ---------------------------------------------------------------------------
40
41class MemoryHeapPmem;
42
43class SubRegionMemory : public BnMemory {
44public:
45 SubRegionMemory(const sp<MemoryHeapPmem>& heap, ssize_t offset, size_t size);
46 virtual ~SubRegionMemory();
47 virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
48private:
49 friend class MemoryHeapPmem;
50 void revoke();
51 size_t mSize;
52 ssize_t mOffset;
53 sp<MemoryHeapPmem> mClientHeap;
54};
55
56SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap,
57 ssize_t offset, size_t size)
58 : mSize(size), mOffset(offset), mClientHeap(heap)
59{
60#ifndef NDEBUG
61 void* const start_ptr = (void*)(intptr_t(mClientHeap->base()) + offset);
62 memset(start_ptr, 0xda, size);
63#endif
64
65#if HAVE_ANDROID_OS
66 if (size > 0) {
67 const size_t pagesize = getpagesize();
68 size = (size + pagesize-1) & ~(pagesize-1);
69 int our_fd = heap->heapID();
70 struct pmem_region sub = { offset, size };
71 int err = ioctl(our_fd, PMEM_MAP, &sub);
72 LOGE_IF(err<0, "PMEM_MAP failed (%s), "
73 "mFD=%d, sub.offset=%lu, sub.size=%lu",
74 strerror(errno), our_fd, sub.offset, sub.len);
75}
76#endif
77}
78
79sp<IMemoryHeap> SubRegionMemory::getMemory(ssize_t* offset, size_t* size) const
80{
81 if (offset) *offset = mOffset;
82 if (size) *size = mSize;
83 return mClientHeap;
84}
85
86SubRegionMemory::~SubRegionMemory()
87{
88 revoke();
89}
90
91
92void SubRegionMemory::revoke()
93{
94 // NOTE: revoke() doesn't need to be protected by a lock because it
95 // can only be called from MemoryHeapPmem::revoke(), which means
96 // that we can't be in ~SubRegionMemory(), or in ~SubRegionMemory(),
97 // which means MemoryHeapPmem::revoke() wouldn't have been able to
98 // promote() it.
99
100#if HAVE_ANDROID_OS
101 if (mClientHeap != NULL) {
102 int our_fd = mClientHeap->heapID();
103 struct pmem_region sub;
104 sub.offset = mOffset;
105 sub.len = mSize;
106 int err = ioctl(our_fd, PMEM_UNMAP, &sub);
107 LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
108 "mFD=%d, sub.offset=%lu, sub.size=%lu",
109 strerror(errno), our_fd, sub.offset, sub.len);
110 mClientHeap.clear();
111 }
112#endif
113}
114
115// ---------------------------------------------------------------------------
116
117MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
118 uint32_t flags)
119 : HeapInterface(), MemoryHeapBase()
120{
121 char const * const device = pmemHeap->getDevice();
122#if HAVE_ANDROID_OS
123 if (device) {
124 int fd = open(device, O_RDWR);
125 LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno));
126 if (fd >= 0) {
127 int err = ioctl(fd, PMEM_CONNECT, pmemHeap->heapID());
128 if (err < 0) {
129 LOGE("PMEM_CONNECT failed (%s), mFD=%d, sub-fd=%d",
130 strerror(errno), fd, pmemHeap->heapID());
131 close(fd);
132 } else {
133 // everything went well...
134 mParentHeap = pmemHeap;
135 MemoryHeapBase::init(fd,
136 pmemHeap->getBase(),
137 pmemHeap->getSize(),
138 pmemHeap->getFlags() | flags,
139 device);
140 }
141 }
142 }
143#else
144 mParentHeap = pmemHeap;
145 MemoryHeapBase::init(
146 dup(pmemHeap->heapID()),
147 pmemHeap->getBase(),
148 pmemHeap->getSize(),
149 pmemHeap->getFlags() | flags,
150 device);
151#endif
152}
153
154MemoryHeapPmem::~MemoryHeapPmem()
155{
156}
157
158sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size)
159{
160 sp<SubRegionMemory> memory;
161 if (heapID() > 0)
162 memory = new SubRegionMemory(this, offset, size);
163
164 if (memory != 0) {
165 Mutex::Autolock _l(mLock);
166 mAllocations.add(memory);
167 }
168 return memory;
169}
170
171status_t MemoryHeapPmem::slap()
172{
173#if HAVE_ANDROID_OS
174 size_t size = getSize();
175 const size_t pagesize = getpagesize();
176 size = (size + pagesize-1) & ~(pagesize-1);
177 int our_fd = getHeapID();
178 struct pmem_region sub = { 0, size };
179 int err = ioctl(our_fd, PMEM_MAP, &sub);
180 LOGE_IF(err<0, "PMEM_MAP failed (%s), "
181 "mFD=%d, sub.offset=%lu, sub.size=%lu",
182 strerror(errno), our_fd, sub.offset, sub.len);
183 return -errno;
184#else
185 return NO_ERROR;
186#endif
187}
188
189status_t MemoryHeapPmem::unslap()
190{
191#if HAVE_ANDROID_OS
192 size_t size = getSize();
193 const size_t pagesize = getpagesize();
194 size = (size + pagesize-1) & ~(pagesize-1);
195 int our_fd = getHeapID();
196 struct pmem_region sub = { 0, size };
197 int err = ioctl(our_fd, PMEM_UNMAP, &sub);
198 LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
199 "mFD=%d, sub.offset=%lu, sub.size=%lu",
200 strerror(errno), our_fd, sub.offset, sub.len);
201 return -errno;
202#else
203 return NO_ERROR;
204#endif
205}
206
207void MemoryHeapPmem::revoke()
208{
209 Vector< wp<SubRegionMemory> > allocations;
210
211 { // scope for lock
212 Mutex::Autolock _l(mLock);
213 allocations = mAllocations;
214 mAllocations.clear();
215 }
216
217 ssize_t count = allocations.size();
218 for (ssize_t i=0 ; i<count ; i++) {
219 sp<SubRegionMemory> memory(allocations[i].promote());
220 if (memory != 0)
221 memory->revoke();
222 }
223}
224
225// ---------------------------------------------------------------------------
226}; // namespace android