#include "Log.h" #include "Pledge.h" #include "fs/VFS.h" #include "memory/MemoryManager.h" #include "sys/Syscall.h" #include "thread/Scheduler.h" #include Result sys_poll(Registers*, SyscallArgs args) { struct pollfd* fds = (struct pollfd*)args[0]; nfds_t nfds = (nfds_t)args[1]; int timeout = (int)args[2]; struct pollfd* kfds = (struct pollfd*)TRY(malloc_impl(nfds * sizeof(pollfd), false, false)); auto guard = make_scope_guard([kfds] { free_impl(kfds); }); if (!MemoryManager::copy_from_user(fds, kfds, nfds * sizeof(pollfd))) return err(EFAULT); auto* current = Scheduler::current(); TRY(check_pledge(current, Promise::p_stdio)); Vector> inodes; TRY(inodes.try_reserve(nfds)); for (nfds_t i = 0; i < nfds; i++) { int fd = kfds[i].fd; auto maybe_inode = current->resolve_fd(fd); if (maybe_inode.has_error()) { kwarnln("poll: fd %lu (%d) is not valid, storing POLLNVAL", i, fd); kfds[i].revents |= POLLNVAL; TRY(inodes.try_append({})); } else TRY(inodes.try_append(maybe_inode.release_value()->description->inode)); } bool infinite = timeout < 0; nfds_t fds_with_events; do { fds_with_events = 0; for (nfds_t i = 0; i < nfds; i++) { auto& inode = inodes[i]; if (!inode) continue; if (kfds[i].events & POLLIN && !inode->will_block_if_read()) { fds_with_events++; kfds[i].revents |= POLLIN; } } if (!fds_with_events && (timeout > 0 || infinite)) { kernel_sleep(10); timeout -= (10 - (int)current->sleep_ticks_left); if (current->interrupted) { guard.deactivate(); free_impl(kfds); return err(EINTR); } continue; } break; } while (1); MemoryManager::copy_to_user(fds, kfds, nfds * sizeof(pollfd)); return fds_with_events; }