OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / libs / binder / MemoryHeapPmem.cpp
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
37 namespace android {
38
39 // ---------------------------------------------------------------------------
40
41 MemoryHeapPmem::MemoryPmem::MemoryPmem(const sp<MemoryHeapPmem>& heap)
42     : BnMemory(), mClientHeap(heap)
43 {
44 }
45
46 MemoryHeapPmem::MemoryPmem::~MemoryPmem() {
47     if (mClientHeap != NULL) {
48         mClientHeap->remove(this);
49     }
50 }
51
52 // ---------------------------------------------------------------------------
53
54 class SubRegionMemory : public MemoryHeapPmem::MemoryPmem {
55 public:
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;
59 private:
60     friend class MemoryHeapPmem;
61     void revoke();
62     size_t              mSize;
63     ssize_t             mOffset;
64 };
65
66 SubRegionMemory::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
89 sp<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
96 SubRegionMemory::~SubRegionMemory()
97 {
98     revoke();
99 }
100
101
102 void 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
128 MemoryHeapPmem::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
165 MemoryHeapPmem::~MemoryHeapPmem()
166 {
167 }
168
169 sp<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
179 sp<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
188 status_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
206 status_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
224 void 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
241 void MemoryHeapPmem::remove(const wp<MemoryPmem>& memory)
242 {
243     Mutex::Autolock _l(mLock);
244     mAllocations.remove(memory);
245 }
246
247 // ---------------------------------------------------------------------------
248 }; // namespace android