diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 601e671a..9171dae9 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -42,6 +42,7 @@ set(SOURCES src/sys/resource.cpp src/sys/signal.cpp src/sys/socket.cpp + src/sys/poll.cpp src/fs/VFS.cpp src/fs/Pipe.cpp src/fs/Mount.cpp diff --git a/kernel/src/sys/poll.cpp b/kernel/src/sys/poll.cpp new file mode 100644 index 00000000..96a77b75 --- /dev/null +++ b/kernel/src/sys/poll.cpp @@ -0,0 +1,70 @@ +#include "fs/VFS.h" +#include "memory/MemoryManager.h" +#include "sys/Syscall.h" +#include "thread/Scheduler.h" +#include + +Result sys_poll(Registers* regs, 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))); + auto guard = make_scope_guard([kfds] { free_impl(kfds); }); + + if (!MemoryManager::copy_from_user(fds, kfds, nfds * sizeof(pollfd))) return err(EFAULT); + + Vector> inodes; + auto* current = Scheduler::current(); + + 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()) + { + kfds[i].revents |= POLLNVAL; + TRY(inodes.try_append({})); + } + else + TRY(inodes.try_append(maybe_inode.release_value()->description->inode)); + } + + bool infinite = timeout < 0; + int 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 -= (int)current->sleep_ticks_left; + if (current->interrupted) + { + guard.deactivate(); + free_impl(kfds); + if (current->will_invoke_signal_handler()) return err(EINTR); + current->process_pending_signals(regs); + return err(EINTR); + } + continue; + } + } while (false); + + MemoryManager::copy_to_user(fds, kfds, nfds * sizeof(pollfd)); + + return fds_with_events; +} diff --git a/libc/include/bits/fixed-size-types.h b/libc/include/bits/fixed-size-types.h index d38de035..a078371b 100644 --- a/libc/include/bits/fixed-size-types.h +++ b/libc/include/bits/fixed-size-types.h @@ -3,7 +3,8 @@ #ifndef _BITS_FIXED_SIZE_TYPES_H #define _BITS_FIXED_SIZE_TYPES_H -#if !defined(_SYS_TYPES_H) && !defined(_BITS_SETJMP_TYPES_H) && !defined(_BITS_MAKEDEV_H) && !defined(_BITS_TERMIOS_H) +#if !defined(_SYS_TYPES_H) && !defined(_BITS_SETJMP_TYPES_H) && !defined(_BITS_MAKEDEV_H) && \ + !defined(_BITS_TERMIOS_H) && !defined(_BITS_POLL_H) #error "Never include bits/fixed-size-types.h, use the standard header instead." #endif diff --git a/libc/include/bits/poll.h b/libc/include/bits/poll.h new file mode 100644 index 00000000..83f46a77 --- /dev/null +++ b/libc/include/bits/poll.h @@ -0,0 +1,21 @@ +/* bits/poll.h: The pollfd data structure. */ + +#ifndef _BITS_POLL_H +#define _BITS_POLL_H + +#include + +#define POLLIN 0 +#define POLLERR 1 +#define POLLNVAL 2 + +typedef __u64_t nfds_t; + +struct pollfd +{ + int fd; + short events; + short revents; +}; + +#endif diff --git a/libluna/include/luna/Syscall.h b/libluna/include/luna/Syscall.h index b663a02d..57baf9ae 100644 --- a/libluna/include/luna/Syscall.h +++ b/libluna/include/luna/Syscall.h @@ -7,7 +7,7 @@ _e(fstatat) _e(chdir) _e(getcwd) _e(unlinkat) _e(uname) _e(sethostname) _e(dup2) _e(pipe) _e(mount) \ _e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask) _e(linkat) _e(faccessat) \ _e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \ - _e(getpgid) _e(socket) _e(bind) _e(connect) _e(listen) _e(accept) + _e(getpgid) _e(socket) _e(bind) _e(connect) _e(listen) _e(accept) _e(poll) enum Syscalls {