x86: Don't enter the monitor for invalid opcode
[akaros.git] / user / iplib / select.c
1 /* Copyright (c) 2016 Google Inc.
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * select()
6  *
7  * Our select() is super spurious and will only work with apps that use
8  * non-blocking I/O.
9  *
10  * Under the hood, our select() is implemented with epoll (and under that, FD
11  * taps).  Those can only detect edges (e.g. a socket becomes readable).
12  *
13  * The problem is that we want to detect a level status (e.g. socket is
14  * readable) with an edge event (e.g. socket *becomes* readable).  To do this,
15  * when someone initially selects, the FD gets tracked with epoll and we
16  * immediately return saying the FD is ready for whatever they asked for.  This
17  * is usually not true, and the application will need to poll all of its FDs
18  * once after the initial select() call.  Subsequent selects() will still be
19  * tracking the FD in the epoll set.  If any edge events that come after the
20  * poll (which eventually returns EAGAIN) will be caught by epoll, and a
21  * subsequent select will wake up (or never block in the first place) due to the
22  * reception of that edge event.
23  *
24  * We maintain one FD set per program.  It tracks *any* FD being tracked by
25  * *any* select call.  Regardless of whether the user asked for
26  * read/write/except, the FD gets watched for anything until it closes.  This
27  * will result in spurious wakeups.
28  *
29  * One issue with the global FD set is that one thread may consume the epoll
30  * events intended for another thread (or even for itself at another call
31  * site!).  To get around this, only one thread is the actual epoller, and the
32  * others block on a mutex.  An alternative is to use a per-thread FD set, using
33  * TLS, but not every 2LS uses TLS, and performance is not a concern for code
34  * using select().
35  *
36  * Notes:
37  * - pselect might be racy
38  * - if the user has no read/write/except sets, we won't wait.  some users of
39  *   select use it as a timer only.  if that comes up, we can expand this.
40  * - if you epoll or FD tap an FD, then try to use select on it, you'll get an
41  *   error (only one tap per FD).  select() only knows about the FDs in its set.
42  * - if you select() on a readfd that is a disk file, it'll always say it is
43  *   available for I/O.
44  */
45
46 #include <sys/select.h>
47 #include <sys/stat.h>
48 #include <sys/time.h>
49 #include <sys/types.h>
50 #include <unistd.h>
51
52 #include <errno.h>
53 #include <malloc.h>
54 #include <parlib/arch/arch.h>
55 #include <parlib/uthread.h>
56 #include <parlib/parlib.h>
57 #include <ros/common.h>
58 #include <ros/fs.h>
59 #include <signal.h>
60 #include <stdlib.h>
61 #include <sys/close_cb.h>
62 #include <sys/epoll.h>
63 #include <sys/fork_cb.h>
64
65 static int epoll_fd;
66 static fd_set all_fds;
67 static uth_mutex_t *fdset_mtx;
68 static uintptr_t unique_caller;
69 static uth_mutex_t *sleep_mtx;
70
71 static bool fd_is_set(unsigned int fd, fd_set *set)
72 {
73         if (fd > FD_SETSIZE)
74                 return FALSE;
75         if (!set)
76                 return FALSE;
77         return FD_ISSET(fd, set);
78 }
79
80 static void select_fd_closed(int fd)
81 {
82         /* Slightly racy, but anything concurrently added will be closed later, and
83          * after it is_set. */
84         if (!fd_is_set(fd, &all_fds))
85                 return;
86         /* We just need to stop tracking FD.  We do not need to remove it from the
87          * epoll set, since that will happen automatically on close(). */
88         uth_mutex_lock(fdset_mtx);
89         FD_CLR(fd, &all_fds);
90         uth_mutex_unlock(fdset_mtx);
91 }
92
93 static void select_forked(void)
94 {
95         struct epoll_event ep_ev;
96
97         uth_mutex_lock(fdset_mtx);
98         for (int i = 0; i < FD_SETSIZE; i++) {
99                 if (fd_is_set(i, &all_fds)) {
100                         ep_ev.events = EPOLLET | EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLERR;
101                         ep_ev.data.fd = i;
102                         /* Discard error.  The underlying tap is gone, and the epoll ctlr
103                          * might also have been emptied.  We just want to make sure there is
104                          * no epoll/tap so that a future CTL_ADD doesn't fail. */
105                         epoll_ctl(epoll_fd, EPOLL_CTL_DEL, i, &ep_ev);
106                         FD_CLR(i, &all_fds);
107                 }
108         }
109         uth_mutex_unlock(fdset_mtx);
110 }
111
112 static void select_init(void *arg)
113 {
114         static struct close_cb select_close_cb = {.func = select_fd_closed};
115         static struct fork_cb select_fork_cb = {.func = select_forked};
116
117         register_close_cb(&select_close_cb);
118         epoll_fd = epoll_create(FD_SETSIZE);
119         if (epoll_fd < 0) {
120                 perror("select failed epoll_create");
121                 exit(-1);
122         }
123         fdset_mtx = uth_mutex_alloc();
124         sleep_mtx = uth_mutex_alloc();
125         register_fork_cb(&select_fork_cb);
126 }
127
128 static int select_tv_to_ep_timeout(struct timeval *tv)
129 {
130         if (!tv)
131                 return -1;
132         return tv->tv_sec * 1000 + DIV_ROUND_UP(tv->tv_usec, 1000);
133 }
134
135 /* Check with the kernel if FD is readable/writable or not.  Some apps will call
136  * select() on something even if it is already actionable, and not wait until
137  * they get the EAGAIN.
138  *
139  * TODO: this *won't* work for disk based files.  It only works on qids that are
140  * backed with qio queues or something similar, where the device has support for
141  * setting DMREADABLE/DMWRITABLE. */
142 static bool fd_is_actionable(int fd, fd_set *readfds, fd_set *writefds)
143 {
144         struct stat stat_buf;
145         int ret;
146
147         /* Avoid the stat call on FDs we're not tracking (which should trigger an
148          * error, or give us the stat for FD 0). */
149         if (!(fd_is_set(fd, readfds) || fd_is_set(fd, writefds)))
150                 return FALSE;
151         ret = fstat(fd, &stat_buf);
152         assert(!ret);
153         return (fd_is_set(fd, readfds) && S_READABLE(stat_buf.st_mode)) ||
154                (fd_is_set(fd, writefds) && S_WRITABLE(stat_buf.st_mode));
155 }
156
157 int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
158            struct timeval *timeout)
159 {
160         bool changed_set = FALSE;
161         struct epoll_event ep_ev;
162         struct epoll_event *ep_results;
163         uintptr_t my_call_id;
164         int ret;
165         int ep_timeout = select_tv_to_ep_timeout(timeout);
166         static parlib_once_t once = PARLIB_ONCE_INIT;
167
168         parlib_run_once(&once, select_init, NULL);
169         /* good thing nfds is a signed int... */
170         if (nfds < 0) {
171                 errno = EINVAL;
172                 return -1;
173         }
174         /* It is legal to select on read even if you didn't consume all of the data
175          * in an FD; similarly for writers on non-full FDs. */
176         for (int i = 0; i < nfds; i++) {
177                 if (fd_is_actionable(i, readfds, writefds))
178                         return nfds;
179         }
180         uth_mutex_lock(fdset_mtx);
181         for (int i = 0; i < nfds; i++) {
182                 if ((fd_is_set(i, readfds) || fd_is_set(i, writefds) ||
183                      fd_is_set(i, exceptfds)) &&
184                     !fd_is_set(i, &all_fds)) {
185
186                         changed_set = TRUE;
187                         FD_SET(i, &all_fds);
188                         /* FDs that we track for *any* reason with select will be
189                          * tracked for *all* reasons with epoll. */
190                         ep_ev.events = EPOLLET | EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLERR;
191                         ep_ev.data.fd = i;
192                         if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, i, &ep_ev)) {
193                                 /* We might have failed because we tried to set up too many
194                                  * FD tap types.  Listen FDs, for instance, can only be
195                                  * tapped for READABLE and HANGUP.  Let's try for one of
196                                  * those. */
197                                 if (errno == ENOSYS) {
198                                         ep_ev.events = EPOLLET | EPOLLIN | EPOLLHUP;
199                                         if (!epoll_ctl(epoll_fd, EPOLL_CTL_ADD, i, &ep_ev))
200                                                 continue;
201                                 }
202                                 /* Careful to unlock before calling perror.  perror calls
203                                  * close, which calls our CB, which grabs the lock. */
204                                 uth_mutex_unlock(fdset_mtx);
205                                 perror("select epoll_ctl failed");
206                                 return -1;
207                         }
208                 }
209         }
210         uth_mutex_unlock(fdset_mtx);
211         /* Since we just added some FD to our tracking set, we don't know if its
212          * readable or not.  We'll only catch edge-triggered changes in the future.
213          * We can spuriously tell the user all FDs are ready, and next time they
214          * can block until there is edge activity. */
215         if (changed_set)
216                 return nfds;
217         /* Since there is a global epoll set, we could have multiple threads
218          * epolling at a time and one thread could consume the events that should
219          * wake another thread.  We don't know when the 'other' thread last polled,
220          * so we'll need to assume its event was consumed and just return.
221          *
222          * To make matters more confusing, we could also have a single thread that
223          * selects multiple times on separate FD sets.  So we also need to
224          * distinguish between calls and threads.
225          *
226          * If the same {thread, callsite} selects again and no one else has since
227          * selected, then we know no one consumed the events.  We'll use the stack
228          * pointer to uniquely identify the {thread, callsite} combo that recently
229          * selected.  We use a mutex so that the extra threads sleep. */
230         uth_mutex_lock(sleep_mtx);
231         my_call_id = get_stack_pointer();
232         if (my_call_id != unique_caller) {
233                 /* Could thrash, if we fight with another uth for unique_caller */
234                 unique_caller = my_call_id;
235                 uth_mutex_unlock(sleep_mtx);
236                 return nfds;
237         }
238         /* Need to check for up to FD_SETSIZE - nfds isn't the size of all FDs
239          * tracked; it's the size of only our current select call */
240         ep_results = malloc(sizeof(struct epoll_event) * FD_SETSIZE);
241         if (!ep_results) {
242                 uth_mutex_unlock(sleep_mtx);
243                 errno = ENOMEM;
244                 return -1;
245         }
246         /* Don't care which ones were set; we'll just tell the user they all were
247          * set.  If they can't handle that, this whole plan won't work. */
248         ret = epoll_wait(epoll_fd, ep_results, FD_SETSIZE, ep_timeout);
249         uth_mutex_unlock(sleep_mtx);
250         free(ep_results);
251         /* TODO: consider updating timeval.  It's not mandatory (POSIX). */
252         if (ret == 0)   /* timeout */
253                 return 0;
254         return nfds;
255 }
256
257 int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
258             const struct timespec *timeout, const sigset_t *sigmask)
259 {
260         int ready;
261         sigset_t origmask;
262         struct timeval local_tv, *tv = &local_tv;
263
264         if (!timeout) {
265                 tv = 0;
266         } else {
267                 tv->tv_sec = timeout->tv_sec;
268                 tv->tv_usec = DIV_ROUND_UP(timeout->tv_nsec, 1000);
269         }
270         /* TODO: this is probably racy */
271         sigprocmask(SIG_SETMASK, sigmask, &origmask);
272         ready = select(nfds, readfds, writefds, exceptfds, tv);
273         sigprocmask(SIG_SETMASK, &origmask, NULL);
274         return ready;
275 }