Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--intern/guardedalloc/CMakeLists.txt6
-rw-r--r--intern/guardedalloc/intern/mmap_win.c294
-rw-r--r--intern/guardedalloc/mmap_win.h50
-rw-r--r--source/blender/blenlib/BLI_mmap.h59
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/BLI_mmap.c233
-rw-r--r--source/blender/blenloader/intern/readfile.c68
-rw-r--r--source/blender/blenloader/intern/readfile.h4
-rw-r--r--source/blender/imbuf/intern/IMB_allocimbuf.h2
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c2
-rw-r--r--source/blender/imbuf/intern/readimage.c24
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt6
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt1
13 files changed, 376 insertions, 375 deletions
diff --git a/intern/guardedalloc/CMakeLists.txt b/intern/guardedalloc/CMakeLists.txt
index 0d46e81cd87..b47565b8ef9 100644
--- a/intern/guardedalloc/CMakeLists.txt
+++ b/intern/guardedalloc/CMakeLists.txt
@@ -49,12 +49,6 @@ set(LIB
)
if(WIN32 AND NOT UNIX)
- list(APPEND SRC
- intern/mmap_win.c
-
- mmap_win.h
- )
-
list(APPEND INC_SYS
${PTHREADS_INC}
)
diff --git a/intern/guardedalloc/intern/mmap_win.c b/intern/guardedalloc/intern/mmap_win.c
deleted file mode 100644
index a02a0f88fa9..00000000000
--- a/intern/guardedalloc/intern/mmap_win.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2008 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup MEM
- */
-
-#ifdef WIN32
-
-# include <errno.h>
-# include <io.h>
-# include <stdio.h>
-# include <sys/types.h>
-# include <windows.h>
-
-# include "mmap_win.h"
-
-# ifndef FILE_MAP_EXECUTE
-// not defined in earlier versions of the Platform SDK (before February 2003)
-# define FILE_MAP_EXECUTE 0x0020
-# endif
-
-/* copied from BLI_utildefines.h, ugh */
-# ifdef __GNUC__
-# define UNUSED(x) UNUSED_##x __attribute__((__unused__))
-# else
-# define UNUSED(x) x
-# endif
-
-/* --------------------------------------------------------------------- */
-/* local storage definitions */
-/* --------------------------------------------------------------------- */
-/* all memory mapped chunks are put in linked lists */
-typedef struct mmapLink {
- struct mmapLink *next, *prev;
-} mmapLink;
-
-typedef struct mmapListBase {
- void *first, *last;
-} mmapListBase;
-
-typedef struct MemMap {
- struct MemMap *next, *prev;
- void *mmap;
- HANDLE fhandle;
- HANDLE maphandle;
-} MemMap;
-
-/* --------------------------------------------------------------------- */
-/* local functions */
-/* --------------------------------------------------------------------- */
-
-static void mmap_addtail(volatile mmapListBase *listbase, void *vlink);
-static void mmap_remlink(volatile mmapListBase *listbase, void *vlink);
-static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr);
-
-static int mmap_get_prot_flags(int flags);
-static int mmap_get_access_flags(int flags);
-
-/* --------------------------------------------------------------------- */
-/* vars */
-/* --------------------------------------------------------------------- */
-volatile static struct mmapListBase _mmapbase;
-volatile static struct mmapListBase *mmapbase = &_mmapbase;
-
-/* --------------------------------------------------------------------- */
-/* implementation */
-/* --------------------------------------------------------------------- */
-
-/* mmap for windows */
-void *mmap(void *UNUSED(start), size_t len, int prot, int flags, int fd, off_t offset)
-{
- HANDLE fhandle = INVALID_HANDLE_VALUE;
- HANDLE maphandle;
- int prot_flags = mmap_get_prot_flags(prot);
- int access_flags = mmap_get_access_flags(prot);
- MemMap *mm = NULL;
- void *ptr = NULL;
-
- if (flags & MAP_FIXED) {
- return MAP_FAILED;
- }
-
-# if 0
- if (fd == -1) {
- _set_errno(EBADF);
- return MAP_FAILED;
- }
-# endif
-
- if (fd != -1) {
- fhandle = (HANDLE)_get_osfhandle(fd);
- }
- if (fhandle == INVALID_HANDLE_VALUE) {
- if (!(flags & MAP_ANONYMOUS)) {
- errno = EBADF;
- return MAP_FAILED;
- }
- }
- else {
- if (!DuplicateHandle(GetCurrentProcess(),
- fhandle,
- GetCurrentProcess(),
- &fhandle,
- 0,
- FALSE,
- DUPLICATE_SAME_ACCESS)) {
- return MAP_FAILED;
- }
- }
-
- /* Split 64 bit size into low and high bits. */
- DWORD len_bits_high = len >> 32;
- DWORD len_bits_low = len & 0xFFFFFFFF;
-
- maphandle = CreateFileMapping(fhandle, NULL, prot_flags, len_bits_high, len_bits_low, NULL);
- if (maphandle == 0) {
- errno = EBADF;
- return MAP_FAILED;
- }
-
- ptr = MapViewOfFile(maphandle, access_flags, 0, offset, 0);
- if (ptr == NULL) {
- DWORD dwLastErr = GetLastError();
- if (dwLastErr == ERROR_MAPPED_ALIGNMENT) {
- errno = EINVAL;
- }
- else {
- errno = EACCES;
- }
- CloseHandle(maphandle);
- return MAP_FAILED;
- }
-
- mm = (MemMap *)malloc(sizeof(MemMap));
- if (!mm) {
- errno = ENOMEM;
- }
- mm->fhandle = fhandle;
- mm->maphandle = maphandle;
- mm->mmap = ptr;
- mmap_addtail(mmapbase, mm);
-
- return ptr;
-}
-
-/* munmap for windows */
-intptr_t munmap(void *ptr, size_t UNUSED(size))
-{
- MemMap *mm = mmap_findlink(mmapbase, ptr);
- if (!mm) {
- errno = EINVAL;
- return -1;
- }
- UnmapViewOfFile(mm->mmap);
- CloseHandle(mm->maphandle);
- CloseHandle(mm->fhandle);
- mmap_remlink(mmapbase, mm);
- free(mm);
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-/* local functions */
-/* --------------------------------------------------------------------- */
-
-static void mmap_addtail(volatile mmapListBase *listbase, void *vlink)
-{
- struct mmapLink *link = vlink;
-
- if (link == NULL) {
- return;
- }
- if (listbase == NULL) {
- return;
- }
-
- link->next = 0;
- link->prev = listbase->last;
-
- if (listbase->last) {
- ((struct mmapLink *)listbase->last)->next = link;
- }
- if (listbase->first == NULL) {
- listbase->first = link;
- }
- listbase->last = link;
-}
-
-static void mmap_remlink(volatile mmapListBase *listbase, void *vlink)
-{
- struct mmapLink *link = vlink;
-
- if (link == NULL) {
- return;
- }
- if (listbase == NULL) {
- return;
- }
- if (link->next) {
- link->next->prev = link->prev;
- }
- if (link->prev) {
- link->prev->next = link->next;
- }
-
- if (listbase->last == link) {
- listbase->last = link->prev;
- }
- if (listbase->first == link) {
- listbase->first = link->next;
- }
-}
-
-static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr)
-{
- MemMap *mm;
-
- if (ptr == NULL) {
- return NULL;
- }
- if (listbase == NULL) {
- return NULL;
- }
-
- mm = (MemMap *)listbase->first;
- while (mm) {
- if (mm->mmap == ptr) {
- return mm;
- }
- mm = mm->next;
- }
- return NULL;
-}
-
-static int mmap_get_prot_flags(int flags)
-{
- int prot = PAGE_NOACCESS;
-
- if ((flags & PROT_READ) == PROT_READ) {
- if ((flags & PROT_WRITE) == PROT_WRITE) {
- prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
- }
- else {
- prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_READONLY;
- }
- }
- else if ((flags & PROT_WRITE) == PROT_WRITE) {
- prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_WRITECOPY;
- }
- else if ((flags & PROT_EXEC) == PROT_EXEC) {
- prot = PAGE_EXECUTE_READ;
- }
- return prot;
-}
-
-static int mmap_get_access_flags(int flags)
-{
- int access = 0;
-
- if ((flags & PROT_READ) == PROT_READ) {
- if ((flags & PROT_WRITE) == PROT_WRITE) {
- access = FILE_MAP_WRITE;
- }
- else {
- access = (flags & PROT_EXEC) ? FILE_MAP_EXECUTE : FILE_MAP_READ;
- }
- }
- else if ((flags & PROT_WRITE) == PROT_WRITE) {
- access = FILE_MAP_COPY;
- }
- else if ((flags & PROT_EXEC) == PROT_EXEC) {
- access = FILE_MAP_EXECUTE;
- }
- return access;
-}
-
-#endif // WIN32
diff --git a/intern/guardedalloc/mmap_win.h b/intern/guardedalloc/mmap_win.h
deleted file mode 100644
index c0cbaa0e512..00000000000
--- a/intern/guardedalloc/mmap_win.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2008 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup MEM
- */
-
-#ifndef __MMAP_WIN_H__
-#define __MMAP_WIN_H__
-
-#define PROT_NONE 0
-#define PROT_READ 1
-#define PROT_WRITE 2
-#define PROT_EXEC 4
-
-#define MAP_FILE 0
-#define MAP_SHARED 1
-#define MAP_PRIVATE 2
-#define MAP_TYPE 0xF
-#define MAP_FIXED 0x10
-#define MAP_ANONYMOUS 0x20
-#define MAP_ANON MAP_ANONYMOUS
-
-#define MAP_FAILED ((void *)-1)
-
-/* needed for uintptr_t, exception, dont use BLI anywhere else in MEM_* */
-#include "../../source/blender/blenlib/BLI_sys_types.h"
-
-#include <sys/types.h>
-
-void *mmap(void *start, size_t len, int prot, int flags, int fd, off_t offset);
-intptr_t munmap(void *ptr, size_t size);
-
-#endif
diff --git a/source/blender/blenlib/BLI_mmap.h b/source/blender/blenlib/BLI_mmap.h
new file mode 100644
index 00000000000..385c56bd10a
--- /dev/null
+++ b/source/blender/blenlib/BLI_mmap.h
@@ -0,0 +1,59 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+#ifndef __BLI_MMAP_H__
+#define __BLI_MMAP_H__
+
+/** \file
+ * \ingroup bli
+ */
+
+#include "BLI_compiler_attrs.h"
+#include "BLI_utildefines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Memory-mapped file IO that implements all the OS-specific details and error handling. */
+
+struct BLI_mmap_file;
+
+typedef struct BLI_mmap_file BLI_mmap_file;
+
+/* Prepares an opened file for memory-mapped IO.
+ * May return NULL if the operation fails.
+ * Note that this seeks to the end of the file to determine its length. */
+BLI_mmap_file *BLI_mmap_open(int fd) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+
+/* Reads length bytes from file at the given offset into dest.
+ * Returns whether the operation was successful (may fail when reading beyond the file
+ * end or when IO errors occur). */
+bool BLI_mmap_read(BLI_mmap_file *file, void *dest, size_t offset, size_t length)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+
+void *BLI_mmap_get_pointer(BLI_mmap_file *file) ATTR_WARN_UNUSED_RESULT;
+
+void BLI_mmap_free(BLI_mmap_file *file) ATTR_NONNULL(1);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BLI_MEMPOOL_H__ */
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index aa4c4efe7d4..b7a13596dd0 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -54,6 +54,7 @@ set(SRC
intern/BLI_memblock.c
intern/BLI_memiter.c
intern/BLI_mempool.c
+ intern/BLI_mmap.c
intern/BLI_timer.c
intern/DLRB_tree.c
intern/array_store.c
@@ -243,6 +244,7 @@ set(SRC
BLI_mempool.h
BLI_mesh_boolean.hh
BLI_mesh_intersect.hh
+ BLI_mmap.h
BLI_mpq2.hh
BLI_mpq3.hh
BLI_multi_value_map.hh
diff --git a/source/blender/blenlib/intern/BLI_mmap.c b/source/blender/blenlib/intern/BLI_mmap.c
new file mode 100644
index 00000000000..f0b13183c68
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_mmap.c
@@ -0,0 +1,233 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bli
+ */
+
+#include "BLI_mmap.h"
+#include "BLI_fileops.h"
+#include "BLI_listbase.h"
+#include "MEM_guardedalloc.h"
+
+#include <string.h>
+
+#ifndef WIN32
+# include <stdlib.h>
+# include <signal.h>
+# include <sys/mman.h> // for mmap
+# include <unistd.h> // for read close
+#else
+# include "BLI_winstuff.h"
+# include <io.h> // for open close read
+#endif
+
+struct BLI_mmap_file {
+ /* The address to which the file was mapped. */
+ char *memory;
+
+ /* The length of the file (and therefore the mapped region). */
+ size_t length;
+
+ /* Platform-specific handle for the mapping. */
+ void *handle;
+
+ /* Flag to indicate IO errors. Needs to be volatile since it's being set from
+ * within the signal handler, which is not part of the normal execution flow. */
+ volatile bool io_error;
+};
+
+#ifndef WIN32
+/* When using memory-mapped files, any IO errors will result in a SIGBUS signal.
+ * Therefore, we need to catch that signal and stop reading the file in question.
+ * To do so, we keep a list of all current FileDatas that use memory-mapped files,
+ * and if a SIGBUS is caught, we check if the failed address is inside one of the
+ * mapped regions.
+ * If it is, we set a flag to indicate a failed read and remap the memory in
+ * question to a zero-backed region in order to avoid additional signals.
+ * The code that actually reads the memory area has to check whether the flag was
+ * set after it's done reading.
+ * If the error occurred outside of a memory-mapped region, we call the previous
+ * handler if one was configured and abort the process otherwise.
+ */
+
+struct error_handler_data {
+ ListBase open_mmaps;
+ char configured;
+ void (*next_handler)(int, siginfo_t *, void *);
+} error_handler = {0};
+
+static void sigbus_handler(int sig, siginfo_t *siginfo, void *ptr)
+{
+ /* We only handle SIGBUS here for now. */
+ BLI_assert(sig == SIGBUS);
+
+ char *error_addr = (char *)siginfo->si_addr;
+ /* Find the file that this error belongs to. */
+ LISTBASE_FOREACH (LinkData *, link, &error_handler.open_mmaps) {
+ BLI_mmap_file *file = link->data;
+
+ /* Is the address where the error occurred in this file's mapped range? */
+ if (error_addr >= file->memory && error_addr < file->memory + file->length) {
+ file->io_error = true;
+
+ /* Replace the mapped memory with zeroes. */
+ mmap(file->memory, file->length, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+
+ return;
+ }
+ }
+
+ /* Fall back to other handler if there was one. */
+ if (error_handler.next_handler) {
+ error_handler.next_handler(sig, siginfo, ptr);
+ }
+ else {
+ fprintf(stderr, "Unhandled SIGBUS caught\n");
+ abort();
+ }
+}
+
+/* Ensures that the error handler is set up and ready. */
+static bool sigbus_handler_setup(void)
+{
+ if (!error_handler.configured) {
+ struct sigaction newact = {0}, oldact = {0};
+
+ newact.sa_sigaction = sigbus_handler;
+ newact.sa_flags = SA_SIGINFO;
+
+ if (sigaction(SIGBUS, &newact, &oldact)) {
+ return false;
+ }
+
+ /* Remember the previously configured handler to fall back to it if the error
+ * does not belong to any of the mapped files. */
+ error_handler.next_handler = oldact.sa_sigaction;
+ error_handler.configured = 1;
+ }
+
+ return true;
+}
+
+/* Adds a file to the list that the error handler checks. */
+static void sigbus_handler_add(BLI_mmap_file *file)
+{
+ BLI_addtail(&error_handler.open_mmaps, BLI_genericNodeN(file));
+}
+
+/* Removes a file from the list that the error handler checks. */
+static void sigbus_handler_remove(BLI_mmap_file *file)
+{
+ LinkData *link = BLI_findptr(&error_handler.open_mmaps, file, offsetof(LinkData, data));
+ BLI_freelinkN(&error_handler.open_mmaps, link);
+}
+#endif
+
+BLI_mmap_file *BLI_mmap_open(int fd)
+{
+ void *memory, *handle = NULL;
+ size_t length = BLI_lseek(fd, 0, SEEK_END);
+
+#ifndef WIN32
+ /* Ensure that the SIGBUS handler is configured. */
+ if (!sigbus_handler_setup()) {
+ return NULL;
+ }
+
+ /* Map the given file to memory. */
+ memory = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (memory == MAP_FAILED) {
+ return NULL;
+ }
+#else
+ /* Convert the POSIX-style file descriptor to a Windows handle. */
+ void *file_handle = (void *)_get_osfhandle(fd);
+ /* Memory mapping on Windows is a two-step process - first we create a mapping,
+ * then we create a view into that mapping.
+ * In our case, one view that spans the entire file is enough. */
+ handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (handle == NULL) {
+ return NULL;
+ }
+ memory = MapViewOfFile(handle, FILE_MAP_READ, 0, 0, 0);
+ if (memory == NULL) {
+ CloseHandle(handle);
+ return NULL;
+ }
+#endif
+
+ /* Now that the mapping was successful, allocate memory and set up the BLI_mmap_file. */
+ BLI_mmap_file *file = MEM_callocN(sizeof(BLI_mmap_file), __func__);
+ file->memory = memory;
+ file->handle = handle;
+ file->length = length;
+
+#ifndef WIN32
+ /* Register the file with the error handler. */
+ sigbus_handler_add(file);
+#endif
+
+ return file;
+}
+
+bool BLI_mmap_read(BLI_mmap_file *file, void *dest, size_t offset, size_t length)
+{
+ /* If a previous read has already failed or we try to read past the end,
+ * don't even attempt to read any further. */
+ if (file->io_error || (offset + length > file->length)) {
+ return false;
+ }
+
+#ifndef WIN32
+ /* If an error occurs in this call, sigbus_handler will be called and will set
+ * file->io_error to true. */
+ memcpy(dest, file->memory + offset, length);
+#else
+ /* On Windows, we use exception handling to be notified of errors. */
+ __try {
+ memcpy(dest, file->memory + offset, length);
+ }
+ __except (GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER :
+ EXCEPTION_CONTINUE_SEARCH) {
+ file->io_error = true;
+ return false;
+ }
+#endif
+
+ return !file->io_error;
+}
+
+void *BLI_mmap_get_pointer(BLI_mmap_file *file)
+{
+ return file->memory;
+}
+
+void BLI_mmap_free(BLI_mmap_file *file)
+{
+#ifndef WIN32
+ munmap((void *)file->memory, file->length);
+ sigbus_handler_remove(file);
+#else
+ UnmapViewOfFile(file->memory);
+ CloseHandle(file->handle);
+#endif
+
+ MEM_freeN(file);
+}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index b61abd4ed06..2192e9a378f 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -68,6 +68,7 @@
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_mempool.h"
+#include "BLI_mmap.h"
#include "BLI_threads.h"
#include "BLT_translation.h"
@@ -1179,6 +1180,53 @@ static ssize_t fd_read_from_memory(FileData *filedata,
return readsize;
}
+/* Memory-mapped file reading.
+ * By using mmap(), we can map a file so that it can be treated like normal memory,
+ * meaning that we can just read from it with memcpy() etc.
+ * This avoids system call overhead and can significantly speed up file loading.
+ */
+
+static ssize_t fd_read_from_mmap(FileData *filedata,
+ void *buffer,
+ size_t size,
+ bool *UNUSED(r_is_memchunck_identical))
+{
+ /* don't read more bytes than there are available in the buffer */
+ size_t readsize = MIN2(size, (size_t)(filedata->buffersize - filedata->file_offset));
+
+ if (!BLI_mmap_read(filedata->mmap_file, buffer, filedata->file_offset, readsize)) {
+ return 0;
+ }
+
+ filedata->file_offset += readsize;
+
+ return readsize;
+}
+
+static off64_t fd_seek_from_mmap(FileData *filedata, off64_t offset, int whence)
+{
+ off64_t new_pos;
+ if (whence == SEEK_CUR) {
+ new_pos = filedata->file_offset + offset;
+ }
+ else if (whence == SEEK_SET) {
+ new_pos = offset;
+ }
+ else if (whence == SEEK_END) {
+ new_pos = filedata->buffersize + offset;
+ }
+ else {
+ return -1;
+ }
+
+ if (new_pos < 0 || new_pos > filedata->buffersize) {
+ return -1;
+ }
+
+ filedata->file_offset = new_pos;
+ return filedata->file_offset;
+}
+
/* MemFile reading. */
static ssize_t fd_read_from_memfile(FileData *filedata,
@@ -1306,6 +1354,8 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath,
{
FileDataReadFn *read_fn = NULL;
FileDataSeekFn *seek_fn = NULL; /* Optional. */
+ size_t buffersize = 0;
+ BLI_mmap_file *mmap_file = NULL;
gzFile gzfile = (gzFile)Z_NULL;
@@ -1322,14 +1372,21 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath,
return NULL;
}
- BLI_lseek(file, 0, SEEK_SET);
-
/* Regular file. */
if (memcmp(header, "BLENDER", sizeof(header)) == 0) {
read_fn = fd_read_data_from_file;
seek_fn = fd_seek_data_from_file;
+
+ mmap_file = BLI_mmap_open(file);
+ if (mmap_file != NULL) {
+ read_fn = fd_read_from_mmap;
+ seek_fn = fd_seek_from_mmap;
+ buffersize = BLI_lseek(file, 0, SEEK_END);
+ }
}
+ BLI_lseek(file, 0, SEEK_SET);
+
/* Gzip file. */
errno = 0;
if ((read_fn == NULL) &&
@@ -1363,6 +1420,8 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath,
fd->read = read_fn;
fd->seek = seek_fn;
+ fd->mmap_file = mmap_file;
+ fd->buffersize = buffersize;
return fd;
}
@@ -1531,6 +1590,11 @@ void blo_filedata_free(FileData *fd)
fd->buffer = NULL;
}
+ if (fd->mmap_file) {
+ BLI_mmap_free(fd->mmap_file);
+ fd->mmap_file = NULL;
+ }
+
/* Free all BHeadN data blocks */
#ifndef NDEBUG
BLI_freelistN(&fd->bhead_list);
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index c724cc32051..86f05eda7b7 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -41,6 +41,7 @@ struct Object;
struct OldNewMap;
struct ReportList;
struct UserDef;
+struct BLI_mmap_file;
typedef struct IDNameLib_Map IDNameLib_Map;
@@ -83,8 +84,9 @@ typedef struct FileData {
/** Regular file reading. */
int filedes;
- /** Variables needed for reading from memory / stream. */
+ /** Variables needed for reading from memory / stream / memory-mapped files. */
const char *buffer;
+ struct BLI_mmap_file *mmap_file;
/** Variables needed for reading from memfile (undo). */
struct MemFile *memfile;
/** Whether we are undoing (< 0) or redoing (> 0), used to choose which 'unchanged' flag to use
diff --git a/source/blender/imbuf/intern/IMB_allocimbuf.h b/source/blender/imbuf/intern/IMB_allocimbuf.h
index 08aa1936a6f..c92d764a104 100644
--- a/source/blender/imbuf/intern/IMB_allocimbuf.h
+++ b/source/blender/imbuf/intern/IMB_allocimbuf.h
@@ -32,7 +32,7 @@ struct ImBuf;
void imb_refcounter_lock_init(void);
void imb_refcounter_lock_exit(void);
-#ifdef WIN32
+#ifndef WIN32
void imb_mmap_lock_init(void);
void imb_mmap_lock_exit(void);
void imb_mmap_lock(void);
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 8dfb3ada7d6..bfb7bc93ac7 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -53,7 +53,7 @@ void imb_refcounter_lock_exit(void)
BLI_spin_end(&refcounter_spin);
}
-#ifdef WIN32
+#ifndef WIN32
static SpinLock mmap_spin;
void imb_mmap_lock_init(void)
diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c
index f0daa4543e1..50210650f05 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -23,13 +23,13 @@
*/
#ifdef _WIN32
-# include "mmap_win.h"
# include <io.h>
# include <stddef.h>
# include <sys/types.h>
#endif
#include "BLI_fileops.h"
+#include "BLI_mmap.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -186,20 +186,19 @@ ImBuf *IMB_loadifffile(
size = BLI_file_descriptor_size(file);
imb_mmap_lock();
- mem = mmap(NULL, size, PROT_READ, MAP_SHARED, file, 0);
+ BLI_mmap_file *mmap_file = BLI_mmap_open(file);
imb_mmap_unlock();
-
- if (mem == (unsigned char *)-1) {
+ if (mmap_file == NULL) {
fprintf(stderr, "%s: couldn't get mapping %s\n", __func__, descr);
return NULL;
}
+ mem = BLI_mmap_get_pointer(mmap_file);
+
ibuf = IMB_ibImageFromMemory(mem, size, flags, colorspace, descr);
imb_mmap_lock();
- if (munmap(mem, size)) {
- fprintf(stderr, "%s: couldn't unmap file %s\n", __func__, descr);
- }
+ BLI_mmap_free(mmap_file);
imb_mmap_unlock();
return ibuf;
@@ -292,14 +291,15 @@ static void imb_loadtilefile(ImBuf *ibuf, int file, int tx, int ty, unsigned int
size = BLI_file_descriptor_size(file);
imb_mmap_lock();
- mem = mmap(NULL, size, PROT_READ, MAP_SHARED, file, 0);
+ BLI_mmap_file *mmap_file = BLI_mmap_open(file);
imb_mmap_unlock();
-
- if (mem == (unsigned char *)-1) {
+ if (mmap_file == NULL) {
fprintf(stderr, "Couldn't get memory mapping for %s\n", ibuf->cachename);
return;
}
+ mem = BLI_mmap_get_pointer(mmap_file);
+
const ImFileType *type = IMB_file_type_from_ibuf(ibuf);
if (type != NULL) {
if (type->load_tile != NULL) {
@@ -308,9 +308,7 @@ static void imb_loadtilefile(ImBuf *ibuf, int file, int tx, int ty, unsigned int
}
imb_mmap_lock();
- if (munmap(mem, size)) {
- fprintf(stderr, "Couldn't unmap memory for %s.\n", ibuf->cachename);
- }
+ BLI_mmap_free(mmap_file);
imb_mmap_unlock();
}
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index a7adaa7e258..5d1ed7b44a1 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -48,12 +48,6 @@ set(SRC
../../../../intern/guardedalloc/intern/mallocn_lockfree_impl.c
)
-if(WIN32 AND NOT UNIX)
- list(APPEND SRC
- ../../../../intern/guardedalloc/intern/mmap_win.c
- )
-endif()
-
# SRC_DNA_INC is defined in the parent dir
add_cc_flags_custom_test(makesdna)
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 72cdaecb2c3..94cfd8464ae 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -189,7 +189,6 @@ set(SRC
../../../../intern/guardedalloc/intern/mallocn.c
../../../../intern/guardedalloc/intern/mallocn_guarded_impl.c
../../../../intern/guardedalloc/intern/mallocn_lockfree_impl.c
- ../../../../intern/guardedalloc/intern/mmap_win.c
# Needed for defaults.
../../../../release/datafiles/userdef/userdef_default.c