summaryrefslogtreecommitdiffstats
path: root/libs/utils/FileMap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/utils/FileMap.cpp')
-rw-r--r--libs/utils/FileMap.cpp222
1 files changed, 222 insertions, 0 deletions
diff --git a/libs/utils/FileMap.cpp b/libs/utils/FileMap.cpp
new file mode 100644
index 0000000..e1ba9b2
--- /dev/null
+++ b/libs/utils/FileMap.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Shared file mapping class.
+//
+
+#define LOG_TAG "filemap"
+
+#include <utils/FileMap.h>
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_POSIX_FILEMAP
+#include <sys/mman.h>
+#endif
+
+#include <string.h>
+#include <memory.h>
+#include <errno.h>
+#include <assert.h>
+
+using namespace android;
+
+/*static*/ long FileMap::mPageSize = -1;
+
+
+/*
+ * Constructor. Create an empty object.
+ */
+FileMap::FileMap(void)
+ : mRefCount(1), mFileName(NULL), mBasePtr(NULL), mBaseLength(0),
+ mDataPtr(NULL), mDataLength(0)
+{
+}
+
+/*
+ * Destructor.
+ */
+FileMap::~FileMap(void)
+{
+ assert(mRefCount == 0);
+
+ //printf("+++ removing FileMap %p %u\n", mDataPtr, mDataLength);
+
+ mRefCount = -100; // help catch double-free
+ if (mFileName != NULL) {
+ free(mFileName);
+ }
+#ifdef HAVE_POSIX_FILEMAP
+ if (munmap(mBasePtr, mBaseLength) != 0) {
+ LOGD("munmap(%p, %d) failed\n", mBasePtr, (int) mBaseLength);
+ }
+#endif
+#ifdef HAVE_WIN32_FILEMAP
+ if ( UnmapViewOfFile(mBasePtr) == 0) {
+ LOGD("UnmapViewOfFile(%p) failed, error = %ld\n", mBasePtr,
+ GetLastError() );
+ }
+ CloseHandle(mFileMapping);
+ CloseHandle(mFileHandle);
+#endif
+}
+
+
+/*
+ * Create a new mapping on an open file.
+ *
+ * Closing the file descriptor does not unmap the pages, so we don't
+ * claim ownership of the fd.
+ *
+ * Returns "false" on failure.
+ */
+bool FileMap::create(const char* origFileName, int fd, off_t offset, size_t length, bool readOnly)
+{
+#ifdef HAVE_WIN32_FILEMAP
+ int adjust;
+ off_t adjOffset;
+ size_t adjLength;
+
+ if (mPageSize == -1) {
+ SYSTEM_INFO si;
+
+ GetSystemInfo( &si );
+ mPageSize = si.dwAllocationGranularity;
+ }
+
+ DWORD protect = readOnly ? PAGE_READONLY : PAGE_READWRITE;
+
+ mFileHandle = (HANDLE) _get_osfhandle(fd);
+ mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL);
+ if (mFileMapping == NULL) {
+ LOGE("CreateFileMapping(%p, %lx) failed with error %ld\n",
+ mFileHandle, protect, GetLastError() );
+ return false;
+ }
+
+ adjust = offset % mPageSize;
+ adjOffset = offset - adjust;
+ adjLength = length + adjust;
+
+ mBasePtr = MapViewOfFile( mFileMapping,
+ readOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
+ 0,
+ (DWORD)(adjOffset),
+ adjLength );
+ if (mBasePtr == NULL) {
+ LOGE("MapViewOfFile(%ld, %ld) failed with error %ld\n",
+ adjOffset, adjLength, GetLastError() );
+ CloseHandle(mFileMapping);
+ mFileMapping = INVALID_HANDLE_VALUE;
+ return false;
+ }
+#endif
+#ifdef HAVE_POSIX_FILEMAP
+ int prot, flags, adjust;
+ off_t adjOffset;
+ size_t adjLength;
+
+ void* ptr;
+
+ assert(mRefCount == 1);
+ assert(fd >= 0);
+ assert(offset >= 0);
+ assert(length > 0);
+
+ /* init on first use */
+ if (mPageSize == -1) {
+#if NOT_USING_KLIBC
+ mPageSize = sysconf(_SC_PAGESIZE);
+ if (mPageSize == -1) {
+ LOGE("could not get _SC_PAGESIZE\n");
+ return false;
+ }
+#else
+ /* this holds for Linux, Darwin, Cygwin, and doesn't pain the ARM */
+ mPageSize = 4096;
+#endif
+ }
+
+ adjust = offset % mPageSize;
+try_again:
+ adjOffset = offset - adjust;
+ adjLength = length + adjust;
+
+ flags = MAP_SHARED;
+ prot = PROT_READ;
+ if (!readOnly)
+ prot |= PROT_WRITE;
+
+ ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset);
+ if (ptr == MAP_FAILED) {
+ // Cygwin does not seem to like file mapping files from an offset.
+ // So if we fail, try again with offset zero
+ if (adjOffset > 0) {
+ adjust = offset;
+ goto try_again;
+ }
+
+ LOGE("mmap(%ld,%ld) failed: %s\n",
+ (long) adjOffset, (long) adjLength, strerror(errno));
+ return false;
+ }
+ mBasePtr = ptr;
+#endif /* HAVE_POSIX_FILEMAP */
+
+ mFileName = origFileName != NULL ? strdup(origFileName) : NULL;
+ mBaseLength = adjLength;
+ mDataOffset = offset;
+ mDataPtr = (char*) mBasePtr + adjust;
+ mDataLength = length;
+
+ assert(mBasePtr != NULL);
+
+ LOGV("MAP: base %p/%d data %p/%d\n",
+ mBasePtr, (int) mBaseLength, mDataPtr, (int) mDataLength);
+
+ return true;
+}
+
+/*
+ * Provide guidance to the system.
+ */
+int FileMap::advise(MapAdvice advice)
+{
+#if HAVE_MADVISE
+ int cc, sysAdvice;
+
+ switch (advice) {
+ case NORMAL: sysAdvice = MADV_NORMAL; break;
+ case RANDOM: sysAdvice = MADV_RANDOM; break;
+ case SEQUENTIAL: sysAdvice = MADV_SEQUENTIAL; break;
+ case WILLNEED: sysAdvice = MADV_WILLNEED; break;
+ case DONTNEED: sysAdvice = MADV_DONTNEED; break;
+ default:
+ assert(false);
+ return -1;
+ }
+
+ cc = madvise(mBasePtr, mBaseLength, sysAdvice);
+ if (cc != 0)
+ LOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno));
+ return cc;
+#else
+ return -1;
+#endif // HAVE_MADVISE
+}