1 | /* Copyright 2018 The TensorFlow Authors. All Rights Reserved. |
2 | |
3 | Licensed under the Apache License, Version 2.0 (the "License"); |
4 | you may not use this file except in compliance with the License. |
5 | You may obtain a copy of the License at |
6 | |
7 | http://www.apache.org/licenses/LICENSE-2.0 |
8 | |
9 | Unless required by applicable law or agreed to in writing, software |
10 | distributed under the License is distributed on an "AS IS" BASIS, |
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | See the License for the specific language governing permissions and |
13 | limitations under the License. |
14 | ==============================================================================*/ |
15 | |
16 | #include <fcntl.h> |
17 | #include <stddef.h> |
18 | #include <sys/mman.h> |
19 | #include <sys/stat.h> |
20 | #include <unistd.h> |
21 | |
22 | #include <cerrno> |
23 | |
24 | #include "tensorflow/lite/allocation.h" |
25 | #include "tensorflow/lite/core/api/error_reporter.h" |
26 | |
27 | namespace tflite { |
28 | namespace { |
29 | |
30 | size_t GetFdSizeBytes(int fd) { |
31 | if (fd < 0) { |
32 | return 0; |
33 | } |
34 | |
35 | struct stat fd_stat; |
36 | if (fstat(fd, &fd_stat) != 0) { |
37 | return 0; |
38 | } |
39 | |
40 | return fd_stat.st_size; |
41 | } |
42 | |
43 | } // namespace |
44 | |
45 | MMAPAllocation::MMAPAllocation(const char* filename, |
46 | ErrorReporter* error_reporter) |
47 | : MMAPAllocation(error_reporter, open(filename, O_RDONLY)) { |
48 | if (mmap_fd_ == -1) { |
49 | TF_LITE_REPORT_ERROR(error_reporter, "Could not open '%s'." , filename); |
50 | } |
51 | } |
52 | |
53 | MMAPAllocation::MMAPAllocation(int fd, ErrorReporter* error_reporter) |
54 | : MMAPAllocation(error_reporter, dup(fd)) { |
55 | if (mmap_fd_ == -1) { |
56 | TF_LITE_REPORT_ERROR(error_reporter, "Failed to dup '%d' file descriptor." , |
57 | fd); |
58 | } |
59 | } |
60 | |
61 | MMAPAllocation::MMAPAllocation(int fd, size_t offset, size_t length, |
62 | ErrorReporter* error_reporter) |
63 | : MMAPAllocation(error_reporter, dup(fd), offset, length) { |
64 | if (mmap_fd_ == -1) { |
65 | TF_LITE_REPORT_ERROR(error_reporter, "Failed to dup '%d' file descriptor." , |
66 | fd); |
67 | } |
68 | } |
69 | |
70 | MMAPAllocation::MMAPAllocation(ErrorReporter* error_reporter, int owned_fd) |
71 | : MMAPAllocation(error_reporter, owned_fd, /*offset=*/0, |
72 | /*length=*/GetFdSizeBytes(owned_fd)) {} |
73 | |
74 | MMAPAllocation::MMAPAllocation(ErrorReporter* error_reporter, int owned_fd, |
75 | size_t offset, size_t length) |
76 | : Allocation(error_reporter, Allocation::Type::kMMap), |
77 | mmap_fd_(owned_fd), |
78 | mmapped_buffer_(MAP_FAILED), |
79 | buffer_size_bytes_(length) { |
80 | if (owned_fd < 0) { |
81 | return; |
82 | } |
83 | |
84 | #ifdef __ANDROID__ |
85 | static int pagesize = getpagesize(); |
86 | #else |
87 | static int pagesize = sysconf(_SC_PAGE_SIZE); |
88 | #endif |
89 | |
90 | offset_in_buffer_ = offset % pagesize; |
91 | |
92 | size_t file_size = GetFdSizeBytes(mmap_fd_); |
93 | if (length + offset > file_size) { |
94 | TF_LITE_REPORT_ERROR(error_reporter, |
95 | "Asked to mmap '%d' bytes from fd '%d' at offset " |
96 | "'%d'. This is over the length of file '%d'." , |
97 | length, mmap_fd_, offset, file_size); |
98 | return; |
99 | } |
100 | |
101 | mmapped_buffer_ = |
102 | mmap(nullptr, /*__len=*/length + offset_in_buffer_, PROT_READ, MAP_SHARED, |
103 | mmap_fd_, /*__offset=*/offset - offset_in_buffer_); |
104 | if (mmapped_buffer_ == MAP_FAILED) { |
105 | TF_LITE_REPORT_ERROR(error_reporter, |
106 | "Mmap of '%d' at offset '%d' failed with error '%d'." , |
107 | mmap_fd_, offset, errno); |
108 | return; |
109 | } |
110 | } |
111 | |
112 | MMAPAllocation::~MMAPAllocation() { |
113 | if (valid()) { |
114 | munmap(const_cast<void*>(mmapped_buffer_), |
115 | buffer_size_bytes_ + offset_in_buffer_); |
116 | } |
117 | if (mmap_fd_ >= 0) { |
118 | close(mmap_fd_); |
119 | } |
120 | } |
121 | |
122 | const void* MMAPAllocation::base() const { |
123 | return reinterpret_cast<const void*>( |
124 | reinterpret_cast<const char*>(mmapped_buffer_) + offset_in_buffer_); |
125 | } |
126 | |
127 | size_t MMAPAllocation::bytes() const { return buffer_size_bytes_; } |
128 | |
129 | bool MMAPAllocation::valid() const { return mmapped_buffer_ != MAP_FAILED; } |
130 | |
131 | bool MMAPAllocation::IsSupported() { return true; } |
132 | |
133 | } // namespace tflite |
134 | |