diff options
author | Mikhail Burakov <mburakov@mailbox.org> | 2022-07-26 12:30:57 +0200 |
---|---|---|
committer | Mikhail Burakov <mburakov@mailbox.org> | 2022-07-26 12:30:57 +0200 |
commit | 9bac0662283f73528a2118b5396d4ee4c64600e9 (patch) | |
tree | d019f3ddeef9ba430c63029d486448250369083d /io_muxer.c | |
parent | 5366104ae61e531fbaa7291ba44822b6b38b8b3d (diff) |
Add IoMuxer to toolbox
Diffstat (limited to 'io_muxer.c')
-rw-r--r-- | io_muxer.c | 101 |
1 files changed, 101 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); +} |