1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_FILES_MEMORY_MAPPED_FILE_H_
#define BASE_FILES_MEMORY_MAPPED_FILE_H_
#include <stddef.h>
#include <stdint.h>
#include <utility>
#include "base/base_export.h"
#include "base/containers/span.h"
#include "base/files/file.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_WIN)
#include "base/win/scoped_handle.h"
#endif
namespace base {
class FilePath;
class BASE_EXPORT MemoryMappedFile {
public:
enum Access {
// Mapping a file into memory effectively allows for file I/O on any thread.
// The accessing thread could be paused while data from the file is paged
// into memory. Worse, a corrupted filesystem could cause a SEGV within the
// program instead of just an I/O error.
READ_ONLY,
// This provides read/write access to a file and must be used with care of
// the additional subtleties involved in doing so. Though the OS will do
// the writing of data on its own time, too many dirty pages can cause
// the OS to pause the thread while it writes them out. The pause can
// be as much as 1s on some systems.
READ_WRITE,
// This provides read/write access to the mapped file contents as above, but
// applies a copy-on-write policy such that no writes are carried through to
// the underlying file.
READ_WRITE_COPY,
// This provides read/write access but with the ability to write beyond
// the end of the existing file up to a maximum size specified as the
// "region". Depending on the OS, the file may or may not be immediately
// extended to the maximum size though it won't be loaded in RAM until
// needed. Note, however, that the maximum size will still be reserved
// in the process address space.
READ_WRITE_EXTEND,
#if BUILDFLAG(IS_WIN)
// This provides read access, but as executable code used for prefetching
// DLLs into RAM to avoid inefficient hard fault patterns such as during
// process startup. The accessing thread could be paused while data from
// the file is read into memory (if needed).
READ_CODE_IMAGE,
#endif
};
// The default constructor sets all members to invalid/null values.
MemoryMappedFile();
MemoryMappedFile(const MemoryMappedFile&) = delete;
MemoryMappedFile& operator=(const MemoryMappedFile&) = delete;
~MemoryMappedFile();
// Used to hold information about a region [offset + size] of a file.
struct BASE_EXPORT Region {
static const Region kWholeFile;
friend bool operator==(const Region&, const Region&) = default;
// Start of the region (measured in bytes from the beginning of the file).
int64_t offset;
// Length of the region in bytes.
size_t size;
};
// Opens an existing file and maps it into memory. |access| can be read-only
// or read/write but not read/write+extend. If this object already points
// to a valid memory mapped file then this method will fail and return
// false. If it cannot open the file, the file does not exist, or the
// memory mapping fails, it will return false.
[[nodiscard]] bool Initialize(const FilePath& file_name, Access access);
[[nodiscard]] bool Initialize(const FilePath& file_name) {
return Initialize(file_name, READ_ONLY);
}
// As above, but works with an already-opened file. |access| can be read-only
// or read/write but not read/write+extend. MemoryMappedFile takes ownership
// of |file| and closes it when done. |file| must have been opened with
// permissions suitable for |access|. If the memory mapping fails, it will
// return false.
[[nodiscard]] bool Initialize(File file, Access access);
[[nodiscard]] bool Initialize(File file) {
return Initialize(std::move(file), READ_ONLY);
}
// As above, but works with a region of an already-opened file. |access|
// must not be READ_CODE_IMAGE. If READ_WRITE_EXTEND is specified then
// |region| provides the maximum size of the file. If the memory mapping
// fails, it return false.
[[nodiscard]] bool Initialize(File file, const Region& region, Access access);
[[nodiscard]] bool Initialize(File file, const Region& region) {
return Initialize(std::move(file), region, READ_ONLY);
}
const uint8_t* data() const { return bytes_.data(); }
uint8_t* data() { return bytes_.data(); }
size_t length() const { return bytes_.size(); }
span<const uint8_t> bytes() const { return bytes_; }
span<uint8_t> mutable_bytes() { return bytes_; }
// Is file_ a valid file handle that points to an open, memory mapped file?
bool IsValid() const;
private:
// Given the arbitrarily aligned memory region [start, size], returns the
// boundaries of the region aligned to the granularity specified by the OS,
// (a page on Linux, ~32k on Windows) as follows:
// - |aligned_start| is page aligned and <= |start|.
// - |aligned_size| is a multiple of the VM granularity and >= |size|.
// - |offset| is the displacement of |start| w.r.t |aligned_start|.
static void CalculateVMAlignedBoundaries(int64_t start,
size_t size,
int64_t* aligned_start,
size_t* aligned_size,
int32_t* offset);
#if BUILDFLAG(IS_WIN)
// Maps the executable file to memory, point `bytes_` to the memory range.
// Return true on success.
bool MapImageToMemory(Access access);
#endif
// Map the file to memory, point `bytes_` to that memory address. Return true
// on success, false on any kind of failure. This is a helper for
// Initialize().
bool MapFileRegionToMemory(const Region& region, Access access);
// Closes all open handles.
void CloseHandles();
File file_;
// RAW_PTR_EXCLUSION: Never allocated by PartitionAlloc (always mmap'ed), so
// there is no benefit to using a raw_span, only cost.
RAW_PTR_EXCLUSION span<uint8_t> bytes_;
#if BUILDFLAG(IS_WIN)
win::ScopedHandle file_mapping_;
#endif
};
} // namespace base
#endif // BASE_FILES_MEMORY_MAPPED_FILE_H_
|