diff options
-rw-r--r-- | io_muxer.c | 101 | ||||
-rw-r--r-- | io_muxer.h | 49 |
2 files changed, 150 insertions, 0 deletions
diff --git a/io_muxer.c b/io_muxer.c new file mode 100644 index 0000000..31ebc53 --- /dev/null +++ b/io_muxer.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2022 Mikhail Burakov. This file is part of toolbox. + * + * toolbox 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 3 of the License, or + * (at your option) any later version. + * + * toolbox 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 toolbox. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "io_muxer.h" + +#include <poll.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +struct IoMuxer_Closure { + void (*callback)(void*); + void* user; +}; + +static _Bool AppendRecord(struct IoMuxer* io_muxer) { + if (io_muxer->size < io_muxer->alloc) return 1; + size_t alloc = io_muxer->alloc + 1; + struct pollfd* pfds = realloc(io_muxer->pfds, alloc * sizeof(struct pollfd)); + if (!pfds) return 0; + io_muxer->pfds = pfds; + struct IoMuxer_Closure* closures = + realloc(io_muxer->closures, alloc * sizeof(struct IoMuxer_Closure)); + if (!closures) return 0; + io_muxer->closures = closures; + io_muxer->alloc = alloc; + return 1; +} + +static void CompressRecords(struct IoMuxer* io_muxer) { + for (size_t forward = 0, reverse = io_muxer->size - 1; io_muxer->size;) { + while (forward < reverse && !io_muxer->pfds[forward].revents) forward++; + while (forward < reverse && io_muxer->pfds[reverse].revents) reverse--; + if (forward == reverse) { + if (!io_muxer->pfds[forward].revents) forward++; + io_muxer->size = forward; + return; + } + struct pollfd pfd = io_muxer->pfds[forward]; + io_muxer->pfds[forward] = io_muxer->pfds[reverse]; + io_muxer->pfds[reverse] = pfd; + struct IoMuxer_Closure closure = io_muxer->closures[forward]; + io_muxer->closures[forward] = io_muxer->closures[reverse]; + io_muxer->closures[reverse] = closure; + } +} + +void IoMuxer_Create(struct IoMuxer* io_muxer) { + memset(io_muxer, 0, sizeof(struct IoMuxer)); +} + +int IoMuxer_OnRead(struct IoMuxer* io_muxer, int fd, + void (*read_callback)(void*), void* user) { + if (!AppendRecord(io_muxer)) return -1; + struct pollfd pfd = {.fd = fd, .events = POLLIN}; + struct IoMuxer_Closure closure = {.callback = read_callback, .user = user}; + io_muxer->pfds[io_muxer->size] = pfd; + io_muxer->closures[io_muxer->size] = closure; + io_muxer->size++; + return 0; +} + +int IoMuxer_OnWrite(struct IoMuxer* io_muxer, int fd, + void (*write_callback)(void*), void* user) { + if (!AppendRecord(io_muxer)) return -1; + struct pollfd pfd = {.fd = fd, .events = POLLOUT}; + struct IoMuxer_Closure closure = {.callback = write_callback, .user = user}; + io_muxer->pfds[io_muxer->size] = pfd; + io_muxer->closures[io_muxer->size] = closure; + return 0; +} + +int IoMuxer_Iterate(struct IoMuxer* io_muxer) { + CompressRecords(io_muxer); + int result = poll(io_muxer->pfds, io_muxer->size, -1); + if (result <= 0) return -1; + for (size_t i = 0; i < io_muxer->size; i++) { + if (io_muxer->pfds[i].revents) + io_muxer->closures[i].callback(io_muxer->closures[i].user); + } + return 0; +} + +void IoMuxer_Destroy(struct IoMuxer* io_muxer) { + free(io_muxer->pfds); + free(io_muxer->closures); +} diff --git a/io_muxer.h b/io_muxer.h new file mode 100644 index 0000000..75fa832 --- /dev/null +++ b/io_muxer.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2022 Mikhail Burakov. This file is part of toolbox. + * + * toolbox 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 3 of the License, or + * (at your option) any later version. + * + * toolbox 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 toolbox. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef IO_MUXER_H_ +#define IO_MUXER_H_ + +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +struct pollfd; +struct IoMuxer_Closure; + +struct IoMuxer { + struct pollfd* pfds; + struct IoMuxer_Closure* closures; + size_t alloc; + size_t size; +}; + +void IoMuxer_Create(struct IoMuxer* io_muxer); +int IoMuxer_OnRead(struct IoMuxer* io_muxer, int fd, + void (*read_callback)(void*), void* user); +int IoMuxer_OnWrite(struct IoMuxer* io_muxer, int fd, + void (*write_callback)(void*), void* user); +int IoMuxer_Iterate(struct IoMuxer* io_muxer); +void IoMuxer_Destroy(struct IoMuxer* io_muxer); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // IO_MUXER_H_ |