From 162fd65c477c5cd37a743d90e3880480da0b3282 Mon Sep 17 00:00:00 2001 From: Francesco Cozzuto Date: Sun, 7 Apr 2024 22:17:33 +0200 Subject: [PATCH] Merge io_linux.c and io_win.c into io.c --- README.txt | 4 +- io_linux.c => io.c | 98 ++++++++++++++++++++++++++++++++++++++++++++-- io.h | 9 +++++ io_win.c | 94 -------------------------------------------- makefile | 5 ++- 5 files changed, 110 insertions(+), 100 deletions(-) rename io_linux.c => io.c (75%) delete mode 100644 io_win.c diff --git a/README.txt b/README.txt index bc895fb..57e9ec2 100644 --- a/README.txt +++ b/README.txt @@ -1,6 +1,6 @@ -This repository implements a cross-platform (Windows and Linux) API for asynchronous I/O operations. It's backed by io_uring on Linux and I/O completion ports (IOCP) on windows. It has no dependencies (other than OS stuff and freestanding libc headers) and does no dynamic allocations. +This repository implements a cross-platform (Windows and Linux) API for asynchronous I/O operations. It's backed by io_uring on Linux and I/O completion ports (IOCP) on Windows. It has no dependencies (other than OS stuff and freestanding libc headers) and does no dynamic allocations. It's likely that the io_uring code has some bugs, so be wary! Also bug reports are appreciated :) -To use it, you need to add io_linux.c and io_win.c in your source tree and compile them as they were your files. Each .c file is ignored when not compiling for its platform, so you can include them both in all builds. +To use it, you need to add io.c and io.h in your source tree and compile them as they were your own files. diff --git a/io_linux.c b/io.c similarity index 75% rename from io_linux.c rename to io.c index 6fd24ee..60418d0 100644 --- a/io_linux.c +++ b/io.c @@ -1,12 +1,104 @@ + #include "io.h" +#if IO_PLATFORM_WINDOWS + +#include + +/* + * Declare Windows symbols locally to avoid including windows.h + */ + +#define ERROR_IO_PENDING 997l + +extern int ReadFile(void *handle, void *dst, unsigned long max, unsigned long *num, struct io_overlap *ov); +extern int WriteFile(void *handle, const void *src, unsigned long max, unsigned long *num, struct io_overlap *ov); +extern void *CreateIoCompletionPort(void *handle, void *existing_ioport, unsigned long *ptr, unsigned long num_threads); +extern int CloseHandle(void *handle); +extern unsigned long GetLastError(); +extern int GetQueuedCompletionStatus(void *ioport, unsigned long *num, unsigned long *key, struct io_overlap **ov, unsigned long timeout); + +bool io_context_init(struct io_context *ioc, + struct io_operation *ops, + uint32_t max_ops) +{ + io_handle handle = CreateIoCompletionPort(IO_INVALID_HANDLE, NULL, 0, 1); + if (handle == IO_INVALID_HANDLE) + return false; + + ioc->handle = handle; + ioc->max_ops = max_ops; + ioc->ops = ops; + return true; +} + +void io_context_free(struct io_context *ioc) +{ + CloseHandle(ioc->handle); +} + +static struct io_operation *alloc_op(struct io_context *ioc) +{ + for (uint32_t i = 0; i < ioc->max_ops; i++) + if (ioc->ops[i].type == IO_VOID) + return &ioc->ops[i]; + return NULL; +} + +bool io_start_recv(struct io_context *ioc, io_handle handle, + void *dst, uint32_t max, void *user) +{ + struct io_operation *op = alloc_op(ioc); + if (op == NULL) + return false; + + memset(&op->ov, 0, sizeof(struct io_overlap)); + + int ok = ReadFile(handle, dst, max, NULL, &op->ov); + if (!ok && GetLastError() != ERROR_IO_PENDING) + return false; + + op->user = user; + op->type = IO_RECV; + return true; +} + +bool io_start_send(struct io_context *ioc, io_handle handle, + void *src, uint32_t num, void *user) +{ + struct io_operation *op = alloc_op(ioc); + if (op == NULL) + return false; + + memset(&op->ov, 0, sizeof(struct io_overlap)); + + int ok = WriteFile(handle, src, num, NULL, &op->ov); + if (!ok && GetLastError() != ERROR_IO_PENDING) + return false; + + op->user = user; + op->type = IO_SEND; + return true; +} + +bool io_start_accept(struct io_context *ioc, io_handle handle, void *user) +{ + // TODO + return false; +} + +void io_wait(struct io_context *ioc, struct io_event *ev) +{ + // TODO +} + +#endif + + #if IO_PLATFORM_LINUX #include #include -#include -#include -#include #include #include diff --git a/io.h b/io.h index 72c1314..cc0022a 100644 --- a/io.h +++ b/io.h @@ -162,3 +162,12 @@ bool io_start_accept(struct io_context *ioc, io_handle handle, */ void io_wait(struct io_context *ioc, struct io_event *ev); + +io_handle io_open_file(struct io_context *ioc, + const char *name, int flags); + +io_handle io_create_file(struct io_context *ioc, + const char *name, int flags); + +io_handle io_listen(struct io_context *ioc, + const char *addr, int port); \ No newline at end of file diff --git a/io_win.c b/io_win.c deleted file mode 100644 index c309d02..0000000 --- a/io_win.c +++ /dev/null @@ -1,94 +0,0 @@ -#include "io.h" - -#if IO_PLATFORM_WINDOWS - -#include - -/* - * Declare Windows symbols locally to avoid including windows.h - */ - -#define ERROR_IO_PENDING 997l - -extern int ReadFile(void *handle, void *dst, unsigned long max, unsigned long *num, struct io_overlap *ov); -extern int WriteFile(void *handle, const void *src, unsigned long max, unsigned long *num, struct io_overlap *ov); -extern void *CreateIoCompletionPort(void *handle, void *existing_ioport, unsigned long *ptr, unsigned long num_threads); -extern int CloseHandle(void *handle); -extern unsigned long GetLastError(); -extern int GetQueuedCompletionStatus(void *ioport, unsigned long *num, unsigned long *key, struct io_overlap **ov, unsigned long timeout); - -bool io_context_init(struct io_context *ioc, - struct io_operation *ops, - uint32_t max_ops) -{ - io_handle handle = CreateIoCompletionPort(IO_INVALID_HANDLE, NULL, 0, 1); - if (handle == IO_INVALID_HANDLE) - return false; - - ioc->handle = handle; - ioc->max_ops = max_ops; - ioc->ops = ops; - return true; -} - -void io_context_free(struct io_context *ioc) -{ - CloseHandle(ioc->handle); -} - -static struct io_operation *alloc_op(struct io_context *ioc) -{ - for (uint32_t i = 0; i < ioc->max_ops; i++) - if (ioc->ops[i].type == IO_VOID) - return &ioc->ops[i]; - return NULL; -} - -bool io_start_recv(struct io_context *ioc, io_handle handle, - void *dst, uint32_t max, void *user) -{ - struct io_operation *op = alloc_op(ioc); - if (op == NULL) - return false; - - memset(&op->ov, 0, sizeof(struct io_overlap)); - - int ok = ReadFile(handle, dst, max, NULL, &op->ov); - if (!ok && GetLastError() != ERROR_IO_PENDING) - return false; - - op->user = user; - op->type = IO_RECV; - return true; -} - -bool io_start_send(struct io_context *ioc, io_handle handle, - void *src, uint32_t num, void *user) -{ - struct io_operation *op = alloc_op(ioc); - if (op == NULL) - return false; - - memset(&op->ov, 0, sizeof(struct io_overlap)); - - int ok = WriteFile(handle, src, num, NULL, &op->ov); - if (!ok && GetLastError() != ERROR_IO_PENDING) - return false; - - op->user = user; - op->type = IO_SEND; - return true; -} - -bool io_start_accept(struct io_context *ioc, io_handle handle, void *user) -{ - // TODO - return false; -} - -void io_wait(struct io_context *ioc, struct io_event *ev) -{ - // TODO -} - -#endif \ No newline at end of file diff --git a/makefile b/makefile index b49c1d5..c7f3eb4 100644 --- a/makefile +++ b/makefile @@ -1,2 +1,5 @@ all: - gcc example.c io_win.c io_linux.c -o example -Wall -Wextra -ggdb \ No newline at end of file + gcc example.c io.c -o example -Wall -Wextra -ggdb + +clean: + rm example example.exe \ No newline at end of file