mmap.cpp: also added createTemporary() support

metadata
Wenzel Jakob 2013-12-19 23:05:31 +01:00
parent 4bae47db4c
commit c97ea5f1cb
4 changed files with 118 additions and 6 deletions

View File

@ -103,7 +103,12 @@ public:
//! @{ \name Miscellaneous
// =============================================================
/// Create a temporary file and return an associated FileStream
/**
* \brief Create a temporary file and return an associated FileStream
*
* \remark When closing the file stream, the file is automatically
* deleted.
*/
static ref<FileStream> createTemporary();
/// Initialize the file I/O layer (unicode conversions etc.)

View File

@ -54,14 +54,28 @@ public:
*/
void resize(size_t size);
/// Return the associated filename
const fs::path &getFilename() const;
/// Return whether the mapped memory region is read-only
bool isReadOnly() const;
/// Return a string representation
std::string toString() const;
/**
* \brief Create a temporary memory-mapped file
*
* \remark When closing the mapping, the file is
* automatically deleted.
*/
static ref<MemoryMappedFile> createTemporary(size_t size);
MTS_DECLARE_CLASS()
protected:
/// Internal constructor
MemoryMappedFile();
/// Release all resources
virtual ~MemoryMappedFile();
private:

View File

@ -53,7 +53,6 @@ FileStream::FileStream(const fs::path &path, EFileMode mode)
open(path, mode);
}
FileStream::~FileStream() {
if (d->file != 0)
close();
@ -189,7 +188,6 @@ void FileStream::close() {
}
}
void FileStream::remove() {
close();
Log(EDebug, "Removing \"%s\"", d->path.string().c_str());

View File

@ -18,9 +18,10 @@ struct MemoryMappedFile::MemoryMappedFilePrivate {
size_t size;
void *data;
bool readOnly;
bool temp;
MemoryMappedFilePrivate(const fs::path & f, size_t s = 0)
: filename(f), size(s), data(NULL), readOnly(false) {}
MemoryMappedFilePrivate(const fs::path &f = "", size_t s = 0)
: filename(f), size(s), data(NULL), readOnly(false), temp(false) {}
void create() {
#if defined(__LINUX__) || defined(__OSX__)
@ -57,10 +58,69 @@ struct MemoryMappedFile::MemoryMappedFilePrivate {
readOnly = false;
}
void createTemp() {
readOnly = false;
temp = true;
#if defined(__LINUX__) || defined(__OSX__)
char *path = strdup("/tmp/mitsuba_XXXXXX");
int fd = mkstemp(path);
if (fd == -1)
SLog(EError, "Unable to create temporary file (1): %s", strerror(errno));
filename = path;
free(path);
int result = lseek(fd, size-1, SEEK_SET);
if (result == -1)
Log(EError, "Could not set file size of \"%s\"!", filename.string().c_str());
result = write(fd, "", 1);
if (result != 1)
Log(EError, "Could not write to \"%s\"!", filename.string().c_str());
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == NULL)
Log(EError, "Could not map \"%s\" to memory!", filename.string().c_str());
if (close(fd) != 0)
Log(EError, "close(): unable to close file!");
#elif defined(__WINDOWS__)
WCHAR tempPath[MAX_PATH];
WCHAR filename[MAX_PATH];
unsigned int ret = GetTempPathW(MAX_PATH, tempPath);
if (ret == 0 || ret > MAX_PATH)
SLog(EError, "GetTempPath failed(): %s", lastErrorText().c_str());
ret = GetTempFileNameW(tempPath, TEXT("mitsuba"), 0, filename);
if (ret == 0)
SLog(EError, "GetTempFileName failed(): %s", lastErrorText().c_str());
file = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE)
SLog(EError, "Error while trying to create temporary file \"%s\": %s",
d->path.string().c_str(), lastErrorText().c_str());
filename = fs::path(filename);
fileMapping = CreateFileMapping(file, NULL, PAGE_READWRITE, 0,
static_cast<DWORD>(size), NULL);
if (fileMapping == NULL)
Log(EError, "CreateFileMapping: Could not map \"%s\" to memory: %s",
filename.string().c_str(), lastErrorText().c_str());
data = (void *) MapViewOfFile(fileMapping, FILE_MAP_WRITE, 0, 0, 0);
if (data == NULL)
Log(EError, "MapViewOfFile: Could not map \"%s\" to memory: %s",
filename.string().c_str(), lastErrorText().c_str());
#endif
}
void map() {
if (!fs::exists(filename))
Log(EError, "The file \"%s\" does not exist!", filename.string().c_str());
size = (size_t) fs::file_size(filename);
#if defined(__LINUX__) || defined(__OSX__)
int fd = open(filename.string().c_str(), readOnly ? O_RDONLY : O_RDWR);
if (fd == -1)
@ -91,10 +151,19 @@ struct MemoryMappedFile::MemoryMappedFilePrivate {
void unmap() {
SLog(ETrace, "Unmapping \"%s\" from memory",
filename.string().c_str());
#if defined(__LINUX__) || defined(__OSX__)
if (temp) {
/* Temporary file that will be deleted in any case:
invalidate dirty pages to avoid a costly flush to disk */
int retval = msync(data, size, MS_INVALIDATE);
if (retval != 0)
Log(EError, "munmap(): unable to unmap memory: %s", strerror(errno));
}
int retval = munmap(data, size);
if (retval != 0)
Log(EError, "munmap(): unable to unmap memory!");
Log(EError, "munmap(): unable to unmap memory: %s", strerror(errno));
#elif defined(__WINDOWS__)
if (!UnmapViewOfFile(data))
Log(EError, "UnmapViewOfFile(): unable to unmap memory: %s", lastErrorText().c_str());
@ -103,11 +172,23 @@ struct MemoryMappedFile::MemoryMappedFilePrivate {
if (!CloseHandle(file))
Log(EError, "CloseHandle(): unable to close file: %s", lastErrorText().c_str());
#endif
if (temp) {
try {
fs::remove(filename);
} catch (...) {
Log(EWarn, "unmap(): Unable to delete file \"%s\"", filename.string().c_str());
}
}
data = NULL;
size = 0;
}
};
MemoryMappedFile::MemoryMappedFile()
: d(new MemoryMappedFilePrivate()) { }
MemoryMappedFile::MemoryMappedFile(const fs::path &filename, size_t size)
: d(new MemoryMappedFilePrivate(filename, size)) {
SLog(ETrace, "Creating memory-mapped file \"%s\" (%s)..",
@ -138,10 +219,13 @@ MemoryMappedFile::~MemoryMappedFile() {
void MemoryMappedFile::resize(size_t size) {
if (!d->data)
Log(EError, "Internal error in MemoryMappedFile::resize()!");
bool temp = d->temp;
d->temp = false;
d->unmap();
fs::resize_file(d->filename, size);
d->size = size;
d->map();
d->temp = temp;
}
void *MemoryMappedFile::getData() {
@ -161,6 +245,17 @@ bool MemoryMappedFile::isReadOnly() const {
return d->readOnly;
}
const fs::path &MemoryMappedFile::getFilename() const {
return d->filename;
}
ref<MemoryMappedFile> MemoryMappedFile::createTemporary(size_t size) {
ref<MemoryMappedFile> result = new MemoryMappedFile();
result->d->size = size;
result->d->createTemp();
return result;
}
std::string MemoryMappedFile::toString() const {
std::ostringstream oss;
oss << "MemoryMappedFile[filename=\""