shithub: rgbds

Download patch

ref: 82469ac0fde1b2e73bfbfc58853a7ecb95e4a794
parent: 96cb5e10ed87e7f072f9f98440a4139a13ba013d
author: ISSOtm <eldredhabert0@gmail.com>
date: Mon Aug 31 10:27:24 EDT 2020

Shim around `mmap` on Windows

--- a/src/asm/lexer.c
+++ b/src/asm/lexer.c
@@ -6,7 +6,7 @@
  * SPDX-License-Identifier: MIT
  */
 
-#include <sys/mman.h>
+#include <sys/types.h>
 #include <sys/stat.h>
 #include <assert.h>
 #include <ctype.h>
@@ -22,6 +22,7 @@
 #include <unistd.h>
 
 #include "extern/utf8decoder.h"
+#include "platform.h" /* For `mmap` */
 
 #include "asm/asm.h"
 #include "asm/lexer.h"
@@ -312,6 +313,48 @@
 	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)
 {
 	dbgPrint("Opening file \"%s\"\n", path);
@@ -318,6 +361,7 @@
 
 	bool isStdin = !strcmp(path, "-");
 	struct LexerState *state = malloc(sizeof(*state));
+	struct stat fileInfo;
 
 	/* Give stdin a nicer file name */
 	if (isStdin)
@@ -326,38 +370,27 @@
 		error("Failed to allocate memory for lexer state: %s\n", strerror(errno));
 		return NULL;
 	}
-	state->path = path;
-
-	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));
+	if (!isStdin && stat(path, &fileInfo) != 0) {
+		error("Failed to stat file \"%s\": %s\n", path, strerror(errno));
 		free(state);
 		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 */
-	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
 		 * alter an eventual `MAP_FAILED` value. It would also invalidate `state->fd`,
 		 * 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)
-			/*
-			 * 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) {
+		mapFile(mappingAddr, state->fd, state->path, fileInfo.st_size);
+		if (mappingAddr == MAP_FAILED) {
 			/* If mmap()ing failed, try again using another method (below) */
 			state->isMmapped = false;
 		} else {
@@ -365,8 +398,8 @@
 			close(state->fd);
 
 			state->isMmapped = true;
-			state->ptr = pa;
-			state->size = size;
+			state->ptr = mappingAddr;
+			state->size = fileInfo.st_size;
 			state->offset = 0;
 
 			if (verbose)
@@ -378,7 +411,6 @@
 		if (verbose)
 			printf("File %s opened as regular, errno reports \"%s\"\n",
 			       path, strerror(errno));
-		lseek(state->fd, 0, SEEK_SET);
 		state->index = 0;
 		state->nbChars = 0;
 	}