opendir change: refinement
[minix.git] / servers / vfs / select.c
blob3fc08dac3d35d4d3b747a102823714ebf9ede6e5
1 /* Implement entry point to select system call.
3 * The entry points into this file are
4 * do_select: perform the SELECT system call
5 * select_callback: notify select system of possible fd operation
6 * select_unsuspend_by_endpt: cancel a blocking select on exiting driver
7 */
9 #include "fs.h"
10 #include <sys/fcntl.h>
11 #include <sys/time.h>
12 #include <sys/select.h>
13 #include <sys/stat.h>
14 #include <minix/com.h>
15 #include <minix/u64.h>
16 #include <string.h>
17 #include <assert.h>
19 #include "file.h"
20 #include "fproc.h"
21 #include "dmap.h"
22 #include "vnode.h"
24 /* max. number of simultaneously pending select() calls */
25 #define MAXSELECTS 25
26 #define FROM_PROC 0
27 #define TO_PROC 1
29 static struct selectentry {
30 struct fproc *requestor; /* slot is free iff this is NULL */
31 endpoint_t req_endpt;
32 fd_set readfds, writefds, errorfds;
33 fd_set ready_readfds, ready_writefds, ready_errorfds;
34 fd_set *vir_readfds, *vir_writefds, *vir_errorfds;
35 struct filp *filps[OPEN_MAX];
36 int type[OPEN_MAX];
37 int nfds, nreadyfds;
38 int error;
39 char block;
40 clock_t expiry;
41 timer_t timer; /* if expiry > 0 */
42 } selecttab[MAXSELECTS];
44 static int copy_fdsets(struct selectentry *se, int nfds, int
45 direction);
46 static int do_select_request(struct selectentry *se, int fd, int *ops);
47 static void filp_status(struct filp *fp, int status);
48 static int is_deferred(struct selectentry *se);
49 static void restart_proc(struct selectentry *se);
50 static void ops2tab(int ops, int fd, struct selectentry *e);
51 static int is_regular_file(struct filp *f);
52 static int is_pipe(struct filp *f);
53 static int is_supported_major(struct filp *f);
54 static void select_lock_filp(struct filp *f, int ops);
55 static int select_request_async(struct filp *f, int *ops, int block);
56 static int select_request_file(struct filp *f, int *ops, int block);
57 static int select_request_major(struct filp *f, int *ops, int block);
58 static int select_request_pipe(struct filp *f, int *ops, int block);
59 static int select_request_sync(struct filp *f, int *ops, int block);
60 static void select_cancel_all(struct selectentry *e);
61 static void select_cancel_filp(struct filp *f);
62 static void select_return(struct selectentry *);
63 static void select_restart_filps(void);
64 static int tab2ops(int fd, struct selectentry *e);
65 static void wipe_select(struct selectentry *s);
67 static struct fdtype {
68 int (*select_request)(struct filp *, int *ops, int block);
69 int (*type_match)(struct filp *f);
70 } fdtypes[] = {
71 { select_request_major, is_supported_major },
72 { select_request_file, is_regular_file },
73 { select_request_pipe, is_pipe },
75 #define SEL_FDS (sizeof(fdtypes) / sizeof(fdtypes[0]))
76 static int select_majors[] = { /* List of majors that support selecting on */
77 TTY_MAJOR,
78 INET_MAJOR,
79 UDS_MAJOR,
80 LOG_MAJOR,
82 #define SEL_MAJORS (sizeof(select_majors) / sizeof(select_majors[0]))
84 /*===========================================================================*
85 * do_select *
86 *===========================================================================*/
87 int do_select(void)
89 /* Implement the select(nfds, readfds, writefds, errorfds, timeout) system
90 * call. First we copy the arguments and verify their sanity. Then we check
91 * whether there are file descriptors that satisfy the select call right of the
92 * bat. If so, or if there are no ready file descriptors but the process
93 * requested to return immediately, we return the result. Otherwise we set a
94 * timeout and wait for either the file descriptors to become ready or the
95 * timer to go off. If no timeout value was provided, we wait indefinitely. */
97 int r, nfds, do_timeout = 0, fd, s;
98 struct timeval timeout;
99 struct selectentry *se;
100 vir_bytes vtimeout;
102 nfds = job_m_in.SEL_NFDS;
103 vtimeout = (vir_bytes) job_m_in.SEL_TIMEOUT;
105 /* Sane amount of file descriptors? */
106 if (nfds < 0 || nfds > OPEN_MAX) return(EINVAL);
108 /* Find a slot to store this select request */
109 for (s = 0; s < MAXSELECTS; s++)
110 if (selecttab[s].requestor == NULL) /* Unused slot */
111 break;
112 if (s >= MAXSELECTS) return(ENOSPC);
114 se = &selecttab[s];
115 wipe_select(se); /* Clear results of previous usage */
116 se->requestor = fp;
117 se->req_endpt = who_e;
118 se->vir_readfds = (fd_set *) job_m_in.SEL_READFDS;
119 se->vir_writefds = (fd_set *) job_m_in.SEL_WRITEFDS;
120 se->vir_errorfds = (fd_set *) job_m_in.SEL_ERRORFDS;
122 /* Copy fdsets from the process */
123 if ((r = copy_fdsets(se, nfds, FROM_PROC)) != OK) {
124 se->requestor = NULL;
125 return(r);
128 /* Did the process set a timeout value? If so, retrieve it. */
129 if (vtimeout != 0) {
130 do_timeout = 1;
131 r = sys_vircopy(who_e, (vir_bytes) vtimeout, SELF,
132 (vir_bytes) &timeout, sizeof(timeout));
133 if (r != OK) {
134 se->requestor = NULL;
135 return(r);
139 /* No nonsense in the timeval */
140 if (do_timeout && (timeout.tv_sec < 0 || timeout.tv_usec < 0)) {
141 se->requestor = NULL;
142 return(EINVAL);
145 /* If there is no timeout, we block forever. Otherwise, we block up to the
146 * specified time interval.
148 if (!do_timeout) /* No timeout value set */
149 se->block = 1;
150 else if (do_timeout && (timeout.tv_sec > 0 || timeout.tv_usec > 0))
151 se->block = 1;
152 else /* timeout set as (0,0) - this effects a poll */
153 se->block = 0;
154 se->expiry = 0; /* no timer set (yet) */
156 /* Verify that file descriptors are okay to select on */
157 for (fd = 0; fd < nfds; fd++) {
158 struct filp *f;
159 unsigned int type, ops;
161 /* Because the select() interface implicitly includes file descriptors
162 * you might not want to select on, we have to figure out whether we're
163 * interested in them. Typically, these file descriptors include fd's
164 * inherited from the parent proc and file descriptors that have been
165 * close()d, but had a lower fd than one in the current set.
167 if (!(ops = tab2ops(fd, se)))
168 continue; /* No operations set; nothing to do for this fd */
170 /* Get filp belonging to this fd */
171 f = se->filps[fd] = get_filp(fd, VNODE_READ);
172 if (f == NULL) {
173 if (err_code == EBADF)
174 r = err_code;
175 else /* File descriptor is 'ready' to return EIO */
176 r = EINTR;
178 se->requestor = NULL;
179 return(r);
182 /* Check file types. According to POSIX 2008:
183 * "The pselect() and select() functions shall support regular files,
184 * terminal and pseudo-terminal devices, FIFOs, pipes, and sockets. The
185 * behavior of pselect() and select() on file descriptors that refer to
186 * other types of file is unspecified."
188 * In our case, terminal and pseudo-terminal devices are handled by the
189 * TTY major and sockets by either INET major (socket type AF_INET) or
190 * PFS major (socket type AF_UNIX). PFS acts as an FS when it handles
191 * pipes and as a driver when it handles sockets. Additionally, we
192 * support select on the LOG major to handle kernel logging, which is
193 * beyond the POSIX spec. */
195 se->type[fd] = -1;
196 for (type = 0; type < SEL_FDS; type++) {
197 if (fdtypes[type].type_match(f)) {
198 se->type[fd] = type;
199 se->nfds = fd+1;
200 se->filps[fd]->filp_selectors++;
201 break;
204 unlock_filp(f);
205 if (se->type[fd] == -1) { /* Type not found */
206 se->requestor = NULL;
207 return(EBADF);
211 /* Check all file descriptors in the set whether one is 'ready' now */
212 for (fd = 0; fd < nfds; fd++) {
213 int ops, r;
214 struct filp *f;
216 /* Again, check for involuntarily selected fd's */
217 if (!(ops = tab2ops(fd, se)))
218 continue; /* No operations set; nothing to do for this fd */
220 /* Test filp for select operations if not already done so. e.g.,
221 * processes sharing a filp and both doing a select on that filp. */
222 f = se->filps[fd];
223 if ((f->filp_select_ops & ops) != ops) {
224 int wantops;
226 wantops = (f->filp_select_ops |= ops);
227 r = do_select_request(se, fd, &wantops);
228 if (r != OK && r != SUSPEND)
229 break; /* Error or bogus return code; abort */
231 /* The select request above might have turned on/off some
232 * operations because they were 'ready' or not meaningful.
233 * Either way, we might have a result and we need to store them
234 * in the select table entry. */
235 if (wantops & ops) ops2tab(wantops, fd, se);
239 if ((se->nreadyfds > 0 || !se->block) && !is_deferred(se)) {
240 /* fd's were found that were ready to go right away, and/or
241 * we were instructed not to block at all. Must return
242 * immediately.
244 r = copy_fdsets(se, se->nfds, TO_PROC);
245 select_cancel_all(se);
246 se->requestor = NULL;
248 if (r != OK)
249 return(r);
250 else if (se->error != OK)
251 return(se->error);
253 return(se->nreadyfds);
256 /* Convert timeval to ticks and set the timer. If it fails, undo
257 * all, return error.
259 if (do_timeout) {
260 int ticks;
261 /* Open Group:
262 * "If the requested timeout interval requires a finer
263 * granularity than the implementation supports, the
264 * actual timeout interval shall be rounded up to the next
265 * supported value."
267 #define USECPERSEC 1000000
268 while(timeout.tv_usec >= USECPERSEC) {
269 /* this is to avoid overflow with *system_hz below */
270 timeout.tv_usec -= USECPERSEC;
271 timeout.tv_sec++;
273 ticks = timeout.tv_sec * system_hz +
274 (timeout.tv_usec * system_hz + USECPERSEC-1) / USECPERSEC;
275 se->expiry = ticks;
276 set_timer(&se->timer, ticks, select_timeout_check, s);
279 /* process now blocked */
280 suspend(FP_BLOCKED_ON_SELECT);
281 return(SUSPEND);
284 /*===========================================================================*
285 * is_deferred *
286 *===========================================================================*/
287 static int is_deferred(struct selectentry *se)
289 /* Find out whether this select has pending initial replies */
291 int fd;
292 struct filp *f;
294 for (fd = 0; fd < se->nfds; fd++) {
295 if ((f = se->filps[fd]) == NULL) continue;
296 if (f->filp_select_flags & (FSF_UPDATE|FSF_BUSY)) return(TRUE);
299 return(FALSE);
303 /*===========================================================================*
304 * is_regular_file *
305 *===========================================================================*/
306 static int is_regular_file(struct filp *f)
308 return(f && f->filp_vno && S_ISREG(f->filp_vno->v_mode));
311 /*===========================================================================*
312 * is_pipe *
313 *===========================================================================*/
314 static int is_pipe(struct filp *f)
316 /* Recognize either anonymous pipe or named pipe (FIFO) */
317 return(f && f->filp_vno && S_ISFIFO(f->filp_vno->v_mode));
320 /*===========================================================================*
321 * is_supported_major *
322 *===========================================================================*/
323 static int is_supported_major(struct filp *f)
325 /* See if this filp is a handle on a device on which we support select() */
326 unsigned int m;
328 if (!(f && f->filp_vno)) return(FALSE);
329 if (!S_ISCHR(f->filp_vno->v_mode)) return(FALSE);
331 for (m = 0; m < SEL_MAJORS; m++)
332 if (major(f->filp_vno->v_sdev) == select_majors[m])
333 return(TRUE);
335 return(FALSE);
338 /*===========================================================================*
339 * select_request_async *
340 *===========================================================================*/
341 static int select_request_async(struct filp *f, int *ops, int block)
343 int r, rops, major;
344 struct dmap *dp;
346 rops = *ops;
348 /* By default, nothing to do */
349 *ops = 0;
351 if (!block && (f->filp_select_flags & FSF_BLOCKED)) {
352 /* This filp is blocked waiting for a reply, but we don't want to
353 * block ourselves. Unless we're awaiting the initial reply, these
354 * operations won't be ready */
355 if (!(f->filp_select_flags & FSF_BUSY)) {
356 if ((rops & SEL_RD) && (f->filp_select_flags & FSF_RD_BLOCK))
357 rops &= ~SEL_RD;
358 if ((rops & SEL_WR) && (f->filp_select_flags & FSF_WR_BLOCK))
359 rops &= ~SEL_WR;
360 if ((rops & SEL_ERR) && (f->filp_select_flags & FSF_ERR_BLOCK))
361 rops &= ~SEL_ERR;
362 if (!(rops & (SEL_RD|SEL_WR|SEL_ERR)))
363 return(OK);
367 f->filp_select_flags |= FSF_UPDATE;
368 if (block) {
369 rops |= SEL_NOTIFY;
370 if (rops & SEL_RD) f->filp_select_flags |= FSF_RD_BLOCK;
371 if (rops & SEL_WR) f->filp_select_flags |= FSF_WR_BLOCK;
372 if (rops & SEL_ERR) f->filp_select_flags |= FSF_ERR_BLOCK;
375 if (f->filp_select_flags & FSF_BUSY)
376 return(SUSPEND);
378 major = major(f->filp_vno->v_sdev);
379 if (major < 0 || major >= NR_DEVICES) return(ENXIO);
380 dp = &dmap[major];
381 if (dp->dmap_sel_filp)
382 return(SUSPEND);
384 f->filp_select_flags &= ~FSF_UPDATE;
385 r = dev_io(VFS_DEV_SELECT, f->filp_vno->v_sdev, rops, NULL,
386 cvu64(0), 0, 0, FALSE);
387 if (r < 0 && r != SUSPEND)
388 return(r);
390 if (r != SUSPEND)
391 panic("select_request_asynch: expected SUSPEND got: %d", r);
393 dp->dmap_sel_filp = f;
394 f->filp_select_flags |= FSF_BUSY;
396 return(SUSPEND);
399 /*===========================================================================*
400 * select_request_file *
401 *===========================================================================*/
402 static int select_request_file(struct filp *UNUSED(f), int *UNUSED(ops),
403 int UNUSED(block))
405 /* Files are always ready, so output *ops is input *ops */
406 return(OK);
409 /*===========================================================================*
410 * select_request_major *
411 *===========================================================================*/
412 static int select_request_major(struct filp *f, int *ops, int block)
414 int major, r;
416 major = major(f->filp_vno->v_sdev);
417 if (major < 0 || major >= NR_DEVICES) return(ENXIO);
419 if (dmap[major].dmap_style == STYLE_DEVA ||
420 dmap[major].dmap_style == STYLE_CLONE_A)
421 r = select_request_async(f, ops, block);
422 else
423 r = select_request_sync(f, ops, block);
425 return(r);
428 /*===========================================================================*
429 * select_request_sync *
430 *===========================================================================*/
431 static int select_request_sync(struct filp *f, int *ops, int block)
433 int rops;
435 rops = *ops;
436 if (block) rops |= SEL_NOTIFY;
437 *ops = dev_io(VFS_DEV_SELECT, f->filp_vno->v_sdev, rops, NULL,
438 cvu64(0), 0, 0, FALSE);
439 if (*ops < 0)
440 return(*ops);
442 return(OK);
445 /*===========================================================================*
446 * select_request_pipe *
447 *===========================================================================*/
448 static int select_request_pipe(struct filp *f, int *ops, int block)
450 int orig_ops, r = 0, err;
452 orig_ops = *ops;
454 if ((*ops & (SEL_RD|SEL_ERR))) {
455 /* Check if we can read 1 byte */
456 err = pipe_check(f->filp_vno, READING, f->filp_flags & ~O_NONBLOCK, 1,
457 1 /* Check only */);
459 if (err != SUSPEND)
460 r |= SEL_RD;
461 if (err < 0 && err != SUSPEND)
462 r |= SEL_ERR;
463 if (err == SUSPEND && !(f->filp_mode & R_BIT)) {
464 /* A "meaningless" read select, therefore ready
465 * for reading and no error set. */
466 r |= SEL_RD;
467 r &= ~SEL_ERR;
471 if ((*ops & (SEL_WR|SEL_ERR))) {
472 /* Check if we can write 1 byte */
473 err = pipe_check(f->filp_vno, WRITING, f->filp_flags & ~O_NONBLOCK, 1,
474 1 /* Check only */);
476 if (err != SUSPEND)
477 r |= SEL_WR;
478 if (err < 0 && err != SUSPEND)
479 r |= SEL_ERR;
480 if (err == SUSPEND && !(f->filp_mode & W_BIT)) {
481 /* A "meaningless" write select, therefore ready
482 for writing and no error set. */
483 r |= SEL_WR;
484 r &= ~SEL_ERR;
488 /* Some options we collected might not be requested. */
489 *ops = r & orig_ops;
491 if (!*ops && block)
492 f->filp_pipe_select_ops |= orig_ops;
494 return(OK);
497 /*===========================================================================*
498 * tab2ops *
499 *===========================================================================*/
500 static int tab2ops(int fd, struct selectentry *e)
502 int ops = 0;
503 if (FD_ISSET(fd, &e->readfds)) ops |= SEL_RD;
504 if (FD_ISSET(fd, &e->writefds)) ops |= SEL_WR;
505 if (FD_ISSET(fd, &e->errorfds)) ops |= SEL_ERR;
507 return(ops);
511 /*===========================================================================*
512 * ops2tab *
513 *===========================================================================*/
514 static void ops2tab(int ops, int fd, struct selectentry *e)
516 if ((ops & SEL_RD) && e->vir_readfds && FD_ISSET(fd, &e->readfds) &&
517 !FD_ISSET(fd, &e->ready_readfds)) {
518 FD_SET(fd, &e->ready_readfds);
519 e->nreadyfds++;
522 if ((ops & SEL_WR) && e->vir_writefds && FD_ISSET(fd, &e->writefds) &&
523 !FD_ISSET(fd, &e->ready_writefds)) {
524 FD_SET(fd, &e->ready_writefds);
525 e->nreadyfds++;
528 if ((ops & SEL_ERR) && e->vir_errorfds && FD_ISSET(fd, &e->errorfds) &&
529 !FD_ISSET(fd, &e->ready_errorfds)) {
530 FD_SET(fd, &e->ready_errorfds);
531 e->nreadyfds++;
536 /*===========================================================================*
537 * copy_fdsets *
538 *===========================================================================*/
539 static int copy_fdsets(struct selectentry *se, int nfds, int direction)
541 int r;
542 size_t fd_setsize;
543 endpoint_t src_e, dst_e;
544 fd_set *src_fds, *dst_fds;
546 if (nfds < 0 || nfds > OPEN_MAX)
547 panic("select copy_fdsets: nfds wrong: %d", nfds);
549 /* Only copy back as many bits as the user expects. */
550 #ifdef __NBSD_LIBC
551 fd_setsize = (size_t) (howmany(nfds, __NFDBITS) * sizeof(__fd_mask));
552 #else
553 fd_setsize = (size_t) (_FDSETWORDS(nfds) * _FDSETBITSPERWORD/8);
554 #endif
556 /* Set source and destination endpoints */
557 src_e = (direction == FROM_PROC) ? se->req_endpt : SELF;
558 dst_e = (direction == FROM_PROC) ? SELF : se->req_endpt;
560 /* read set */
561 src_fds = (direction == FROM_PROC) ? se->vir_readfds : &se->ready_readfds;
562 dst_fds = (direction == FROM_PROC) ? &se->readfds : se->vir_readfds;
563 if (se->vir_readfds) {
564 r = sys_vircopy(src_e, (vir_bytes) src_fds, dst_e,
565 (vir_bytes) dst_fds, fd_setsize);
566 if (r != OK) return(r);
569 /* write set */
570 src_fds = (direction == FROM_PROC) ? se->vir_writefds : &se->ready_writefds;
571 dst_fds = (direction == FROM_PROC) ? &se->writefds : se->vir_writefds;
572 if (se->vir_writefds) {
573 r = sys_vircopy(src_e, (vir_bytes) src_fds, dst_e,
574 (vir_bytes) dst_fds, fd_setsize);
575 if (r != OK) return(r);
578 /* error set */
579 src_fds = (direction == FROM_PROC) ? se->vir_errorfds : &se->ready_errorfds;
580 dst_fds = (direction == FROM_PROC) ? &se->errorfds : se->vir_errorfds;
581 if (se->vir_errorfds) {
582 r = sys_vircopy(src_e, (vir_bytes) src_fds, dst_e,
583 (vir_bytes) dst_fds, fd_setsize);
584 if (r != OK) return(r);
587 return(OK);
591 /*===========================================================================*
592 * select_cancel_all *
593 *===========================================================================*/
594 static void select_cancel_all(struct selectentry *se)
596 /* Cancel select. Decrease select usage and cancel timer */
598 int fd;
599 struct filp *f;
601 for (fd = 0; fd < se->nfds; fd++) {
602 if ((f = se->filps[fd]) == NULL) continue;
603 se->filps[fd] = NULL;
604 select_cancel_filp(f);
607 if (se->expiry > 0) {
608 cancel_timer(&se->timer);
609 se->expiry = 0;
612 se->requestor = NULL;
615 /*===========================================================================*
616 * select_cancel_filp *
617 *===========================================================================*/
618 static void select_cancel_filp(struct filp *f)
620 /* Reduce number of select users of this filp */
622 assert(f);
623 assert(f->filp_selectors >= 0);
624 if (f->filp_selectors == 0) return;
625 if (f->filp_count == 0) return;
627 select_lock_filp(f, f->filp_select_ops);
629 f->filp_selectors--;
630 if (f->filp_selectors == 0) {
631 /* No one selecting on this filp anymore, forget about select state */
632 f->filp_select_ops = 0;
633 f->filp_select_flags = 0;
634 f->filp_pipe_select_ops = 0;
637 unlock_filp(f);
640 /*===========================================================================*
641 * select_return *
642 *===========================================================================*/
643 static void select_return(struct selectentry *se)
645 int r, r1;
647 assert(!is_deferred(se)); /* Not done yet, first wait for async reply */
649 select_cancel_all(se);
651 r1 = copy_fdsets(se, se->nfds, TO_PROC);
652 if (r1 != OK)
653 r = r1;
654 else if (se->error != OK)
655 r = se->error;
656 else
657 r = se->nreadyfds;
659 revive(se->req_endpt, r);
663 /*===========================================================================*
664 * select_callback *
665 *===========================================================================*/
666 void select_callback(struct filp *f, int status)
668 filp_status(f, status);
671 /*===========================================================================*
672 * init_select *
673 *===========================================================================*/
674 void init_select(void)
676 int s;
678 for (s = 0; s < MAXSELECTS; s++)
679 init_timer(&selecttab[s].timer);
683 /*===========================================================================*
684 * select_forget *
685 *===========================================================================*/
686 void select_forget(endpoint_t proc_e)
688 /* Something has happened (e.g. signal delivered that interrupts select()).
689 * Totally forget about the select(). */
691 int slot;
692 struct selectentry *se;
694 for (slot = 0; slot < MAXSELECTS; slot++) {
695 se = &selecttab[slot];
696 if (se->requestor != NULL && se->req_endpt == proc_e)
697 break;
700 if (slot >= MAXSELECTS) return; /* Entry not found */
701 se->error = EINTR;
702 if (is_deferred(se)) return; /* Still awaiting initial reply */
704 select_cancel_all(se);
708 /*===========================================================================*
709 * select_timeout_check *
710 *===========================================================================*/
711 void select_timeout_check(timer_t *timer)
713 int s;
714 struct selectentry *se;
716 s = tmr_arg(timer)->ta_int;
717 if (s < 0 || s >= MAXSELECTS) return; /* Entry does not exist */
719 se = &selecttab[s];
720 if (se->requestor == NULL) return;
721 fp = se->requestor;
722 if (se->expiry <= 0) return; /* Strange, did we even ask for a timeout? */
723 se->expiry = 0;
724 if (is_deferred(se)) return; /* Wait for initial replies to DEV_SELECT */
725 select_return(se);
729 /*===========================================================================*
730 * select_unsuspend_by_endpt *
731 *===========================================================================*/
732 void select_unsuspend_by_endpt(endpoint_t proc_e)
734 /* Revive blocked processes when a driver has disappeared */
736 int fd, s, major;
737 struct selectentry *se;
738 struct filp *f;
740 for (s = 0; s < MAXSELECTS; s++) {
741 int wakehim = 0;
742 se = &selecttab[s];
743 if (se->requestor == NULL) continue;
744 if (se->requestor->fp_endpoint == proc_e) {
745 assert(se->requestor->fp_flags & FP_EXITING);
746 select_cancel_all(se);
747 continue;
750 for (fd = 0; fd < se->nfds; fd++) {
751 if ((f = se->filps[fd]) == NULL || f->filp_vno == NULL)
752 continue;
754 major = major(f->filp_vno->v_sdev);
755 if (dmap_driver_match(proc_e, major)) {
756 se->filps[fd] = NULL;
757 se->error = EINTR;
758 select_cancel_filp(f);
759 wakehim = 1;
763 if (wakehim && !is_deferred(se))
764 select_return(se);
768 /*===========================================================================*
769 * select_reply1 *
770 *===========================================================================*/
771 void select_reply1(driver_e, minor, status)
772 endpoint_t driver_e;
773 int minor;
774 int status;
776 /* Handle reply to DEV_SELECT request */
778 int major;
779 dev_t dev;
780 struct filp *f;
781 struct dmap *dp;
782 struct vnode *vp;
784 /* Figure out which device is replying */
785 if ((dp = get_dmap(driver_e)) == NULL) return;
787 major = dp-dmap;
788 dev = makedev(major, minor);
790 /* Get filp belonging to character special file */
791 if ((f = dp->dmap_sel_filp) == NULL) {
792 printf("VFS (%s:%d): major %d was not expecting a DEV_SELECT reply\n",
793 __FILE__, __LINE__, major);
794 return;
797 /* Is the filp still in use and busy waiting for a reply? The owner might
798 * have vanished before the driver was able to reply. */
799 if (f->filp_count >= 1 && (f->filp_select_flags & FSF_BUSY)) {
800 /* Find vnode and check we got a reply from the device we expected */
801 vp = f->filp_vno;
802 assert(vp != NULL);
803 assert(S_ISCHR(vp->v_mode));
804 if (vp->v_sdev != dev) {
805 printf("VFS (%s:%d): expected reply from dev %d not %d\n",
806 __FILE__, __LINE__, vp->v_sdev, dev);
807 return;
811 /* No longer waiting for a reply from this device */
812 dp->dmap_sel_filp = NULL;
814 /* Process select result only if requestor is still around. That is, the
815 * corresponding filp is still in use.
817 if (f->filp_count >= 1) {
818 select_lock_filp(f, f->filp_select_ops);
819 f->filp_select_flags &= ~FSF_BUSY;
821 /* The select call is done now, except when
822 * - another process started a select on the same filp with possibly a
823 * different set of operations.
824 * - a process does a select on the same filp but using different file
825 * descriptors.
826 * - the select has a timeout. Upon receiving this reply the operations
827 * might not be ready yet, so we want to wait for that to ultimately
828 * happen.
829 * Therefore we need to keep remembering what the operations are.
831 if (!(f->filp_select_flags & (FSF_UPDATE|FSF_BLOCKED)))
832 f->filp_select_ops = 0; /* done selecting */
833 else if (!(f->filp_select_flags & FSF_UPDATE))
834 /* there may be operations pending */
835 f->filp_select_ops &= ~status;
837 /* Record new filp status */
838 if (!(status == 0 && (f->filp_select_flags & FSF_BLOCKED))) {
839 if (status > 0) { /* operations ready */
840 if (status & SEL_RD)
841 f->filp_select_flags &= ~FSF_RD_BLOCK;
842 if (status & SEL_WR)
843 f->filp_select_flags &= ~FSF_WR_BLOCK;
844 if (status & SEL_ERR)
845 f->filp_select_flags &= ~FSF_ERR_BLOCK;
846 } else if (status < 0) { /* error */
847 /* Always unblock upon error */
848 f->filp_select_flags &= ~FSF_BLOCKED;
852 unlock_filp(f);
853 filp_status(f, status); /* Tell filp owners about the results */
856 select_restart_filps();
860 /*===========================================================================*
861 * select_reply2 *
862 *===========================================================================*/
863 void select_reply2(driver_e, minor, status)
864 endpoint_t driver_e;
865 int minor;
866 int status;
868 /* Handle secondary reply to DEV_SELECT request. A secondary reply occurs when
869 * the select request is 'blocking' until an operation becomes ready. */
870 int major, slot, fd;
871 dev_t dev;
872 struct filp *f;
873 struct dmap *dp;
874 struct vnode *vp;
875 struct selectentry *se;
877 if (status == 0) {
878 printf("VFS (%s:%d): weird status (%d) to report\n",
879 __FILE__, __LINE__, status);
880 return;
883 /* Figure out which device is replying */
884 if ((dp = get_dmap(driver_e)) == NULL) {
885 printf("VFS (%s:%d): endpoint %d is not a known driver endpoint\n",
886 __FILE__, __LINE__, driver_e);
887 return;
889 major = dp-dmap;
890 dev = makedev(major, minor);
892 /* Find all file descriptors selecting for this device */
893 for (slot = 0; slot < MAXSELECTS; slot++) {
894 se = &selecttab[slot];
895 if (se->requestor == NULL) continue; /* empty slot */
897 for (fd = 0; fd < se->nfds; fd++) {
898 if ((f = se->filps[fd]) == NULL) continue;
899 if ((vp = f->filp_vno) == NULL) continue;
900 if (!S_ISCHR(vp->v_mode)) continue;
901 if (vp->v_sdev != dev) continue;
903 select_lock_filp(f, f->filp_select_ops);
904 if (status > 0) { /* Operations ready */
905 /* Clear the replied bits from the request
906 * mask unless FSF_UPDATE is set.
908 if (!(f->filp_select_flags & FSF_UPDATE))
909 f->filp_select_ops &= ~status;
910 if (status & SEL_RD)
911 f->filp_select_flags &= ~FSF_RD_BLOCK;
912 if (status & SEL_WR)
913 f->filp_select_flags &= ~FSF_WR_BLOCK;
914 if (status & SEL_ERR)
915 f->filp_select_flags &= ~FSF_ERR_BLOCK;
917 ops2tab(status, fd, se);
918 } else {
919 f->filp_select_flags &= ~FSF_BLOCKED;
920 ops2tab(SEL_RD|SEL_WR|SEL_ERR, fd, se);
922 unlock_filp(f);
923 if (se->nreadyfds > 0) restart_proc(se);
927 select_restart_filps();
930 /*===========================================================================*
931 * select_restart_filps *
932 *===========================================================================*/
933 static void select_restart_filps()
935 int fd, slot;
936 struct filp *f;
937 struct vnode *vp;
938 struct selectentry *se;
940 /* Locate filps that can be restarted */
941 for (slot = 0; slot < MAXSELECTS; slot++) {
942 se = &selecttab[slot];
943 if (se->requestor == NULL) continue; /* empty slot */
945 /* Only 'deferred' processes are eligible to restart */
946 if (!is_deferred(se)) continue;
948 /* Find filps that are not waiting for a reply, but have an updated
949 * status (i.e., another select on the same filp with possibly a
950 * different set of operations is to be done), and thus requires the
951 * select request to be sent again).
953 for (fd = 0; fd < se->nfds; fd++) {
954 int r, wantops, ops;
955 if ((f = se->filps[fd]) == NULL) continue;
956 if (f->filp_select_flags & FSF_BUSY) /* Still waiting for */
957 continue; /* initial reply */
958 if (!(f->filp_select_flags & FSF_UPDATE)) /* Must be in */
959 continue; /* 'update' state */
961 wantops = ops = f->filp_select_ops;
962 vp = f->filp_vno;
963 assert(S_ISCHR(vp->v_mode));
964 r = do_select_request(se, fd, &wantops);
965 if (r != OK && r != SUSPEND)
966 break; /* Error or bogus return code; abort */
967 if (wantops & ops) ops2tab(wantops, fd, se);
972 /*===========================================================================*
973 * do_select_request *
974 *===========================================================================*/
975 static int do_select_request(se, fd, ops)
976 struct selectentry *se;
977 int fd;
978 int *ops;
980 /* Perform actual select request for file descriptor fd */
982 int r, type;
983 struct filp *f;
985 type = se->type[fd];
986 f = se->filps[fd];
987 select_lock_filp(f, *ops);
988 r = fdtypes[type].select_request(f, ops, se->block);
989 unlock_filp(f);
990 if (r != OK && r != SUSPEND) {
991 se->error = EINTR;
992 se->block = 0; /* Stop blocking to return asap */
993 if (!is_deferred(se)) select_cancel_all(se);
996 return(r);
999 /*===========================================================================*
1000 * filp_status *
1001 *===========================================================================*/
1002 static void filp_status(f, status)
1003 struct filp *f;
1004 int status;
1006 /* Tell processes that need to know about the status of this filp */
1007 int fd, slot;
1008 struct selectentry *se;
1010 for (slot = 0; slot < MAXSELECTS; slot++) {
1011 se = &selecttab[slot];
1012 if (se->requestor == NULL) continue; /* empty slot */
1014 for (fd = 0; fd < se->nfds; fd++) {
1015 if (se->filps[fd] != f) continue;
1016 if (status < 0)
1017 ops2tab(SEL_RD|SEL_WR|SEL_ERR, fd, se);
1018 else
1019 ops2tab(status, fd, se);
1020 restart_proc(se);
1025 /*===========================================================================*
1026 * restart_proc *
1027 *===========================================================================*/
1028 static void restart_proc(se)
1029 struct selectentry *se;
1031 /* Tell process about select results (if any) unless there are still results
1032 * pending. */
1034 if ((se->nreadyfds > 0 || !se->block) && !is_deferred(se))
1035 select_return(se);
1038 /*===========================================================================*
1039 * wipe_select *
1040 *===========================================================================*/
1041 static void wipe_select(struct selectentry *se)
1043 se->nfds = 0;
1044 se->nreadyfds = 0;
1045 se->error = OK;
1046 se->block = 0;
1047 memset(se->filps, 0, sizeof(se->filps));
1049 FD_ZERO(&se->readfds);
1050 FD_ZERO(&se->writefds);
1051 FD_ZERO(&se->errorfds);
1052 FD_ZERO(&se->ready_readfds);
1053 FD_ZERO(&se->ready_writefds);
1054 FD_ZERO(&se->ready_errorfds);
1057 /*===========================================================================*
1058 * select_lock_filp *
1059 *===========================================================================*/
1060 static void select_lock_filp(struct filp *f, int ops)
1062 /* Lock a filp and vnode based on which operations are requested */
1063 tll_access_t locktype;;
1065 locktype = VNODE_READ; /* By default */
1067 if (ops & (SEL_WR|SEL_ERR))
1068 /* Selecting for error or writing requires exclusive access */
1069 locktype = VNODE_WRITE;
1071 lock_filp(f, locktype);