/*
 * 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.
 */

//
// Encapsulate a shared file mapping.
//
#ifndef __LIBS_FILE_MAP_H
#define __LIBS_FILE_MAP_H

#include <sys/types.h>

#include <utils/Compat.h>

#ifdef HAVE_WIN32_FILEMAP
#include <windows.h>
#endif

namespace android {

/*
 * This represents a memory-mapped file.  It might be the entire file or
 * only part of it.  This requires a little bookkeeping because the mapping
 * needs to be aligned on page boundaries, and in some cases we'd like to
 * have multiple references to the mapped area without creating additional
 * maps.
 *
 * This always uses MAP_SHARED.
 *
 * TODO: we should be able to create a new FileMap that is a subset of
 * an existing FileMap and shares the underlying mapped pages.  Requires
 * completing the refcounting stuff and possibly introducing the notion
 * of a FileMap hierarchy.
 */
class FileMap {
public:
    FileMap(void);

    /*
     * 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 create(const char* origFileName, int fd,
                off64_t offset, size_t length, bool readOnly);

    /*
     * Return the name of the file this map came from, if known.
     */
    const char* getFileName(void) const { return mFileName; }
    
    /*
     * Get a pointer to the piece of the file we requested.
     */
    void* getDataPtr(void) const { return mDataPtr; }

    /*
     * Get the length we requested.
     */
    size_t getDataLength(void) const { return mDataLength; }

    /*
     * Get the data offset used to create this map.
     */
    off64_t getDataOffset(void) const { return mDataOffset; }

    /*
     * Get a "copy" of the object.
     */
    FileMap* acquire(void) { mRefCount++; return this; }

    /*
     * Call this when mapping is no longer needed.
     */
    void release(void) {
        if (--mRefCount <= 0)
            delete this;
    }

    /*
     * This maps directly to madvise() values, but allows us to avoid
     * including <sys/mman.h> everywhere.
     */
    enum MapAdvice {
        NORMAL, RANDOM, SEQUENTIAL, WILLNEED, DONTNEED
    };

    /*
     * Apply an madvise() call to the entire file.
     *
     * Returns 0 on success, -1 on failure.
     */
    int advise(MapAdvice advice);

protected:
    // don't delete objects; call release()
    ~FileMap(void);

private:
    // these are not implemented
    FileMap(const FileMap& src);
    const FileMap& operator=(const FileMap& src);

    int         mRefCount;      // reference count
    char*       mFileName;      // original file name, if known
    void*       mBasePtr;       // base of mmap area; page aligned
    size_t      mBaseLength;    // length, measured from "mBasePtr"
    off64_t     mDataOffset;    // offset used when map was created
    void*       mDataPtr;       // start of requested data, offset from base
    size_t      mDataLength;    // length, measured from "mDataPtr"
#ifdef HAVE_WIN32_FILEMAP
    HANDLE      mFileHandle;    // Win32 file handle
    HANDLE      mFileMapping;   // Win32 file mapping handle
#endif

    static long mPageSize;
};

}; // namespace android

#endif // __LIBS_FILE_MAP_H