From fb6c9ff7f21e46edf8a7d72cc77769966a3f6a05 Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Fri, 15 Sep 2023 15:17:24 +0200 Subject: shared_memory: win32 impl --- TODO | 15 +++--- build_and_test.sh | 4 +- source/kit/shared_memory.h | 24 ++++++--- source/kit/shared_memory.posix.c | 105 +++++++++++---------------------------- source/kit/shared_memory.win32.c | 72 +++++++++++++++++++++++++++ source/kit/status.h | 17 ++++--- source/kit/threads.win32.c | 3 ++ source/tests/test_interprocess.c | 29 ++++++----- 8 files changed, 158 insertions(+), 111 deletions(-) diff --git a/TODO b/TODO index eb568f1..5571249 100644 --- a/TODO +++ b/TODO @@ -8,24 +8,25 @@ To-Do - Memory stack - Bump - Data formats - - UTF-8. + - UTF-8 - XML - JSON - unival - System - - Better atomics support. - - System call + - Better atomics support + - System call, run process - Terminal - File and memory mapping - Inter-process transfer - Sockets tests. - - Graphics boilerplate + - System boilerplate (graphics, audio, input) + - SDL - X11 (Linux) - Win32 (Windows) - Cocoa (macOS) - Emscripten (WebAssembly) - Parsing OpenGL interface - Utils - - parse, print. - - String builder. - - HTTP 1 client. + - parse, print + - String builder + - HTTP 1 client diff --git a/build_and_test.sh b/build_and_test.sh index 28e05ed..4133639 100644 --- a/build_and_test.sh +++ b/build_and_test.sh @@ -223,8 +223,8 @@ else STATUS=1 fi -./build/test_interprocess writer & -./build/test_interprocess reader +./build/test_interprocess reader & +./build/test_interprocess writer if [ $? -eq 0 ]; then echo "interprocess - OK" else diff --git a/source/kit/shared_memory.h b/source/kit/shared_memory.h index 5eb4fc4..811bd0b 100644 --- a/source/kit/shared_memory.h +++ b/source/kit/shared_memory.h @@ -5,6 +5,10 @@ #include "allocator.h" #include "string_ref.h" +#if !defined(_WIN32) || defined(__CYGWIN__) +# include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -13,14 +17,22 @@ typedef struct { kit_status_t status; i64 size; u8 *bytes; - struct { - u8 internal[512]; - } _state; +#if defined(_WIN32) && !defined(__CYGWIN__) + void *_handle; +#else + i8 _owned; + i32 _fd; + char _name[NAME_MAX + 1]; +#endif } kit_shared_memory_t; -kit_shared_memory_t kit_shared_memory_create(kit_str_t name, - i64 size); -kit_shared_memory_t kit_shared_memory_open(kit_str_t name, i64 size); +enum { + KIT_SHARED_MEMORY_OPEN, + KIT_SHARED_MEMORY_CREATE, +}; + +kit_shared_memory_t kit_shared_memory_open(kit_str_t name, i64 size, + i32 mode); kit_status_t kit_shared_memory_close(kit_shared_memory_t *mem); #ifdef __cplusplus diff --git a/source/kit/shared_memory.posix.c b/source/kit/shared_memory.posix.c index d2c4973..1695f14 100644 --- a/source/kit/shared_memory.posix.c +++ b/source/kit/shared_memory.posix.c @@ -7,119 +7,77 @@ # include # include # include -# include # include -typedef struct { - i8 owned; - i32 fd; - char name[NAME_MAX + 1]; -} kit_shared_memory_internal_t; - -kit_shared_memory_t kit_shared_memory_create(kit_str_t name, - i64 size) { - kit_shared_memory_t mem; - kit_shared_memory_internal_t *internal = - (kit_shared_memory_internal_t *) &mem._state; +kit_shared_memory_t kit_shared_memory_open(kit_str_t name, i64 size, + i32 mode) { + kit_shared_memory_t mem; memset(&mem, 0, sizeof mem); + assert(size > 0); + assert(name.size > 0); assert(name.size + 1 <= NAME_MAX); - if (name.size + 1 > NAME_MAX) { - mem.status = KIT_ERROR_NAME_TOO_LONG; - return mem; - } - - for (i64 i = 0; i < name.size; i++) - if (name.values[i] == '/') { - mem.status = KIT_ERROR_INVALID_NAME; - return mem; - } - - internal->name[0] = '/'; - memcpy(internal->name + 1, name.values, name.size); - internal->name[1 + name.size] = '\0'; + assert(name.values != NULL); - i32 fd = shm_open(internal->name, O_RDWR | O_CREAT | O_EXCL, 0660); - - assert(fd != -1); - if (fd == -1) { - mem.status = KIT_ERROR_SHM_OPEN_FAILED; + if (size <= 0) { + mem.status = KIT_ERROR_INVALID_SIZE; return mem; } - if (ftruncate(fd, size) == -1) { - shm_unlink(internal->name); - assert(0); - mem.status = KIT_ERROR_FTRUNCATE_FAILED; + if (name.size <= 0) { + mem.status = KIT_ERROR_INVALID_NAME; return mem; } - void *p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, - 0); - - if (p == MAP_FAILED) { - shm_unlink(internal->name); - assert(0); - mem.status = KIT_ERROR_MMAP_FAILED; - return mem; - } - - internal->owned = 1; - internal->fd = fd; - - mem.status = KIT_OK; - mem.size = size; - mem.bytes = (u8 *) p; - return mem; -} - -kit_shared_memory_t kit_shared_memory_open(kit_str_t name, i64 size) { - kit_shared_memory_t mem; - kit_shared_memory_internal_t *internal = - (kit_shared_memory_internal_t *) &mem._state; - - memset(&mem, 0, sizeof mem); - - assert(name.size + 1 <= NAME_MAX); if (name.size + 1 > NAME_MAX) { mem.status = KIT_ERROR_NAME_TOO_LONG; return mem; } for (i64 i = 0; i < name.size; i++) - if (name.values[i] == '/') { + if (name.values[i] == '/' || name.values[i] == '\\') { mem.status = KIT_ERROR_INVALID_NAME; return mem; } - internal->name[0] = '/'; - memcpy(internal->name + 1, name.values, name.size); - internal->name[1 + name.size] = '\0'; + mem._name[0] = '/'; + memcpy(mem._name + 1, name.values, name.size); + mem._name[1 + name.size] = '\0'; - i32 fd = shm_open(internal->name, O_RDWR, 0660); + i32 fd = shm_open(mem._name, + mode == KIT_SHARED_MEMORY_CREATE + ? O_RDWR | O_CREAT | O_EXCL + : O_RDWR, + mode == KIT_SHARED_MEMORY_CREATE ? 0660 : 0); - assert(fd != -1); if (fd == -1) { mem.status = KIT_ERROR_SHM_OPEN_FAILED; return mem; } + if (mode == KIT_SHARED_MEMORY_CREATE && ftruncate(fd, size) == -1) { + shm_unlink(mem._name); + assert(0); + mem.status = KIT_ERROR_FTRUNCATE_FAILED; + return mem; + } + void *p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (p == MAP_FAILED) { + shm_unlink(mem._name); assert(0); mem.status = KIT_ERROR_MMAP_FAILED; return mem; } - internal->owned = 0; - internal->fd = fd; - mem.status = KIT_OK; mem.size = size; mem.bytes = (u8 *) p; + mem._owned = (mode == KIT_SHARED_MEMORY_CREATE); + mem._fd = fd; return mem; } @@ -129,14 +87,11 @@ kit_status_t kit_shared_memory_close(kit_shared_memory_t *mem) { if (mem == NULL) return KIT_ERROR_INVALID_ARGUMENT; - kit_shared_memory_internal_t *internal = - (kit_shared_memory_internal_t *) &mem->_state; - kit_status_t status = KIT_OK; if (munmap(mem->bytes, mem->size) != 0) status |= KIT_ERROR_MUNMAP_FAILED; - if (internal->owned && shm_unlink(internal->name) != 0) + if (mem->_owned && shm_unlink(mem->_name) != 0) status |= KIT_ERROR_UNLINK_FAILED; return status; diff --git a/source/kit/shared_memory.win32.c b/source/kit/shared_memory.win32.c index f23d3a8..b13308f 100644 --- a/source/kit/shared_memory.win32.c +++ b/source/kit/shared_memory.win32.c @@ -1,4 +1,76 @@ #include "shared_memory.h" #if defined(_WIN32) && !defined(__CYGWIN__) +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# ifndef NOMINMAX +# define NOMINMAX +# endif +# include + +kit_shared_memory_t kit_shared_memory_open(kit_str_t name, i64 size, + i32 mode) { + kit_shared_memory_t mem; + memset(&mem, 0, sizeof mem); + + char buf[264] = "Global\\"; + + assert(size > 0); + assert(name.size > 0); + assert(name.size + 8 < sizeof buf); + assert(name.values != NULL); + + if (name.size <= 0) { + mem.status = KIT_ERROR_INVALID_NAME; + return mem; + } + + if (name.size + 8 >= sizeof buf) { + mem.status = KIT_ERROR_NAME_TOO_LONG; + return mem; + } + + for (i64 i = 0; i < name.size; i++) + if (name.values[i] == '/' || name.values[i] == '\\') { + mem.status = KIT_ERROR_INVALID_NAME; + return mem; + } + + memcpy(buf + 7, name, name.size); + buf[7 + name.size] = '\0'; + + HANDLE h = mode == KIT_SHARED_MEMORY_CREATE + ? CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, 0, size, buf) + : OpenFileMappingA(FILE_MAP_ALL_ACCESS, NULL, buf); + + assert(h != NULL); + if (h == NULL) { + mem.status = KIT_ERROR_SHM_OPEN_FAILED; + return mem; + } + + void *p = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, size); + + assert(p != NULL); + if (p == NULL) { + CloseHandle(h); + mem.status = KIT_ERROR_MMAP_FAILED; + return mem; + } + + mem.status = KIT_OK; + mem.size = size; + mem.bytes = (u8 *) p; + mem._handle = h; + return mem; +} + +kit_status_t kit_shared_memory_close(kit_shared_memory_t *mem) { + assert(mem != NULL); + + UnmapViewOfFile(mem.bytes); + CloseHandle(mem._handle); +} #endif diff --git a/source/kit/status.h b/source/kit/status.h index e38a36b..983e263 100644 --- a/source/kit/status.h +++ b/source/kit/status.h @@ -4,8 +4,8 @@ #include "types.h" enum { - KIT_OK, - KIT_ERROR_NOT_IMPLEMENTED = (1), + KIT_OK = 0, + KIT_ERROR_NOT_IMPLEMENTED = 1, KIT_ERROR_BAD_ALLOC = (1 << 1), KIT_ERROR_INVALID_ARGUMENT = (1 << 2), KIT_ERROR_MKDIR_FAILED = (1 << 3), @@ -17,12 +17,13 @@ enum { KIT_ERROR_SOCKETS_STARTUP_FAILED = (1 << 9), KIT_ERROR_SOCKET_CONTROL_FAILED = (1 << 10), KIT_ERROR_NAME_TOO_LONG = (1 << 11), - KIT_ERROR_INVALID_NAME = (1 << 12), - KIT_ERROR_SHM_OPEN_FAILED = (1 << 13), - KIT_ERROR_SHM_UNLINK_FAILED = (1 << 14), - KIT_ERROR_FTRUNCATE_FAILED = (1 << 15), - KIT_ERROR_MMAP_FAILED = (1 << 16), - KIT_ERROR_MUNMAP_FAILED = (1 << 17), + KIT_ERROR_INVALID_SIZE = (1 << 12), + KIT_ERROR_INVALID_NAME = (1 << 13), + KIT_ERROR_SHM_OPEN_FAILED = (1 << 14), + KIT_ERROR_SHM_UNLINK_FAILED = (1 << 15), + KIT_ERROR_FTRUNCATE_FAILED = (1 << 16), + KIT_ERROR_MMAP_FAILED = (1 << 17), + KIT_ERROR_MUNMAP_FAILED = (1 << 18), }; typedef i32 kit_status_t; diff --git a/source/kit/threads.win32.c b/source/kit/threads.win32.c index 414f15a..72f0ba1 100644 --- a/source/kit/threads.win32.c +++ b/source/kit/threads.win32.c @@ -13,6 +13,9 @@ # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN 1 # endif +# ifndef NOMINMAX +# define NOMINMAX +# endif # include /* diff --git a/source/tests/test_interprocess.c b/source/tests/test_interprocess.c index 30a8779..fece68f 100644 --- a/source/tests/test_interprocess.c +++ b/source/tests/test_interprocess.c @@ -3,24 +3,20 @@ #include -#ifdef _WIN32 -int main() { - return 0; -} -#else -# define NAME "kit_test_interprocess" +#define NAME "kit_test_interprocess" enum { SIZE = 64 }; enum { STATE_INIT, STATE_READY, STATE_DONE }; int run_writer() { - kit_shared_memory_t mem = kit_shared_memory_create(SZ(NAME), SIZE); + kit_shared_memory_t mem = kit_shared_memory_open( + SZ(NAME), SIZE, KIT_SHARED_MEMORY_CREATE); if (mem.status != KIT_OK) { - printf("%s: kit_shared_memory_create failed.\n", __FUNCTION__); + printf("%s: kit_shared_memory_open failed.\n", __FUNCTION__); fflush(stdout); - return mem.status; + return 1; } mem.bytes[0] = STATE_INIT; @@ -33,12 +29,19 @@ int run_writer() { } int run_reader() { - kit_shared_memory_t mem = kit_shared_memory_open(SZ(NAME), SIZE); + kit_shared_memory_t mem; + for (;;) { + mem = kit_shared_memory_open(SZ(NAME), SIZE, + KIT_SHARED_MEMORY_OPEN); + if (mem.status == KIT_OK) + break; + thrd_yield(); + } if (mem.status != KIT_OK) { printf("%s: kit_shared_memory_open failed.\n", __FUNCTION__); fflush(stdout); - return mem.status; + return 1; } while (mem.bytes[0] != STATE_READY) thrd_yield(); @@ -54,7 +57,8 @@ int run_reader() { mem.bytes[0] = STATE_DONE; - status |= kit_shared_memory_close(&mem); + if (kit_shared_memory_close(&mem) != KIT_OK) + status = 1; return status; } @@ -90,4 +94,3 @@ int main(int argc, char **argv) { printf("Invalid command line argument \"%s\"\n", argv[1]); return 1; } -#endif -- cgit v1.2.3