lin
2025-04-25 6a7002bcc41716f11f4ca7eb68ebd06c18fdd5e8
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
/*
 * Copyright (C) 2018 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.
 */
 
#ifndef LIBTEXTCLASSIFIER_UTILS_MEMORY_MMAP_H_
#define LIBTEXTCLASSIFIER_UTILS_MEMORY_MMAP_H_
 
#include <stddef.h>
 
#include <string>
 
#include "utils/base/integral_types.h"
#include "utils/strings/stringpiece.h"
 
namespace libtextclassifier3 {
 
// Handle for a memory area where a file has been mmapped.
//
// Similar to a pointer: you "allocate" it using MmapFile(filename) and "delete"
// it using Unmap().  Just like a pointer, it is passed around by value (see
// signature of MmapFile and Unmap; fortunately, it's a small class, so there
// shouldn't be any significant performance penalty) and its usage is not
// necessarily scoped (that's why the destructor is not performing the unmap).
//
// Note: on program termination, each still unmapped file is automatically
// unmapped.  Hence, it is not an error if you don't call Unmap() (provided you
// are ok keeping that file in memory the whole time).
class MmapHandle {
 public:
  MmapHandle(void *start, size_t num_bytes, void *unmap_addr = nullptr)
      : start_(start), num_bytes_(num_bytes), unmap_addr_(unmap_addr) {}
 
  // Returns start address for the memory area where a file has been mmapped.
  void *start() const { return start_; }
 
  // Returns address to use for munmap call. If unmap_addr was not specified
  // the start address is used.
  void *unmap_addr() const {
    if (unmap_addr_ != nullptr) {
      return unmap_addr_;
    } else {
      return start_;
    }
  }
 
  // Returns number of bytes of the memory area from start().
  size_t num_bytes() const { return num_bytes_; }
 
  // Shortcut to simplify checking success of MmapFile().  See usage example
  // from the doc of that function.
  bool ok() const { return start() != nullptr; }
 
  // Returns a StringPiece pointing to the same underlying bytes.
  StringPiece to_stringpiece() const {
    return StringPiece(reinterpret_cast<char *>(start_), num_bytes_);
  }
 
 private:
  // See doc for start().  Not owned.
  void *const start_;
 
  // See doc for num_bytes().
  const size_t num_bytes_;
 
  // Address to use for unmapping.
  void *const unmap_addr_;
};
 
// Maps the full content of a file in memory (using mmap).
//
// When done using the file content, one can unmap using Unmap().  Otherwise,
// all mapped files are unmapped when the program terminates.
//
// Sample usage:
//
// MmapHandle mmap_handle = MmapFile(filename);
// TC3_DCHECK(mmap_handle.ok()) << "Unable to mmap " << filename;
//
// ... use data from addresses
// ... [mmap_handle.start, mmap_handle.start + mmap_handle.num_bytes)
//
// Unmap(mmap_handle);  // Unmap logs errors internally.
//
// Note: one can read *and* write the num_bytes bytes from start, but those
// writes are not propagated to the underlying file, nor to other processes that
// may have mmapped that file (all changes are local to current process).
MmapHandle MmapFile(const std::string &filename);
 
// Like MmapFile(const std::string &filename), but uses a file descriptor.
MmapHandle MmapFile(int fd);
 
// Maps a segment of a file to memory. File is given by a file descriptor, and
// offset (relative to the beginning of the file) and size specify the segment
// to be mapped. NOTE: Internally, we align the offset for the call to mmap
// system call to be a multiple of page size, so offset does NOT have to be a
// multiply of the page size.
MmapHandle MmapFile(int fd, int64 segment_offset, int64 segment_size);
 
// Unmaps a file mapped using MmapFile.  Returns true on success, false
// otherwise.
bool Unmap(MmapHandle mmap_handle);
 
// Scoped mmapping of a file.  Mmaps a file on construction, unmaps it on
// destruction.
class ScopedMmap {
 public:
  explicit ScopedMmap(const std::string &filename)
      : handle_(MmapFile(filename)) {}
 
  explicit ScopedMmap(int fd) : handle_(MmapFile(fd)) {}
 
  ScopedMmap(int fd, int segment_offset, int segment_size)
      : handle_(MmapFile(fd, segment_offset, segment_size)) {}
 
  ~ScopedMmap() {
    if (handle_.ok()) {
      Unmap(handle_);
    }
  }
 
  const MmapHandle &handle() { return handle_; }
 
 private:
  MmapHandle handle_;
};
 
}  // namespace libtextclassifier3
 
#endif  // LIBTEXTCLASSIFIER_UTILS_MEMORY_MMAP_H_