mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Shim around mmap on Windows
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/mman.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "extern/utf8decoder.h"
|
#include "extern/utf8decoder.h"
|
||||||
|
#include "platform.h" /* For `mmap` */
|
||||||
|
|
||||||
#include "asm/asm.h"
|
#include "asm/asm.h"
|
||||||
#include "asm/lexer.h"
|
#include "asm/lexer.h"
|
||||||
@@ -312,12 +313,55 @@ static void initState(struct LexerState *state)
|
|||||||
state->expansionOfs = 0;
|
state->expansionOfs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Neither MSVC nor MinGW provide `mmap` */
|
||||||
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
|
# include <windows.h>
|
||||||
|
# include <fileapi.h>
|
||||||
|
# include <winbase.h>
|
||||||
|
# define MAP_FAILED NULL
|
||||||
|
# define mapFile(ptr, fd, path, size) do { \
|
||||||
|
HANDLE file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, \
|
||||||
|
FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_RANDOM_ACCESS, NULL); \
|
||||||
|
HANDLE mappingObj; \
|
||||||
|
\
|
||||||
|
if (file == INVALID_HANDLE_VALUE) \
|
||||||
|
break; \
|
||||||
|
mappingObj = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL); \
|
||||||
|
(ptr) = mappingObj == INVALID_HANDLE_VALUE \
|
||||||
|
? NULL \
|
||||||
|
: MapViewOfFile(mappingObj, FILE_MAP_READ, 0, 0, 0); \
|
||||||
|
CloseHandle(mappingObj); \
|
||||||
|
CloseHandle(file); \
|
||||||
|
} while (0)
|
||||||
|
# define munmap(ptr, size) UnmapViewOfFile((ptr))
|
||||||
|
|
||||||
|
#else /* defined(_MSC_VER) || defined(__MINGW32__) */
|
||||||
|
|
||||||
|
# include <sys/mman.h>
|
||||||
|
# define mapFile(ptr, fd, path, size) do { \
|
||||||
|
(ptr) = mmap(NULL, (size), PROT_READ, MAP_PRIVATE, (fd), 0); \
|
||||||
|
\
|
||||||
|
if ((ptr) == MAP_FAILED && errno == ENOTSUP) { \
|
||||||
|
/*
|
||||||
|
* The implementation may not support MAP_PRIVATE; try again with MAP_SHARED
|
||||||
|
* instead, offering, I believe, weaker guarantees about external
|
||||||
|
* modifications to the file while reading it. That's still better than not
|
||||||
|
* opening it at all, though.
|
||||||
|
*/ \
|
||||||
|
if (verbose) \
|
||||||
|
printf("mmap(%s, MAP_PRIVATE) failed, retrying with MAP_SHARED\n", path); \
|
||||||
|
(ptr) = mmap(NULL, (size), PROT_READ, MAP_SHARED, (fd), 0); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#endif /* !( defined(_MSC_VER) || defined(__MINGW32__) ) */
|
||||||
|
|
||||||
struct LexerState *lexer_OpenFile(char const *path)
|
struct LexerState *lexer_OpenFile(char const *path)
|
||||||
{
|
{
|
||||||
dbgPrint("Opening file \"%s\"\n", path);
|
dbgPrint("Opening file \"%s\"\n", path);
|
||||||
|
|
||||||
bool isStdin = !strcmp(path, "-");
|
bool isStdin = !strcmp(path, "-");
|
||||||
struct LexerState *state = malloc(sizeof(*state));
|
struct LexerState *state = malloc(sizeof(*state));
|
||||||
|
struct stat fileInfo;
|
||||||
|
|
||||||
/* Give stdin a nicer file name */
|
/* Give stdin a nicer file name */
|
||||||
if (isStdin)
|
if (isStdin)
|
||||||
@@ -326,38 +370,27 @@ struct LexerState *lexer_OpenFile(char const *path)
|
|||||||
error("Failed to allocate memory for lexer state: %s\n", strerror(errno));
|
error("Failed to allocate memory for lexer state: %s\n", strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
state->path = path;
|
if (!isStdin && stat(path, &fileInfo) != 0) {
|
||||||
|
error("Failed to stat file \"%s\": %s\n", path, strerror(errno));
|
||||||
state->isFile = true;
|
|
||||||
state->fd = isStdin ? STDIN_FILENO : open(path, O_RDONLY);
|
|
||||||
if (state->fd == -1) {
|
|
||||||
error("Failed to open file \"%s\": %s\n", path, strerror(errno));
|
|
||||||
free(state);
|
free(state);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
state->path = path;
|
||||||
|
state->isFile = true;
|
||||||
|
state->fd = isStdin ? STDIN_FILENO : open(path, O_RDONLY);
|
||||||
state->isMmapped = false; /* By default, assume it won't be mmap()ed */
|
state->isMmapped = false; /* By default, assume it won't be mmap()ed */
|
||||||
off_t size = lseek(state->fd, 0, SEEK_END);
|
if (!isStdin && fileInfo.st_size > 0) {
|
||||||
|
/* Try using `mmap` for better performance */
|
||||||
if (size != 1) {
|
|
||||||
/* The file is a regular file, so use `mmap` for better performance */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Important: do NOT assign to `state->ptr` directly, to avoid a cast that may
|
* Important: do NOT assign to `state->ptr` directly, to avoid a cast that may
|
||||||
* alter an eventual `MAP_FAILED` value. It would also invalidate `state->fd`,
|
* alter an eventual `MAP_FAILED` value. It would also invalidate `state->fd`,
|
||||||
* being on the other side of the union.
|
* being on the other side of the union.
|
||||||
*/
|
*/
|
||||||
void *pa = mmap(NULL, size, PROT_READ, MAP_PRIVATE, state->fd, 0);
|
void *mappingAddr;
|
||||||
|
|
||||||
if (pa == MAP_FAILED && errno == ENOTSUP)
|
mapFile(mappingAddr, state->fd, state->path, fileInfo.st_size);
|
||||||
/*
|
if (mappingAddr == MAP_FAILED) {
|
||||||
* The implementation may not support MAP_PRIVATE; try again with MAP_SHARED
|
|
||||||
* instead, offering, I believe, weaker guarantees about external
|
|
||||||
* modifications to the file while reading it. That's still better than not
|
|
||||||
* opening it at all, though.
|
|
||||||
*/
|
|
||||||
pa = mmap(NULL, size, PROT_READ, MAP_SHARED, state->fd, 0);
|
|
||||||
|
|
||||||
if (pa == MAP_FAILED) {
|
|
||||||
/* If mmap()ing failed, try again using another method (below) */
|
/* If mmap()ing failed, try again using another method (below) */
|
||||||
state->isMmapped = false;
|
state->isMmapped = false;
|
||||||
} else {
|
} else {
|
||||||
@@ -365,8 +398,8 @@ struct LexerState *lexer_OpenFile(char const *path)
|
|||||||
close(state->fd);
|
close(state->fd);
|
||||||
|
|
||||||
state->isMmapped = true;
|
state->isMmapped = true;
|
||||||
state->ptr = pa;
|
state->ptr = mappingAddr;
|
||||||
state->size = size;
|
state->size = fileInfo.st_size;
|
||||||
state->offset = 0;
|
state->offset = 0;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
@@ -378,7 +411,6 @@ struct LexerState *lexer_OpenFile(char const *path)
|
|||||||
if (verbose)
|
if (verbose)
|
||||||
printf("File %s opened as regular, errno reports \"%s\"\n",
|
printf("File %s opened as regular, errno reports \"%s\"\n",
|
||||||
path, strerror(errno));
|
path, strerror(errno));
|
||||||
lseek(state->fd, 0, SEEK_SET);
|
|
||||||
state->index = 0;
|
state->index = 0;
|
||||||
state->nbChars = 0;
|
state->nbChars = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user