|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #ifndef Mappable_h |
|
6 #define Mappable_h |
|
7 |
|
8 #include <sys/types.h> |
|
9 #include <pthread.h> |
|
10 #include "Zip.h" |
|
11 #include "SeekableZStream.h" |
|
12 #include "mozilla/RefPtr.h" |
|
13 #include "mozilla/Scoped.h" |
|
14 #include "zlib.h" |
|
15 |
|
16 /** |
|
17 * Abstract class to handle mmap()ing from various kind of entities, such as |
|
18 * plain files or Zip entries. The virtual members are meant to act as the |
|
19 * equivalent system functions, except mapped memory is always MAP_PRIVATE, |
|
20 * even though a given implementation may use something different internally. |
|
21 */ |
|
22 class Mappable: public mozilla::RefCounted<Mappable> |
|
23 { |
|
24 public: |
|
25 MOZ_DECLARE_REFCOUNTED_TYPENAME(Mappable) |
|
26 virtual ~Mappable() { } |
|
27 |
|
28 virtual MemoryRange mmap(const void *addr, size_t length, int prot, int flags, |
|
29 off_t offset) = 0; |
|
30 |
|
31 enum Kind { |
|
32 MAPPABLE_FILE, |
|
33 MAPPABLE_EXTRACT_FILE, |
|
34 MAPPABLE_DEFLATE, |
|
35 MAPPABLE_SEEKABLE_ZSTREAM |
|
36 }; |
|
37 |
|
38 virtual Kind GetKind() const = 0; |
|
39 |
|
40 private: |
|
41 virtual void munmap(void *addr, size_t length) { |
|
42 ::munmap(addr, length); |
|
43 } |
|
44 /* Limit use of Mappable::munmap to classes that keep track of the address |
|
45 * and size of the mapping. This allows to ignore ::munmap return value. */ |
|
46 friend class Mappable1stPagePtr; |
|
47 friend class LibHandle; |
|
48 |
|
49 public: |
|
50 /** |
|
51 * Ensures the availability of the memory pages for the page(s) containing |
|
52 * the given address. Returns whether the pages were successfully made |
|
53 * available. |
|
54 */ |
|
55 virtual bool ensure(const void *addr) { return true; } |
|
56 |
|
57 /** |
|
58 * Indicate to a Mappable instance that no further mmap is going to happen. |
|
59 */ |
|
60 virtual void finalize() = 0; |
|
61 |
|
62 /** |
|
63 * Shows some stats about the Mappable instance. |
|
64 * Meant for MappableSeekableZStream only. |
|
65 * As Mappables don't keep track of what they are instanciated for, the name |
|
66 * argument is used to make the stats logging useful to the reader. The when |
|
67 * argument is to be used by the caller to give an identifier of the when |
|
68 * the stats call is made. |
|
69 */ |
|
70 virtual void stats(const char *when, const char *name) const { } |
|
71 |
|
72 /** |
|
73 * Returns the maximum length that can be mapped from this Mappable for |
|
74 * offset = 0. |
|
75 */ |
|
76 virtual size_t GetLength() const = 0; |
|
77 }; |
|
78 |
|
79 /** |
|
80 * Mappable implementation for plain files |
|
81 */ |
|
82 class MappableFile: public Mappable |
|
83 { |
|
84 public: |
|
85 ~MappableFile() { } |
|
86 |
|
87 /** |
|
88 * Create a MappableFile instance for the given file path. |
|
89 */ |
|
90 static Mappable *Create(const char *path); |
|
91 |
|
92 /* Inherited from Mappable */ |
|
93 virtual MemoryRange mmap(const void *addr, size_t length, int prot, int flags, off_t offset); |
|
94 virtual void finalize(); |
|
95 virtual size_t GetLength() const; |
|
96 |
|
97 virtual Kind GetKind() const { return MAPPABLE_FILE; }; |
|
98 protected: |
|
99 MappableFile(int fd): fd(fd) { } |
|
100 |
|
101 private: |
|
102 /* File descriptor */ |
|
103 AutoCloseFD fd; |
|
104 }; |
|
105 |
|
106 /** |
|
107 * Mappable implementation for deflated stream in a Zip archive |
|
108 * Inflates the complete stream into a cache file. |
|
109 */ |
|
110 class MappableExtractFile: public MappableFile |
|
111 { |
|
112 public: |
|
113 ~MappableExtractFile(); |
|
114 |
|
115 /** |
|
116 * Create a MappableExtractFile instance for the given Zip stream. The name |
|
117 * argument is used to create the cache file in the cache directory. |
|
118 */ |
|
119 static Mappable *Create(const char *name, Zip *zip, Zip::Stream *stream); |
|
120 |
|
121 /* Override finalize from MappableFile */ |
|
122 virtual void finalize() {} |
|
123 |
|
124 virtual Kind GetKind() const { return MAPPABLE_EXTRACT_FILE; }; |
|
125 private: |
|
126 MappableExtractFile(int fd, char *path) |
|
127 : MappableFile(fd), path(path), pid(getpid()) { } |
|
128 |
|
129 /** |
|
130 * AutoUnlinkFile keeps track or a file name and removes (unlinks) the file |
|
131 * when the instance is destroyed. |
|
132 */ |
|
133 struct AutoUnlinkFileTraits: public mozilla::ScopedDeleteArrayTraits<char> |
|
134 { |
|
135 static void release(char *value) |
|
136 { |
|
137 if (!value) |
|
138 return; |
|
139 unlink(value); |
|
140 mozilla::ScopedDeleteArrayTraits<char>::release(value); |
|
141 } |
|
142 }; |
|
143 typedef mozilla::Scoped<AutoUnlinkFileTraits> AutoUnlinkFile; |
|
144 |
|
145 /* Extracted file */ |
|
146 AutoUnlinkFile path; |
|
147 |
|
148 /* Id of the process that initialized the instance */ |
|
149 pid_t pid; |
|
150 }; |
|
151 |
|
152 class _MappableBuffer; |
|
153 |
|
154 /** |
|
155 * Mappable implementation for deflated stream in a Zip archive. |
|
156 * Inflates the mapped bits in a temporary buffer. |
|
157 */ |
|
158 class MappableDeflate: public Mappable |
|
159 { |
|
160 public: |
|
161 ~MappableDeflate(); |
|
162 |
|
163 /** |
|
164 * Create a MappableDeflate instance for the given Zip stream. The name |
|
165 * argument is used for an appropriately named temporary file, and the Zip |
|
166 * instance is given for the MappableDeflate to keep a reference of it. |
|
167 */ |
|
168 static Mappable *Create(const char *name, Zip *zip, Zip::Stream *stream); |
|
169 |
|
170 /* Inherited from Mappable */ |
|
171 virtual MemoryRange mmap(const void *addr, size_t length, int prot, int flags, off_t offset); |
|
172 virtual void finalize(); |
|
173 virtual size_t GetLength() const; |
|
174 |
|
175 virtual Kind GetKind() const { return MAPPABLE_DEFLATE; }; |
|
176 private: |
|
177 MappableDeflate(_MappableBuffer *buf, Zip *zip, Zip::Stream *stream); |
|
178 |
|
179 /* Zip reference */ |
|
180 mozilla::RefPtr<Zip> zip; |
|
181 |
|
182 /* Decompression buffer */ |
|
183 mozilla::ScopedDeletePtr<_MappableBuffer> buffer; |
|
184 |
|
185 /* Zlib data */ |
|
186 z_stream zStream; |
|
187 }; |
|
188 |
|
189 /** |
|
190 * Mappable implementation for seekable zStreams. |
|
191 * Inflates the mapped bits in a temporary buffer, on demand. |
|
192 */ |
|
193 class MappableSeekableZStream: public Mappable |
|
194 { |
|
195 public: |
|
196 ~MappableSeekableZStream(); |
|
197 |
|
198 /** |
|
199 * Create a MappableSeekableZStream instance for the given Zip stream. The |
|
200 * name argument is used for an appropriately named temporary file, and the |
|
201 * Zip instance is given for the MappableSeekableZStream to keep a reference |
|
202 * of it. |
|
203 */ |
|
204 static Mappable *Create(const char *name, Zip *zip, |
|
205 Zip::Stream *stream); |
|
206 |
|
207 /* Inherited from Mappable */ |
|
208 virtual MemoryRange mmap(const void *addr, size_t length, int prot, int flags, off_t offset); |
|
209 virtual void munmap(void *addr, size_t length); |
|
210 virtual void finalize(); |
|
211 virtual bool ensure(const void *addr); |
|
212 virtual void stats(const char *when, const char *name) const; |
|
213 virtual size_t GetLength() const; |
|
214 |
|
215 virtual Kind GetKind() const { return MAPPABLE_SEEKABLE_ZSTREAM; }; |
|
216 private: |
|
217 MappableSeekableZStream(Zip *zip); |
|
218 |
|
219 /* Zip reference */ |
|
220 mozilla::RefPtr<Zip> zip; |
|
221 |
|
222 /* Decompression buffer */ |
|
223 mozilla::ScopedDeletePtr<_MappableBuffer> buffer; |
|
224 |
|
225 /* Seekable ZStream */ |
|
226 SeekableZStream zStream; |
|
227 |
|
228 /* Keep track of mappings performed with MappableSeekableZStream::mmap so |
|
229 * that they can be realized by MappableSeekableZStream::ensure. |
|
230 * Values stored in the struct are those passed to mmap */ |
|
231 struct LazyMap |
|
232 { |
|
233 const void *addr; |
|
234 size_t length; |
|
235 int prot; |
|
236 off_t offset; |
|
237 |
|
238 /* Returns addr + length, as a pointer */ |
|
239 const void *end() const { |
|
240 return reinterpret_cast<const void *> |
|
241 (reinterpret_cast<const unsigned char *>(addr) + length); |
|
242 } |
|
243 |
|
244 /* Returns offset + length */ |
|
245 const off_t endOffset() const { |
|
246 return offset + length; |
|
247 } |
|
248 |
|
249 /* Returns the offset corresponding to the given address */ |
|
250 const off_t offsetOf(const void *ptr) const { |
|
251 return reinterpret_cast<uintptr_t>(ptr) |
|
252 - reinterpret_cast<uintptr_t>(addr) + offset; |
|
253 } |
|
254 |
|
255 /* Returns whether the given address is in the LazyMap range */ |
|
256 const bool Contains(const void *ptr) const { |
|
257 return (ptr >= addr) && (ptr < end()); |
|
258 } |
|
259 }; |
|
260 |
|
261 /* List of all mappings */ |
|
262 std::vector<LazyMap> lazyMaps; |
|
263 |
|
264 /* Array keeping track of which chunks have already been decompressed. |
|
265 * Each value is the number of pages decompressed for the given chunk. */ |
|
266 mozilla::ScopedDeleteArray<unsigned char> chunkAvail; |
|
267 |
|
268 /* Number of chunks that have already been decompressed. */ |
|
269 mozilla::Atomic<size_t> chunkAvailNum; |
|
270 |
|
271 /* Mutex protecting decompression */ |
|
272 pthread_mutex_t mutex; |
|
273 }; |
|
274 |
|
275 #endif /* Mappable_h */ |