/* * 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 . */ #include "io_muxer.h" #include #include #include #include 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); }