1 /*
2 * Copyright (c) 2019, 2022 Arm Limited.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24 #if !defined(_WIN64) && !defined(BARE_METAL)
25
26 #include "arm_compute/core/utils/misc/MMappedFile.h"
27
28 #include <cstdio>
29 #include <cstring>
30 #include <tuple>
31
32 #include <fcntl.h>
33 #include <sys/mman.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <unistd.h>
37
38 namespace arm_compute
39 {
40 namespace utils
41 {
42 namespace mmap_io
43 {
44 namespace
45 {
46 /** File size accessor
47 *
48 * @param[in] filename File to extract its size
49 *
50 * @return A pair of size and status.
51 */
get_file_size(const std::string & filename)52 std::pair<size_t, bool> get_file_size(const std::string &filename)
53 {
54 struct stat st; // NOLINT
55 memset(&st, 0, sizeof(struct stat));
56 if(stat(filename.c_str(), &st) == 0)
57 {
58 return std::make_pair(st.st_size, true);
59 }
60 else
61 {
62 return std::make_pair(0, false);
63 }
64 }
65
66 /** Get OS page size
67 *
68 * @return Page size
69 */
get_page_size()70 size_t get_page_size()
71 {
72 return sysconf(_SC_PAGESIZE);
73 }
74 } // namespace
75
MMappedFile()76 MMappedFile::MMappedFile()
77 : _filename(), _file_size(0), _map_size(0), _map_offset(0), _fp(nullptr), _data(nullptr)
78 {
79 }
80
MMappedFile(std::string filename,size_t size,size_t offset)81 MMappedFile::MMappedFile(std::string filename, size_t size, size_t offset)
82 : _filename(std::move(filename)), _file_size(0), _map_size(size), _map_offset(offset), _fp(nullptr), _data(nullptr)
83 {
84 map(_filename, _map_size, _map_offset);
85 }
86
~MMappedFile()87 MMappedFile::~MMappedFile()
88 {
89 release();
90 }
91
map(const std::string & filename,size_t size,size_t offset)92 bool MMappedFile::map(const std::string &filename, size_t size, size_t offset)
93 {
94 // Check if file is mapped
95 if(is_mapped())
96 {
97 return false;
98 }
99
100 // Open file
101 _fp = fopen(filename.c_str(), "a+be");
102 if(_fp == nullptr)
103 {
104 return false;
105 }
106
107 // Extract file descriptor
108 int fd = fileno(_fp);
109 bool status = fd >= 0;
110 if(status)
111 {
112 // Get file size
113 std::tie(_file_size, status) = get_file_size(_filename);
114
115 if(status)
116 {
117 // Map all file from offset if map size is 0
118 _map_size = (size == 0) ? _file_size : size;
119 _map_offset = offset;
120
121 // Check offset mapping
122 if((_map_offset > _file_size) || (_map_offset % get_page_size() != 0))
123 {
124 status = false;
125 }
126 else
127 {
128 // Truncate to file size
129 if(_map_offset + _map_size > _file_size)
130 {
131 _map_size = _file_size - _map_offset;
132 }
133
134 // Perform mapping
135 _data = ::mmap(nullptr, _map_size, PROT_WRITE, MAP_SHARED, fd, _map_offset);
136 }
137 }
138 }
139
140 if(!status)
141 {
142 fclose(_fp);
143 }
144
145 return status;
146 }
147
release()148 void MMappedFile::release()
149 {
150 // Unmap file
151 if(_data != nullptr)
152 {
153 ::munmap(_data, _file_size);
154 _data = nullptr;
155 }
156
157 // Close file
158 if(_fp != nullptr)
159 {
160 fclose(_fp);
161 _fp = nullptr;
162 }
163
164 // Clear variables
165 _file_size = 0;
166 _map_size = 0;
167 _map_offset = 0;
168 }
169
data()170 unsigned char *MMappedFile::data()
171 {
172 return static_cast<unsigned char *>(_data);
173 }
174
file_size() const175 size_t MMappedFile::file_size() const
176 {
177 return _file_size;
178 }
179
map_size() const180 size_t MMappedFile::map_size() const
181 {
182 return _map_size;
183 }
184
is_mapped() const185 bool MMappedFile::is_mapped() const
186 {
187 return _data != nullptr;
188 }
189 } // namespace mmap_io
190 } // namespace utils
191 } // namespace arm_compute
192 #endif // !defined(BARE_METAL)
193