From 0eaa91d7fa2000fe1cc42acf750400dcd3c299c9 Mon Sep 17 00:00:00 2001 From: Timothy Werquin Date: Mon, 16 Oct 2023 19:54:00 +0200 Subject: [PATCH] rMlib: Use unistdpp for FD / socket management --- apps/rocket/main.cpp | 7 +- apps/tilem/CMakeLists.txt | 5 +- apps/yaft/main.cpp | 3 +- libs/rMlib/Device.cpp | 57 +++---------- libs/rMlib/EmulatedInput.cpp | 61 +++++--------- libs/rMlib/Input.cpp | 107 +++++++++++-------------- libs/rMlib/include/Device.h | 3 - libs/rMlib/include/Error.h | 4 +- libs/rMlib/include/Input.h | 55 +++++++------ libs/rMlib/include/UI/AppContext.h | 31 +++---- libs/unistdpp/include/unistdpp/error.h | 1 + libs/unistdpp/include/unistdpp/poll.h | 4 +- tools/rm2fb-emu/rm2fb-emu.cpp | 3 +- 13 files changed, 141 insertions(+), 200 deletions(-) diff --git a/apps/rocket/main.cpp b/apps/rocket/main.cpp index d696e3f..d279315 100755 --- a/apps/rocket/main.cpp +++ b/apps/rocket/main.cpp @@ -7,6 +7,8 @@ #include #include +#include + using namespace rmlib; namespace { @@ -336,9 +338,10 @@ class LauncherState : public StateBase { if (res == 0) { // Get the reason - auto irq = rmlib::device::readFile("/sys/power/pm_wakeup_irq"); + auto irq = unistdpp::readFile("/sys/power/pm_wakeup_irq"); if (!irq.has_value()) { - std::cout << "Error getting reason: " << irq.error().msg << std::endl; + std::cout << "Error getting reason: " << unistdpp::toString(irq.error()) + << std::endl; // If there is no irq it must be the user which pressed the button: return true; diff --git a/apps/tilem/CMakeLists.txt b/apps/tilem/CMakeLists.txt index fb348d5..5bc1953 100755 --- a/apps/tilem/CMakeLists.txt +++ b/apps/tilem/CMakeLists.txt @@ -3,14 +3,11 @@ project(tilem) add_subdirectory(emu) add_executable(${PROJECT_NAME} - main.cpp - ${WABBIT_SRC}) + main.cpp) target_compile_definitions(${PROJECT_NAME} PRIVATE _LINUX) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) -target_include_directories(${PROJECT_NAME} PRIVATE ${WABBIT_INCLUDE}) - target_link_libraries(${PROJECT_NAME} PRIVATE tiemu diff --git a/apps/yaft/main.cpp b/apps/yaft/main.cpp index 4ed325c..74721d5 100755 --- a/apps/yaft/main.cpp +++ b/apps/yaft/main.cpp @@ -188,7 +188,8 @@ fork_and_exec(int* master, return true; } -constexpr auto select_timeout = std::chrono::microseconds(SELECT_TIMEOUT); +constexpr auto select_timeout = + std::chrono::milliseconds(SELECT_TIMEOUT / 1000); int main(int argc, const char* argv[]) { diff --git a/libs/rMlib/Device.cpp b/libs/rMlib/Device.cpp index d15bc68..ff9aa91 100644 --- a/libs/rMlib/Device.cpp +++ b/libs/rMlib/Device.cpp @@ -1,5 +1,7 @@ #include "Device.h" +#include + #include #include #include @@ -51,30 +53,6 @@ const InputPaths rm2_paths = { }; } // namespace -ErrorOr -readFile(std::string_view path) { - assert(path[path.length()] == '\0' && "path must be null terminated"); - FILE* f = fopen(&path[0], "rb"); - if (f == nullptr) { - return Error::errn(); - } - - fseek(f, 0, SEEK_END); - const unsigned long size = ftell(f); - fseek(f, 0, SEEK_SET); - - std::string result(size + 1, '\0'); - auto read = fread(result.data(), size, 1, f); - if (read != size && !(read == 0 && feof(f))) { - fclose(f); - return tl::unexpected( - Error{ "Only read: " + std::to_string(read) + " bytes?" }); - } - - fclose(f); - return result; -} - ErrorOr getDeviceType() { #ifdef EMULATE @@ -82,16 +60,7 @@ getDeviceType() { #else static const auto result = []() -> ErrorOr { constexpr auto path = "/sys/devices/soc0/machine"; - std::ifstream ifs(path); - if (!ifs.is_open()) { - return Error::make("Couldn't open device path"); - } - - std::string name; - name.reserve(16); - name.assign(std::istreambuf_iterator(ifs), - std::istreambuf_iterator()); - + auto name = TRY(unistdpp::readFile(path)); if (name.find("2.0") == std::string::npos) { return DeviceType::reMarkable1; } @@ -151,22 +120,16 @@ listDirectory(std::string_view path, bool onlyFiles) { bool IsPogoConnected() { - int fd = open( #ifndef EMULATE - "/sys/pogo/status/pogo_connected" + constexpr auto path = "/sys/pogo/status/pogo_connected"; #else - "/tmp/pogo" + constexpr auto path = "/tmp/pogo"; #endif - , - O_RDWR); - if (fd == -1) { - return false; - } - - char buf = '\0'; - read(fd, &buf, 1); - close(fd); - return buf == '1'; + return unistdpp::open(path, O_RDWR) + .and_then([](unistdpp::FD fd) { + return fd.readAll().transform([&](char buf) { return buf == '1'; }); + }) + .value_or(false); } } // namespace rmlib::device diff --git a/libs/rMlib/EmulatedInput.cpp b/libs/rMlib/EmulatedInput.cpp index 4674ac8..a8869cf 100644 --- a/libs/rMlib/EmulatedInput.cpp +++ b/libs/rMlib/EmulatedInput.cpp @@ -1,5 +1,7 @@ #include "Input.h" +#include + #include #include #include @@ -21,17 +23,18 @@ InputDeviceBase::~InputDeviceBase() {} namespace { struct FakeInputDevice : public InputDeviceBase { - int pipes[2]; + unistdpp::Pipe pipes; unsigned int sdlUserEvent; - FakeInputDevice() : InputDeviceBase(0, nullptr, "test") { + FakeInputDevice() : InputDeviceBase(unistdpp::FD(), nullptr, "test") { sdlUserEvent = SDL_RegisterEvents(1); - int res = pipe(pipes); - if (res != 0) { - perror("Error creating input notify pipes"); - } - std::cout << "Got pipes: " << pipes[0] << ", " << pipes[1] << "\n"; + pipes = unistdpp::pipe() + .or_else([](auto err) { + std::cerr << unistdpp::toString(err) << "\n"; + std::exit(EXIT_FAILURE); + }) + .value(); } void flood() final {} @@ -59,43 +62,22 @@ InputManager::openAll(bool monitor) { } ErrorOr> -InputManager::waitForInput(fd_set& fdSet, - int maxFd, - std::optional timeout) { +InputManager::waitForInput(std::vector& extraFds, + std::optional timeout) { static bool down = false; FakeInputDevice& dev = static_cast(getBaseDevices()->key); - std::thread selectThread([maxFd, - readPipe = dev.pipes[0], - &fdSet, + std::thread selectThread([&readPipe = dev.pipes.readPipe, + &extraFds, &timeout, userEv = dev.sdlUserEvent]() { - if (maxFd == 0 && !FD_ISSET(0, &fdSet)) { - return; - } - // Also listen to the notify pipe - int maxFd2 = std::max(maxFd, readPipe); - FD_SET(readPipe, &fdSet); - - auto tv = timeval{ 0, 0 }; - if (timeout.has_value()) { - constexpr auto second_in_usec = - std::chrono::microseconds(std::chrono::seconds(1)).count(); - tv.tv_sec = - std::chrono::duration_cast(*timeout).count(); - tv.tv_usec = timeout->count() - (tv.tv_sec * second_in_usec); - } - - auto ret = select(maxFd2 + 1, - &fdSet, - nullptr, - nullptr, - timeout.has_value() ? &tv : nullptr); + extraFds.push_back(unistdpp::waitFor(readPipe, unistdpp::Wait::READ)); - if (ret < 0) { - perror("Select on input failed"); + auto ret = unistdpp::poll(extraFds, timeout); + if (!ret) { + std::cerr << "Poll failure: " << unistdpp::toString(ret.error()) << "\n"; return; } @@ -104,9 +86,8 @@ InputManager::waitForInput(fd_set& fdSet, } // Read the single notify byte. - if (FD_ISSET(readPipe, &fdSet)) { - char buf; - read(readPipe, &buf, 1); + if (unistdpp::canRead(extraFds.back())) { + (void)readPipe.readAll(); return; } @@ -129,7 +110,7 @@ InputManager::waitForInput(fd_set& fdSet, } if (event.type != dev.sdlUserEvent) { - write(dev.pipes[1], "1", 1); + (void)dev.pipes.writePipe.writeAll('1'); } selectThread.join(); diff --git a/libs/rMlib/Input.cpp b/libs/rMlib/Input.cpp index bdda3f7..4223ceb 100644 --- a/libs/rMlib/Input.cpp +++ b/libs/rMlib/Input.cpp @@ -2,6 +2,9 @@ #include "Device.h" +#include +#include + #include #include @@ -82,14 +85,18 @@ struct InputDevice : public InputDeviceBase { }; struct TouchDevice : public InputDevice { - TouchDevice(int fd, libevdev* evdev, std::string path, Transform transform) - : InputDevice(fd, evdev, std::move(path)), transform(transform) {} + TouchDevice(unistdpp::FD fd, + libevdev* evdev, + std::string path, + Transform transform) + : InputDevice(std::move(fd), evdev, std::move(path)) + , transform(transform) {} ErrorOr> handleEvent(input_event); TouchEvent& getSlot() { return slots.at(slot); } void flood() final { auto* buf = getTouchFlood(); - write(fd, buf, touch_flood_size * sizeof(input_event)); + (void)fd.writeAll(buf, touch_flood_size * sizeof(input_event)); } Transform transform; @@ -99,13 +106,17 @@ struct TouchDevice : public InputDevice { }; struct PenDevice : public InputDevice { - PenDevice(int fd, libevdev* evdev, std::string path, Transform transform) - : InputDevice(fd, evdev, std::move(path)), transform(transform) {} + PenDevice(unistdpp::FD fd, + libevdev* evdev, + std::string path, + Transform transform) + : InputDevice(std::move(fd), evdev, std::move(path)) + , transform(transform) {} ErrorOr> handleEvent(input_event); void flood() final { auto* buf = getTouchFlood(); - write(fd, buf, touch_flood_size * sizeof(input_event)); + (void)fd.writeAll(buf, touch_flood_size * sizeof(input_event)); } Transform transform; @@ -113,14 +124,14 @@ struct PenDevice : public InputDevice { }; struct KeyDevice : public InputDevice { - KeyDevice(int fd, libevdev* evdev, std::string path) - : InputDevice(fd, evdev, std::move(path)) {} + KeyDevice(unistdpp::FD fd, libevdev* evdev, std::string path) + : InputDevice(std::move(fd), evdev, std::move(path)) {} ErrorOr> handleEvent(input_event); void flood() final { // TODO: this probably doesn't work auto* buf = getTouchFlood(); - write(fd, buf, touch_flood_size * sizeof(input_event)); + (void)fd.writeAll(buf, touch_flood_size * sizeof(input_event)); } std::vector keyEvents; @@ -233,7 +244,7 @@ KeyDevice::handleEvent(input_event event) { } std::unique_ptr -makeDevice(int fd, +makeDevice(unistdpp::FD fd, libevdev* evdev, std::string path, Transform transform = {}) { @@ -242,20 +253,21 @@ makeDevice(int fd, if (libevdev_has_event_code(evdev, EV_ABS, ABS_MT_SLOT)) { std::cout << "Got touch\n"; return std::make_unique( - fd, evdev, std::move(path), transform); + std::move(fd), evdev, std::move(path), transform); } // pen/single touch screen -> ev_abs if (libevdev_has_event_code(evdev, EV_ABS, ABS_X)) { std::cout << "Got pen\n"; - return std::make_unique(fd, evdev, std::move(path), transform); + return std::make_unique( + std::move(fd), evdev, std::move(path), transform); } } std::cout << "Got key\n"; // finally keyboard -> ev_key // TODO: support mouse? - return std::make_unique(fd, evdev, std::move(path)); + return std::make_unique(std::move(fd), evdev, std::move(path)); } void @@ -291,9 +303,6 @@ InputDeviceBase::~InputDeviceBase() { if (evdev != nullptr) { libevdev_free(evdev); } - if (fd != -1) { - close(fd); - } } InputManager::InputManager() {} @@ -313,19 +322,16 @@ InputManager::open(std::string_view input, Transform inputTransform) { return &*it->second; } - int fd = ::open(input.data(), O_RDWR | O_NONBLOCK); - if (fd < 0) { - return Error::make("Couldn't open '" + std::string(input) + "'"); - } + auto fd = TRY(unistdpp::open(input.data(), O_RDWR | O_NONBLOCK)); libevdev* dev = nullptr; - if (libevdev_new_from_fd(fd, &dev) < 0) { - close(fd); + if (libevdev_new_from_fd(fd.fd, &dev) < 0) { return Error::make("Error initializing evdev for '" + std::string(input) + "'"); } - auto device = makeDevice(fd, dev, std::string(input), inputTransform); + auto device = + makeDevice(std::move(fd), dev, std::string(input), inputTransform); auto* devicePtr = device.get(); devices.emplace(devicePtr->path, std::move(device)); return devicePtr; @@ -367,12 +373,12 @@ InputManager::openAll(bool monitor) { udevMonitor = udev_monitor_new_from_netlink(udevHandle, "udev"); udev_monitor_filter_add_match_subsystem_devtype(udevMonitor, "input", NULL); udev_monitor_enable_receiving(udevMonitor); - udevMonitorFd = udev_monitor_get_fd(udevMonitor); + udevMonitorFd = unistdpp::FD(udev_monitor_get_fd(udevMonitor)); } else { udev_unref(udevHandle); this->udevHandle = nullptr; - this->udevMonitorFd = -1; + this->udevMonitorFd = unistdpp::FD(); } auto type = TRY(device::getDeviceType()); @@ -387,42 +393,29 @@ InputManager::openAll(bool monitor) { } ErrorOr> -InputManager::waitForInput(fd_set& fdSet, - int maxFd, - std::optional timeout) { +InputManager::waitForInput(std::vector& extraFds, + std::optional timeout) { + const auto inputFdsSize = extraFds.size(); + + std::vector deviceOrder; for (auto& [_, device] : devices) { (void)_; - FD_SET(device->fd, &fdSet); // NOLINT - maxFd = std::max(device->fd, maxFd); + deviceOrder.emplace_back(device.get()); + extraFds.emplace_back(unistdpp::waitFor(device->fd, unistdpp::Wait::READ)); } - if (udevMonitorFd >= 0) { - FD_SET(udevMonitorFd, &fdSet); - maxFd = std::max(maxFd, udevMonitorFd); - } - - auto tv = timeval{ 0, 0 }; - if (timeout.has_value()) { - constexpr auto second_in_usec = - std::chrono::microseconds(std::chrono::seconds(1)).count(); - tv.tv_sec = - std::chrono::duration_cast(*timeout).count(); - tv.tv_usec = timeout->count() - (tv.tv_sec * second_in_usec); - } - - auto ret = select( - maxFd + 1, &fdSet, nullptr, nullptr, !timeout.has_value() ? nullptr : &tv); - if (ret < 0) { - perror("Select on input failed"); - return Error::make("Select failed"); + if (udevMonitorFd.isValid()) { + extraFds.emplace_back( + unistdpp::waitFor(udevMonitorFd, unistdpp::Wait::READ)); } + auto ret = TRY(unistdpp::poll(extraFds, timeout)); if (ret == 0) { // timeout return std::vector{}; } - if (udevMonitorFd >= 0 && FD_ISSET(udevMonitorFd, &fdSet)) { + if (udevMonitorFd.isValid() && unistdpp::canRead(extraFds.back())) { udev_device* dev = udev_monitor_receive_device(udevMonitor); if (dev) { handeDevice(*this, *dev); @@ -432,17 +425,15 @@ InputManager::waitForInput(fd_set& fdSet, // Return the first device we see. std::vector result; - for (auto& [_, device] : devices) { - (void)_; - if (!FD_ISSET(device->fd, &fdSet)) { // NOLINT - continue; - } - - if (auto err = device->readEvents(result); !err.has_value()) { - return tl::unexpected(err.error()); + for (std::size_t i = 0; i < deviceOrder.size(); i++) { + auto& device = *deviceOrder[i]; + if (unistdpp::canRead(extraFds[i + inputFdsSize])) { + TRY(device.readEvents(result)); } } + extraFds.resize(inputFdsSize); + return result; } } // namespace rmlib::input diff --git a/libs/rMlib/include/Device.h b/libs/rMlib/include/Device.h index 35f0aab..ccb65e7 100644 --- a/libs/rMlib/include/Device.h +++ b/libs/rMlib/include/Device.h @@ -12,9 +12,6 @@ namespace rmlib::device { enum class DeviceType { reMarkable1, reMarkable2 }; -ErrorOr -readFile(std::string_view path); - /// \returns The device type on which we're currently running or nullopt if /// detection fails. ErrorOr diff --git a/libs/rMlib/include/Error.h b/libs/rMlib/include/Error.h index 35e97f5..ea138a8 100644 --- a/libs/rMlib/include/Error.h +++ b/libs/rMlib/include/Error.h @@ -17,8 +17,8 @@ struct Error { return tl::unexpected(Error{ std::move(msg) }); } - static Error fromErrno() { return Error{ strerror(errno) }; } - static tl::unexpected errn() { return tl::unexpected(fromErrno()); } + Error(std::errc err) : msg(std::make_error_code(err).message()) {} + Error(std::string msg) : msg(std::move(msg)) {} }; template diff --git a/libs/rMlib/include/Input.h b/libs/rMlib/include/Input.h index 6ddbd7d..618ea10 100755 --- a/libs/rMlib/include/Input.h +++ b/libs/rMlib/include/Input.h @@ -13,6 +13,9 @@ #include #include +#include +#include + struct libevdev; struct udev; struct udev_monitor; @@ -81,7 +84,7 @@ using Gesture = std::variant; using Event = std::variant; struct InputDeviceBase { - int fd; + unistdpp::FD fd; libevdev* evdev; std::string path; @@ -94,8 +97,8 @@ struct InputDeviceBase { virtual OptError<> readEvents(std::vector& out) = 0; protected: - InputDeviceBase(int fd, libevdev* evdev, std::string path) - : fd(fd), evdev(evdev), path(std::move(path)) {} + InputDeviceBase(unistdpp::FD fd, libevdev* evdev, std::string path) + : fd(std::move(fd)), evdev(evdev), path(std::move(path)) {} }; struct BaseDevices { @@ -124,12 +127,11 @@ struct InputManager { , baseDevices(other.baseDevices) , udevHandle(other.udevHandle) , udevMonitor(other.udevMonitor) - , udevMonitorFd(other.udevMonitorFd) { + , udevMonitorFd(std::move(other.udevMonitorFd)) { other.devices.clear(); other.baseDevices = std::nullopt; other.udevHandle = nullptr; other.udevMonitor = nullptr; - other.udevMonitorFd = -1; } InputManager& operator=(InputManager&& other) { @@ -137,7 +139,7 @@ struct InputManager { baseDevices = std::nullopt; udevHandle = nullptr; udevMonitor = nullptr; - udevMonitorFd = -1; + udevMonitorFd.close(); std::swap(other, *this); return *this; @@ -147,39 +149,42 @@ struct InputManager { InputManager& operator=(const InputManager&) = delete; ErrorOr> waitForInput( - fd_set& fdSet, - int maxFd, - std::optional timeout = std::nullopt); + std::vector& extraFds, + std::optional timeout = std::nullopt); template - auto waitForInput(std::optional timeout, - ExtraFds... extraFds) + auto waitForInput(std::optional timeout, + const ExtraFds&... extraFds) -> ErrorOr, std::pair, std::array>>> { - static_assert((std::is_same_v && ...)); - fd_set fds; - FD_ZERO(&fds); + static_assert(((std::is_same_v || + std::is_same_v)&&...)); + + std::vector fds; + if constexpr (sizeof...(ExtraFds) > 0) { - constexpr auto fd_set = [](auto fd, auto& fds) { FD_SET(fd, &fds); }; + fds.reserve(sizeof...(ExtraFds)); + constexpr auto fd_set = [](const auto& fd, auto& fds) { + if constexpr (std::is_same_v) { + fds.emplace_back(pollfd{ .fd = fd, .events = POLLIN, .revents = 0 }); + } else { + fds.emplace_back(unistdpp::waitFor(fd, unistdpp::Wait::READ)); + } + }; (fd_set(extraFds, fds), ...); } - auto maxFd = std::max({ 0, extraFds... }); - - auto res = TRY(waitForInput(fds, maxFd, timeout)); + auto res = TRY(waitForInput(fds, timeout)); if constexpr (sizeof...(ExtraFds) == 0) { return res; } else { std::array extraResult; - int i = 0; - - constexpr auto fd_isset = [](auto fd, auto& fds) { - return FD_ISSET(fd, &fds); - }; - ((extraResult[i++] = fd_isset(extraFds, fds)), ...); + for (std::size_t i = 0; i < sizeof...(extraFds); i++) { + extraResult[i] = unistdpp::canRead(fds[i]); + } return std::pair{ res, extraResult }; } @@ -195,7 +200,7 @@ struct InputManager { std::optional baseDevices; udev* udevHandle = nullptr; udev_monitor* udevMonitor = nullptr; - int udevMonitorFd = -1; + unistdpp::FD udevMonitorFd; }; struct GestureController { diff --git a/libs/rMlib/include/UI/AppContext.h b/libs/rMlib/include/UI/AppContext.h index 7e58bb6..1b1ff73 100644 --- a/libs/rMlib/include/UI/AppContext.h +++ b/libs/rMlib/include/UI/AppContext.h @@ -83,34 +83,35 @@ class AppContext { ErrorOr> waitForInput( std::optional durantion) { + const auto milliDuration = + [durantion]() -> std::optional { + if (!durantion.has_value()) { + return {}; + } + return std::chrono::duration_cast(*durantion); + }(); + std::size_t startDevices = inputManager.devices.size(); std::vector result; if (!extraFds.empty()) { - int maxFd = std::max_element(extraFds.begin(), - extraFds.end(), - [](const auto& a, const auto& b) { - return a.first < b.first; - }) - ->first; - - fd_set set; - FD_ZERO(&set); + std::vector pollFds; for (const auto& [fd, _] : extraFds) { - FD_SET(fd, &set); + pollFds.emplace_back( + pollfd{ .fd = fd, .events = POLLIN, .revents = 0 }); } - auto evs = TRY(inputManager.waitForInput(set, maxFd, durantion)); + auto evs = TRY(inputManager.waitForInput(pollFds, milliDuration)); - for (const auto& [fd, cb] : extraFds) { - if (FD_ISSET(fd, &set)) { - cb(); + for (const auto& poll : pollFds) { + if (unistdpp::canRead(poll)) { + extraFds[poll.fd](); } } result = std::move(evs); } else { - auto evs = TRY(inputManager.waitForInput(durantion)); + auto evs = TRY(inputManager.waitForInput(milliDuration)); result = std::move(evs); } diff --git a/libs/unistdpp/include/unistdpp/error.h b/libs/unistdpp/include/unistdpp/error.h index 850a23e..68bba2b 100644 --- a/libs/unistdpp/include/unistdpp/error.h +++ b/libs/unistdpp/include/unistdpp/error.h @@ -11,6 +11,7 @@ template constexpr auto getValue(tl::expected v) { if constexpr (std::is_same_v) { + (void)v; // to suppress unused variable warnings return; } else { return std::move(*v); diff --git a/libs/unistdpp/include/unistdpp/poll.h b/libs/unistdpp/include/unistdpp/poll.h index e8848c1..726073f 100644 --- a/libs/unistdpp/include/unistdpp/poll.h +++ b/libs/unistdpp/include/unistdpp/poll.h @@ -18,7 +18,9 @@ enum class Wait { inline pollfd waitFor(const FD& fd, Wait wait) { - return pollfd{ .fd = fd.fd, .events = static_cast(wait) }; + return pollfd{ .fd = fd.fd, + .events = static_cast(wait), + .revents = 0 }; } inline bool diff --git a/tools/rm2fb-emu/rm2fb-emu.cpp b/tools/rm2fb-emu/rm2fb-emu.cpp index 32905cf..995b8b0 100644 --- a/tools/rm2fb-emu/rm2fb-emu.cpp +++ b/tools/rm2fb-emu/rm2fb-emu.cpp @@ -60,8 +60,7 @@ main(int argc, char* argv[]) { fb->clear(); while (running) { - // TODO: use poll - auto fdsOrErr = input.waitForInput(std::nullopt, sock->fd); + auto fdsOrErr = input.waitForInput(std::nullopt, *sock); if (!fdsOrErr.has_value()) { std::cerr << "Error input: " << fdsOrErr.error().msg; break;