/* * 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 #include struct IoMuxerTask { void (*fun)(void*); void* user; }; static bool AppendRecord(struct IoMuxer* io_muxer) { if (io_muxer->size < io_muxer->alloc) return true; size_t alloc = io_muxer->alloc + 1; struct pollfd* pfds = realloc(io_muxer->pfds, alloc * sizeof(struct pollfd)); if (!pfds) return false; io_muxer->pfds = pfds; struct IoMuxerTask* tasks = realloc(io_muxer->tasks, alloc * sizeof(struct IoMuxerTask)); if (!tasks) return false; io_muxer->tasks = tasks; io_muxer->alloc = alloc; return true; } 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 IoMuxerTask task = io_muxer->tasks[forward]; io_muxer->tasks[forward] = io_muxer->tasks[reverse]; io_muxer->tasks[reverse] = task; } } void IoMuxerCreate(struct IoMuxer* io_muxer) { memset(io_muxer, 0, sizeof(struct IoMuxer)); } bool IoMuxerOnRead(struct IoMuxer* io_muxer, int fd, void (*fun)(void*), void* user) { if (!AppendRecord(io_muxer)) return false; struct pollfd pfd = {.fd = fd, .events = POLLIN}; struct IoMuxerTask task = {.fun = fun, .user = user}; io_muxer->pfds[io_muxer->size] = pfd; io_muxer->tasks[io_muxer->size] = task; io_muxer->size++; return true; } bool IoMuxerOnWrite(struct IoMuxer* io_muxer, int fd, void (*fun)(void*), void* user) { if (!AppendRecord(io_muxer)) return false; struct pollfd pfd = {.fd = fd, .events = POLLOUT}; struct IoMuxerTask task = {.fun = fun, .user = user}; io_muxer->pfds[io_muxer->size] = pfd; io_muxer->tasks[io_muxer->size] = task; io_muxer->size++; return true; } enum IoMuxerResult IoMuxerIterate(struct IoMuxer* io_muxer, int timeout) { CompressRecords(io_muxer); int result = poll(io_muxer->pfds, io_muxer->size, timeout); switch (result) { case -1: return kIoMuxerResultError; case 0: return kIoMuxerResultTimeout; default: break; } for (size_t i = 0; i < io_muxer->size; i++) { if (io_muxer->pfds[i].revents) io_muxer->tasks[i].fun(io_muxer->tasks[i].user); } return kIoMuxerResultSuccess; } void IoMuxerDestroy(struct IoMuxer* io_muxer) { free(io_muxer->pfds); free(io_muxer->tasks); }