2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
27 #ifdef HAVE_POSIX_FILEMAP
35 * Having trouble finding a portable way to get this. sysconf(_SC_PAGE_SIZE)
36 * seems appropriate, but we don't have that on the device. Some systems
37 * have getpagesize(2), though the linux man page has some odd cautions.
39 #define DEFAULT_PAGE_SIZE 4096
43 * Create an anonymous shared memory segment large enough to hold "length"
44 * bytes. The actual segment may be larger because mmap() operates on
45 * page boundaries (usually 4K).
47 static void* sysCreateAnonShmem(size_t length)
49 #ifdef HAVE_POSIX_FILEMAP
52 ptr = mmap(NULL, length, PROT_READ | PROT_WRITE,
53 MAP_SHARED | MAP_ANON, -1, 0);
54 if (ptr == MAP_FAILED) {
55 LOGW("mmap(%d, RW, SHARED|ANON) failed: %s\n", (int) length,
62 LOGE("sysCreateAnonShmem not implemented.\n");
67 static int getFileStartAndLength(int fd, off_t *start_, size_t *length_)
72 assert(start_ != NULL);
73 assert(length_ != NULL);
75 start = lseek(fd, 0L, SEEK_CUR);
76 end = lseek(fd, 0L, SEEK_END);
77 (void) lseek(fd, start, SEEK_SET);
79 if (start == (off_t) -1 || end == (off_t) -1) {
80 LOGE("could not determine length of file\n");
86 LOGE("file is empty\n");
97 * Pull the contents of a file into an new shared memory segment. We grab
98 * everything from fd's current offset on.
100 * We need to know the length ahead of time so we can allocate a segment
101 * of sufficient size.
103 int sysLoadFileInShmem(int fd, MemMapping* pMap)
105 #ifdef HAVE_POSIX_FILEMAP
107 size_t length, actual;
110 assert(pMap != NULL);
112 if (getFileStartAndLength(fd, &start, &length) < 0)
115 memPtr = sysCreateAnonShmem(length);
119 actual = read(fd, memPtr, length);
120 if (actual != length) {
121 LOGE("only read %d of %d bytes\n", (int) actual, (int) length);
122 sysReleaseShmem(pMap);
126 pMap->baseAddr = pMap->addr = memPtr;
127 pMap->baseLength = pMap->length = length;
131 LOGE("sysLoadFileInShmem not implemented.\n");
137 * Map a file (from fd's current offset) into a shared, read-only memory
138 * segment. The file offset must be a multiple of the page size.
140 * On success, returns 0 and fills out "pMap". On failure, returns a nonzero
141 * value and does not disturb "pMap".
143 int sysMapFileInShmem(int fd, MemMapping* pMap)
145 #ifdef HAVE_POSIX_FILEMAP
150 assert(pMap != NULL);
152 if (getFileStartAndLength(fd, &start, &length) < 0)
155 memPtr = mmap(NULL, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, start);
156 if (memPtr == MAP_FAILED) {
157 LOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s\n", (int) length,
158 fd, (int) start, strerror(errno));
162 pMap->baseAddr = pMap->addr = memPtr;
163 pMap->baseLength = pMap->length = length;
167 /* No MMAP, just fake it by copying the bits.
168 For Win32 we could use MapViewOfFile if really necessary
169 (see libs/utils/FileMap.cpp).
175 assert(pMap != NULL);
177 if (getFileStartAndLength(fd, &start, &length) < 0)
180 memPtr = malloc(length);
181 if (read(fd, memPtr, length) < 0) {
182 LOGW("read(fd=%d, start=%d, length=%d) failed: %s\n", (int) length,
183 fd, (int) start, strerror(errno));
187 pMap->baseAddr = pMap->addr = memPtr;
188 pMap->baseLength = pMap->length = length;
195 * Map part of a file (from fd's current offset) into a shared, read-only
198 * On success, returns 0 and fills out "pMap". On failure, returns a nonzero
199 * value and does not disturb "pMap".
201 int sysMapFileSegmentInShmem(int fd, off_t start, long length,
204 #ifdef HAVE_POSIX_FILEMAP
206 size_t fileLength, actualLength;
211 assert(pMap != NULL);
213 if (getFileStartAndLength(fd, &dummy, &fileLength) < 0)
216 if (start + length > (long)fileLength) {
217 LOGW("bad segment: st=%d len=%ld flen=%d\n",
218 (int) start, length, (int) fileLength);
222 /* adjust to be page-aligned */
223 adjust = start % DEFAULT_PAGE_SIZE;
224 actualStart = start - adjust;
225 actualLength = length + adjust;
227 memPtr = mmap(NULL, actualLength, PROT_READ, MAP_FILE | MAP_SHARED,
229 if (memPtr == MAP_FAILED) {
230 LOGW("mmap(%d, R, FILE|SHARED, %d, %d) failed: %s\n",
231 (int) actualLength, fd, (int) actualStart, strerror(errno));
235 pMap->baseAddr = memPtr;
236 pMap->baseLength = actualLength;
237 pMap->addr = (char*)memPtr + adjust;
238 pMap->length = length;
240 LOGVV("mmap seg (st=%d ln=%d): bp=%p bl=%d ad=%p ln=%d\n",
241 (int) start, (int) length,
242 pMap->baseAddr, (int) pMap->baseLength,
243 pMap->addr, (int) pMap->length);
247 LOGE("sysMapFileSegmentInShmem not implemented.\n");
253 * Release a memory mapping.
255 void sysReleaseShmem(MemMapping* pMap)
257 #ifdef HAVE_POSIX_FILEMAP
258 if (pMap->baseAddr == NULL && pMap->baseLength == 0)
261 if (munmap(pMap->baseAddr, pMap->baseLength) < 0) {
262 LOGW("munmap(%p, %d) failed: %s\n",
263 pMap->baseAddr, (int)pMap->baseLength, strerror(errno));
265 LOGV("munmap(%p, %d) succeeded\n", pMap->baseAddr, pMap->baseLength);
266 pMap->baseAddr = NULL;
267 pMap->baseLength = 0;
270 /* Free the bits allocated by sysMapFileInShmem. */
271 if (pMap->baseAddr != NULL) {
272 free(pMap->baseAddr);
273 pMap->baseAddr = NULL;
275 pMap->baseLength = 0;
280 * Make a copy of a MemMapping.
282 void sysCopyMap(MemMapping* dst, const MemMapping* src)
284 memcpy(dst, src, sizeof(MemMapping));