AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
sys_poll.c
Go to the documentation of this file.
1
10
11#include "syscalls.h"
12
15static struct file *fd_peek(int fd)
16{
17 return proc_fd_file(curproc, fd);
18}
19
20typedef unsigned long fd_mask;
21
22#define FD_SETSIZE 64
23#define NFDBITS (sizeof (fd_mask) * 8) /* the bits in an fd_mask */
24#define _howmany(x,y) (((x)+((y)-1))/(y))
25
26/* the C library's fd_set: one bit per descriptor */
30
33static int fd_ready(struct file *file, int write)
34{
35 int ret = write ? vfs_file_can_write(file, 1) : vfs_file_can_read(file, 1);
36 return ret != 0;
37}
38
41static int fd_watch(struct file *file, int write)
42{
44}
45
50{
51 uint64_t until = ns < 0 ? 0 : curthread->restarting ? curthread->restart_until :
52 arch_rtime_ns() + ns;
53
54 curthread->restart_until = until;
55 return until;
56}
57
68long sys_select(struct aquila_select_args *args)
69{
70 syscall_log(LOG_DEBUG, "select(args=%p)\n", args);
71
72 struct aquila_select_args a;
73
74 if (copyin(&a, args, sizeof(a))) {
75 return -EFAULT;
76 }
77
78 int nfds = a.nfds;
79 fd_set *readfds = a.readfds;
80 fd_set *writefds = a.writefds;
81 fd_set *exceptfds = a.exceptfds;
82 sigset_t *sigmask = a.sigmask;
83
84 if (nfds < 0 || nfds > FD_SETSIZE) {
85 return -EINVAL;
86 }
87
88 /* the kernel's copies of what was asked (the user's sets are
89 * overwritten with the result) */
90 fd_set want_read = {0}, want_write = {0}, out_read, out_write;
91 struct timeval timeout;
92 sigset_t mask;
93
94 if ((readfds && copyin(&want_read, readfds, sizeof(fd_set))) ||
95 (writefds && copyin(&want_write, writefds, sizeof(fd_set))) ||
96 (a.timeout && copyin(&timeout, a.timeout, sizeof(timeout))) ||
97 (sigmask && copyin(&mask, sigmask, sizeof(mask)))) {
98 return -EFAULT;
99 }
100
101 if (a.timeout && ((int64_t) timeout.tv_sec < 0 || timeout.tv_usec < 0 || timeout.tv_usec >= 1000000)) {
102 return -EINVAL;
103 }
104
105 /* pselect(): the signal mask while waiting; the old mask comes back
106 * when this returns, or goes in the handler's frame (as in
107 * sigsuspend()) */
108 if (sigmask) {
109 curthread->sig_oldmask = curproc->sigmask;
110 curthread->sig_oldmask_set = 1;
111 curproc->sigmask = mask & ~SIG_UNMASKABLE;
112 }
113
114 int64_t ns = a.timeout ? (int64_t) timeout.tv_sec * 1000000000 + timeout.tv_usec * 1000 : -1;
115 uint64_t until = poll_deadline(ns);
116 int count, timed_out = 0;
117
118#define FD_BIT(set, i) ((set).fds_bits[(i) / NFDBITS] & (1UL << ((i) % NFDBITS)))
119#define FD_ADD(set, i) ((set).fds_bits[(i) / NFDBITS] |= (1UL << ((i) % NFDBITS)))
120
121 for (;;) {
122 out_read = (fd_set) {0};
123 out_write = (fd_set) {0};
124 count = 0;
125
126 for (int i = 0; i < nfds; ++i) {
127 if (!FD_BIT(want_read, i) && !FD_BIT(want_write, i))
128 continue;
129
130 struct file *file = fd_peek(i);
131 int err = 0;
132
133 if (!file)
134 err = -EBADF;
135
136 if (!err && FD_BIT(want_read, i) && !(err = fd_watch(file, 0)) && fd_ready(file, 0)) {
137 FD_ADD(out_read, i);
138 ++count;
139 }
140
141 if (!err && FD_BIT(want_write, i) && !(err = fd_watch(file, 1)) && fd_ready(file, 1)) {
142 FD_ADD(out_write, i);
143 ++count;
144 }
145
146 if (err) {
148 return err;
149 }
150 }
151
152 if (count || ns == 0 || timed_out) {
154 break;
155 }
156
157 /* a wakeup of a queue that one of them waits on makes us look
158 * again; a signal ends the wait with EINTR (POSIX: it isn't
159 * restarted, except after a stop) */
160 timed_out = sched_wait(&curthread->poll_wait, until);
162
163 if (timed_out < 0) {
164 return -ERESTARTNOHAND;
165 }
166 }
167
168 if (sigmask) {
169 curproc->sigmask = curthread->sig_oldmask;
170 curthread->sig_oldmask_set = 0;
171 }
172
173#undef FD_BIT
174#undef FD_ADD
175
176 fd_set none = {0};
177
178 if ((readfds && copyout(readfds, &out_read, sizeof(fd_set))) ||
179 (writefds && copyout(writefds, &out_write, sizeof(fd_set))) ||
180 (exceptfds && copyout(exceptfds, &none, sizeof(fd_set)))) {
181 return -EFAULT;
182 }
183
184 return count;
185}
186
198long sys_poll(struct pollfd *fds, nfds_t nfds, int timeout_ms)
199{
200 syscall_log(LOG_DEBUG, "poll(fds=%p, nfds=%d, timeout=%d)\n", fds, nfds, timeout_ms);
201
202 if (nfds > FDS_COUNT * 2) {
203 return -EINVAL;
204 }
205
206 /* work on the kernel's copy, and copy the results out at the end */
207 size_t size = nfds * sizeof(struct pollfd);
208 struct pollfd *kfds = nfds ? kmalloc(size, &M_BUFFER, 0) : NULL;
209
210 if (nfds && !kfds) {
211 return -ENOMEM;
212 }
213
214 if (copyin(kfds, fds, size)) {
215 kfree(kfds);
216 return -EFAULT;
217 }
218
219 int64_t ns = timeout_ms < 0 ? -1 : (int64_t) timeout_ms * 1000000;
220 uint64_t until = poll_deadline(ns);
221 int count, timed_out = 0;
222
223 for (;;) {
224 int err = 0;
225 count = 0;
226
227 for (nfds_t i = 0; i < nfds; ++i) {
228 struct pollfd *p = &kfds[i];
229 struct file *file;
230
231 p->revents = 0;
232
233 /* a negative descriptor is skipped */
234 if (p->fd < 0)
235 continue;
236
237 if (!(file = fd_peek(p->fd))) {
238 p->revents = POLLNVAL;
239 } else {
240 if ((p->events & POLLIN) && !err && !(err = fd_watch(file, 0)) && fd_ready(file, 0))
241 p->revents |= POLLIN;
242
243 if ((p->events & POLLOUT) && !err && !(err = fd_watch(file, 1)) && fd_ready(file, 1))
244 p->revents |= POLLOUT;
245 }
246
247 count += !!p->revents;
248 }
249
250 if (err) {
252 count = err;
253 break;
254 }
255
256 if (count || ns == 0 || timed_out) {
258 break;
259 }
260
261 /* a wakeup of a queue that one of them waits on makes us look
262 * again; a signal ends the wait with EINTR (except after a stop) */
263 timed_out = sched_wait(&curthread->poll_wait, until);
265
266 if (timed_out < 0) {
267 count = -ERESTARTNOHAND;
268 break;
269 }
270 }
271
272 if (count >= 0 && copyout(fds, kfds, size))
273 count = -EFAULT;
274
275 kfree(kfds);
276 return count;
277}
struct waitq * vfs_file_wait_queue(struct file *file, int write)
Finds the wait queue that a reader (or a writer) of an open file sleeps on until it can go on,...
Definition fops.c:243
int vfs_file_can_read(struct file *file, size_t size)
Says whether a read of an open file would go on without waiting, for poll() and select().
Definition fops.c:262
int vfs_file_can_write(struct file *file, size_t size)
Says whether a write to an open file would go on without waiting, for poll(), select() and non-blocki...
Definition fops.c:295
#define FDS_COUNT
Definition config.h:46
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
Definition kvmem.c:123
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
#define LOG_DEBUG
Definition printk.h:19
struct file * proc_fd_file(struct proc *proc, int fd)
Finds the open file a descriptor refers to.
Definition proc.c:560
#define curproc
Definition sched.h:13
int sched_wait(struct waitq *waitq, uint64_t until)
Puts the current thread to sleep on a wait queue until it is woken up, a signal ends the sleep,...
Definition sched.c:187
#define curthread
Definition sched.h:12
#define ERESTARTNOHAND
Definition signal.h:82
#define SIG_UNMASKABLE
Definition signal.h:85
#define NULL
Definition stddef.h:27
signed long long int int64_t
Definition stddef.h:19
unsigned long long int uint64_t
Definition stddef.h:23
fd_mask fds_bits[_howmany(FD_SETSIZE, NFDBITS)]
Definition sys_poll.c:28
A file descriptor: the open file it refers to (fs/file.c, shared with the descriptors that dup() and ...
Definition proc.h:47
An open file (POSIX's "open file description", fs/file.c).
Definition vfs.h:157
suseconds_t tv_usec
Definition types.h:37
time_t tv_sec
Definition types.h:36
#define FD_BIT(set, i)
static int fd_ready(struct file *file, int write)
Returns whether file can be read (or written) without waiting.
Definition sys_poll.c:33
long sys_select(struct aquila_select_args *args)
Implements select() and pselect(): waits until a descriptor of the sets can be read or written,...
Definition sys_poll.c:68
static int fd_watch(struct file *file, int write)
Registers the wait queue that file's readers (or writers) sleep on, or NULL (any wakeup) if the file ...
Definition sys_poll.c:41
#define FD_SETSIZE
Definition sys_poll.c:22
long sys_poll(struct pollfd *fds, nfds_t nfds, int timeout_ms)
Implements poll(): waits until one of the descriptors can be read or written, or the timeout passes,...
Definition sys_poll.c:198
#define FD_ADD(set, i)
static uint64_t poll_deadline(int64_t ns)
Returns the deadline of a timeout of ns ns: 0 for none (ns < 0).
Definition sys_poll.c:49
#define _howmany(x, y)
Definition sys_poll.c:24
#define NFDBITS
Definition sys_poll.c:23
unsigned long fd_mask
Definition sys_poll.c:20
static struct file * fd_peek(int fd)
Returns the open file a descriptor refers to, without holding it (as fd_file() does): it is only used...
Definition sys_poll.c:15
uint64_t arch_rtime_ns(void)
Reads the monotonic clock, which starts at boot.
Definition timer.c:56
unsigned long sigset_t
Definition types.h:27
void poll_unregister(struct thread *thread)
Removes every registration of a thread, when it stops waiting (it was woken up, or it is going away).
Definition waitq.c:144
int poll_register(struct waitq *waitq)
Registers a wait queue that the current thread, in select() or poll(), waits for: a wakeup of that qu...
Definition waitq.c:112