michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef Mappable_h michael@0: #define Mappable_h michael@0: michael@0: #include michael@0: #include michael@0: #include "Zip.h" michael@0: #include "SeekableZStream.h" michael@0: #include "mozilla/RefPtr.h" michael@0: #include "mozilla/Scoped.h" michael@0: #include "zlib.h" michael@0: michael@0: /** michael@0: * Abstract class to handle mmap()ing from various kind of entities, such as michael@0: * plain files or Zip entries. The virtual members are meant to act as the michael@0: * equivalent system functions, except mapped memory is always MAP_PRIVATE, michael@0: * even though a given implementation may use something different internally. michael@0: */ michael@0: class Mappable: public mozilla::RefCounted michael@0: { michael@0: public: michael@0: MOZ_DECLARE_REFCOUNTED_TYPENAME(Mappable) michael@0: virtual ~Mappable() { } michael@0: michael@0: virtual MemoryRange mmap(const void *addr, size_t length, int prot, int flags, michael@0: off_t offset) = 0; michael@0: michael@0: enum Kind { michael@0: MAPPABLE_FILE, michael@0: MAPPABLE_EXTRACT_FILE, michael@0: MAPPABLE_DEFLATE, michael@0: MAPPABLE_SEEKABLE_ZSTREAM michael@0: }; michael@0: michael@0: virtual Kind GetKind() const = 0; michael@0: michael@0: private: michael@0: virtual void munmap(void *addr, size_t length) { michael@0: ::munmap(addr, length); michael@0: } michael@0: /* Limit use of Mappable::munmap to classes that keep track of the address michael@0: * and size of the mapping. This allows to ignore ::munmap return value. */ michael@0: friend class Mappable1stPagePtr; michael@0: friend class LibHandle; michael@0: michael@0: public: michael@0: /** michael@0: * Ensures the availability of the memory pages for the page(s) containing michael@0: * the given address. Returns whether the pages were successfully made michael@0: * available. michael@0: */ michael@0: virtual bool ensure(const void *addr) { return true; } michael@0: michael@0: /** michael@0: * Indicate to a Mappable instance that no further mmap is going to happen. michael@0: */ michael@0: virtual void finalize() = 0; michael@0: michael@0: /** michael@0: * Shows some stats about the Mappable instance. michael@0: * Meant for MappableSeekableZStream only. michael@0: * As Mappables don't keep track of what they are instanciated for, the name michael@0: * argument is used to make the stats logging useful to the reader. The when michael@0: * argument is to be used by the caller to give an identifier of the when michael@0: * the stats call is made. michael@0: */ michael@0: virtual void stats(const char *when, const char *name) const { } michael@0: michael@0: /** michael@0: * Returns the maximum length that can be mapped from this Mappable for michael@0: * offset = 0. michael@0: */ michael@0: virtual size_t GetLength() const = 0; michael@0: }; michael@0: michael@0: /** michael@0: * Mappable implementation for plain files michael@0: */ michael@0: class MappableFile: public Mappable michael@0: { michael@0: public: michael@0: ~MappableFile() { } michael@0: michael@0: /** michael@0: * Create a MappableFile instance for the given file path. michael@0: */ michael@0: static Mappable *Create(const char *path); michael@0: michael@0: /* Inherited from Mappable */ michael@0: virtual MemoryRange mmap(const void *addr, size_t length, int prot, int flags, off_t offset); michael@0: virtual void finalize(); michael@0: virtual size_t GetLength() const; michael@0: michael@0: virtual Kind GetKind() const { return MAPPABLE_FILE; }; michael@0: protected: michael@0: MappableFile(int fd): fd(fd) { } michael@0: michael@0: private: michael@0: /* File descriptor */ michael@0: AutoCloseFD fd; michael@0: }; michael@0: michael@0: /** michael@0: * Mappable implementation for deflated stream in a Zip archive michael@0: * Inflates the complete stream into a cache file. michael@0: */ michael@0: class MappableExtractFile: public MappableFile michael@0: { michael@0: public: michael@0: ~MappableExtractFile(); michael@0: michael@0: /** michael@0: * Create a MappableExtractFile instance for the given Zip stream. The name michael@0: * argument is used to create the cache file in the cache directory. michael@0: */ michael@0: static Mappable *Create(const char *name, Zip *zip, Zip::Stream *stream); michael@0: michael@0: /* Override finalize from MappableFile */ michael@0: virtual void finalize() {} michael@0: michael@0: virtual Kind GetKind() const { return MAPPABLE_EXTRACT_FILE; }; michael@0: private: michael@0: MappableExtractFile(int fd, char *path) michael@0: : MappableFile(fd), path(path), pid(getpid()) { } michael@0: michael@0: /** michael@0: * AutoUnlinkFile keeps track or a file name and removes (unlinks) the file michael@0: * when the instance is destroyed. michael@0: */ michael@0: struct AutoUnlinkFileTraits: public mozilla::ScopedDeleteArrayTraits michael@0: { michael@0: static void release(char *value) michael@0: { michael@0: if (!value) michael@0: return; michael@0: unlink(value); michael@0: mozilla::ScopedDeleteArrayTraits::release(value); michael@0: } michael@0: }; michael@0: typedef mozilla::Scoped AutoUnlinkFile; michael@0: michael@0: /* Extracted file */ michael@0: AutoUnlinkFile path; michael@0: michael@0: /* Id of the process that initialized the instance */ michael@0: pid_t pid; michael@0: }; michael@0: michael@0: class _MappableBuffer; michael@0: michael@0: /** michael@0: * Mappable implementation for deflated stream in a Zip archive. michael@0: * Inflates the mapped bits in a temporary buffer. michael@0: */ michael@0: class MappableDeflate: public Mappable michael@0: { michael@0: public: michael@0: ~MappableDeflate(); michael@0: michael@0: /** michael@0: * Create a MappableDeflate instance for the given Zip stream. The name michael@0: * argument is used for an appropriately named temporary file, and the Zip michael@0: * instance is given for the MappableDeflate to keep a reference of it. michael@0: */ michael@0: static Mappable *Create(const char *name, Zip *zip, Zip::Stream *stream); michael@0: michael@0: /* Inherited from Mappable */ michael@0: virtual MemoryRange mmap(const void *addr, size_t length, int prot, int flags, off_t offset); michael@0: virtual void finalize(); michael@0: virtual size_t GetLength() const; michael@0: michael@0: virtual Kind GetKind() const { return MAPPABLE_DEFLATE; }; michael@0: private: michael@0: MappableDeflate(_MappableBuffer *buf, Zip *zip, Zip::Stream *stream); michael@0: michael@0: /* Zip reference */ michael@0: mozilla::RefPtr zip; michael@0: michael@0: /* Decompression buffer */ michael@0: mozilla::ScopedDeletePtr<_MappableBuffer> buffer; michael@0: michael@0: /* Zlib data */ michael@0: z_stream zStream; michael@0: }; michael@0: michael@0: /** michael@0: * Mappable implementation for seekable zStreams. michael@0: * Inflates the mapped bits in a temporary buffer, on demand. michael@0: */ michael@0: class MappableSeekableZStream: public Mappable michael@0: { michael@0: public: michael@0: ~MappableSeekableZStream(); michael@0: michael@0: /** michael@0: * Create a MappableSeekableZStream instance for the given Zip stream. The michael@0: * name argument is used for an appropriately named temporary file, and the michael@0: * Zip instance is given for the MappableSeekableZStream to keep a reference michael@0: * of it. michael@0: */ michael@0: static Mappable *Create(const char *name, Zip *zip, michael@0: Zip::Stream *stream); michael@0: michael@0: /* Inherited from Mappable */ michael@0: virtual MemoryRange mmap(const void *addr, size_t length, int prot, int flags, off_t offset); michael@0: virtual void munmap(void *addr, size_t length); michael@0: virtual void finalize(); michael@0: virtual bool ensure(const void *addr); michael@0: virtual void stats(const char *when, const char *name) const; michael@0: virtual size_t GetLength() const; michael@0: michael@0: virtual Kind GetKind() const { return MAPPABLE_SEEKABLE_ZSTREAM; }; michael@0: private: michael@0: MappableSeekableZStream(Zip *zip); michael@0: michael@0: /* Zip reference */ michael@0: mozilla::RefPtr zip; michael@0: michael@0: /* Decompression buffer */ michael@0: mozilla::ScopedDeletePtr<_MappableBuffer> buffer; michael@0: michael@0: /* Seekable ZStream */ michael@0: SeekableZStream zStream; michael@0: michael@0: /* Keep track of mappings performed with MappableSeekableZStream::mmap so michael@0: * that they can be realized by MappableSeekableZStream::ensure. michael@0: * Values stored in the struct are those passed to mmap */ michael@0: struct LazyMap michael@0: { michael@0: const void *addr; michael@0: size_t length; michael@0: int prot; michael@0: off_t offset; michael@0: michael@0: /* Returns addr + length, as a pointer */ michael@0: const void *end() const { michael@0: return reinterpret_cast michael@0: (reinterpret_cast(addr) + length); michael@0: } michael@0: michael@0: /* Returns offset + length */ michael@0: const off_t endOffset() const { michael@0: return offset + length; michael@0: } michael@0: michael@0: /* Returns the offset corresponding to the given address */ michael@0: const off_t offsetOf(const void *ptr) const { michael@0: return reinterpret_cast(ptr) michael@0: - reinterpret_cast(addr) + offset; michael@0: } michael@0: michael@0: /* Returns whether the given address is in the LazyMap range */ michael@0: const bool Contains(const void *ptr) const { michael@0: return (ptr >= addr) && (ptr < end()); michael@0: } michael@0: }; michael@0: michael@0: /* List of all mappings */ michael@0: std::vector lazyMaps; michael@0: michael@0: /* Array keeping track of which chunks have already been decompressed. michael@0: * Each value is the number of pages decompressed for the given chunk. */ michael@0: mozilla::ScopedDeleteArray chunkAvail; michael@0: michael@0: /* Number of chunks that have already been decompressed. */ michael@0: mozilla::Atomic chunkAvailNum; michael@0: michael@0: /* Mutex protecting decompression */ michael@0: pthread_mutex_t mutex; michael@0: }; michael@0: michael@0: #endif /* Mappable_h */