Fixed extern declaration from pointer to array
[minix.git] / servers / vfs / select.c
blob5472b03b1181b89c4f853b515d322089d378bb2d
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_notified: low-level entry for device notifying select
7 * select_unsuspend_by_endpt: cancel a blocking select on exiting driver
8 */
10 #define DEBUG_SELECT 0
12 #include "fs.h"
13 #include "select.h"
14 #include "file.h"
15 #include "vnode.h"
17 #include <sys/time.h>
18 #include <sys/select.h>
19 #include <minix/com.h>
20 #include <minix/u64.h>
21 #include <string.h>
23 /* max. number of simultaneously pending select() calls */
24 #define MAXSELECTS 25
25 #define FROM_PROC 0
26 #define TO_PROC 1
28 PRIVATE struct selectentry {
29 struct fproc *requestor; /* slot is free iff this is NULL */
30 int req_endpt;
31 fd_set readfds, writefds, errorfds;
32 fd_set ready_readfds, ready_writefds, ready_errorfds;
33 fd_set *vir_readfds, *vir_writefds, *vir_errorfds;
34 struct filp *filps[OPEN_MAX];
35 int type[OPEN_MAX];
36 int deferred; /* awaiting initial reply from driver */
37 int deferred_fd; /* fd awaiting initial reply from driver */
38 int nfds, nreadyfds;
39 char block;
40 clock_t expiry;
41 timer_t timer; /* if expiry > 0 */
42 } selecttab[MAXSELECTS];
44 FORWARD _PROTOTYPE(int copy_fdsets, (struct selectentry *se, int nfds,
45 int direction) );
46 FORWARD _PROTOTYPE(void filp_status, (struct filp *fp, int status) );
47 FORWARD _PROTOTYPE(void restart_proc, (int slot) );
48 FORWARD _PROTOTYPE(void ops2tab, (int ops, int fd, struct selectentry *e));
49 FORWARD _PROTOTYPE(int select_reevaluate, (struct filp *fp) );
50 FORWARD _PROTOTYPE(int select_request_file, (struct filp *f, int *ops,
51 int block) );
52 FORWARD _PROTOTYPE(int select_match_file, (struct filp *f) );
53 FORWARD _PROTOTYPE(int select_request_general, (struct filp *f, int *ops,
54 int block) );
55 FORWARD _PROTOTYPE(int select_request_asynch, (struct filp *f, int *ops,
56 int block) );
57 FORWARD _PROTOTYPE(int select_major_match, (int match_major,
58 struct filp *file) );
59 FORWARD _PROTOTYPE(void select_cancel_all, (struct selectentry *e) );
60 FORWARD _PROTOTYPE(void select_wakeup, (struct selectentry *e, int r) );
61 FORWARD _PROTOTYPE(void select_return, (struct selectentry *, int) );
62 FORWARD _PROTOTYPE(void sel_restart_dev, (void) );
63 FORWARD _PROTOTYPE(int tab2ops, (int fd, struct selectentry *e) );
64 FORWARD _PROTOTYPE(void wipe_select, (struct selectentry *s) );
66 PRIVATE struct fdtype {
67 int (*select_request)(struct filp *, int *ops, int block);
68 int (*select_match)(struct filp *);
69 int select_major;
70 } fdtypes[] = {
71 { select_request_file, select_match_file, 0 },
72 { select_request_general, NULL, TTY_MAJOR },
73 { select_request_general, NULL, INET_MAJOR },
74 { select_request_pipe, select_match_pipe, 0 },
75 { select_request_asynch, NULL, LOG_MAJOR },
77 #define SEL_FDS (sizeof(fdtypes) / sizeof(fdtypes[0]))
79 /*===========================================================================*
80 * do_select *
81 *===========================================================================*/
82 PUBLIC int do_select(void)
84 /* Implement the select(nfds, readfds, writefds, errorfds, timeout) system
85 * call. First we copy the arguments and verify their sanity. Then we check
86 * whether there are file descriptors that satisfy the select call right of the
87 * bat. If so, or if there are no ready file descriptors but the process
88 * requested to return immediately, we return the result. Otherwise we set a
89 * timeout and wait for either the file descriptors to become ready or the
90 * timer to go off. If no timeout value was provided, we wait indefinitely. */
92 int r, nfds, do_timeout = 0, nonzero_timeout = 0, fd, s, fd_setsize;
93 struct timeval timeout;
94 struct selectentry *se;
96 nfds = m_in.SEL_NFDS;
98 /* Sane amount of file descriptors? */
99 if (nfds < 0 || nfds > OPEN_MAX) return(EINVAL);
100 fd_setsize = _FDSETWORDS(nfds) * _FDSETBITSPERWORD/8;
102 /* Find a slot to store this select request */
103 for (s = 0; s < MAXSELECTS; s++)
104 if (selecttab[s].requestor == NULL) /* Unused slot */
105 break;
106 if (s >= MAXSELECTS) return(ENOSPC);
108 se = &selecttab[s];
109 wipe_select(se); /* Clear results of previous usage.*/
110 se->req_endpt = who_e;
111 se->vir_readfds = (fd_set *) m_in.SEL_READFDS;
112 se->vir_writefds = (fd_set *) m_in.SEL_WRITEFDS;
113 se->vir_errorfds = (fd_set *) m_in.SEL_ERRORFDS;
115 /* Copy fdsets from the process */
116 if ((r = copy_fdsets(se, nfds, FROM_PROC)) != OK) return(r);
118 /* Did the process set a timeout value? If so, retrieve it. */
119 if (m_in.SEL_TIMEOUT != NULL) {
120 do_timeout = 1;
121 r = sys_vircopy(who_e, D, (vir_bytes) m_in.SEL_TIMEOUT, SELF, D,
122 (vir_bytes) &timeout, sizeof(timeout));
123 if (r != OK) return(r);
126 /* No nonsense in the timeval. */
127 if(do_timeout && (timeout.tv_sec < 0 || timeout.tv_usec < 0)) return(EINVAL);
129 /* If there is no timeout, we block forever. Otherwise, we block up to the
130 * specified time interval.
132 if(!do_timeout) /* No timeout value set */
133 se->block = 1;
134 else if (do_timeout && (timeout.tv_sec > 0 || timeout.tv_usec > 0))
135 se->block = 1;
136 else /* timeout set as (0,0) - this effects a poll */
137 se->block = 0;
138 se->expiry = 0; /* no timer set (yet) */
140 /* Check all file descriptors in the set whether one is 'ready' now. */
141 for (fd = 0; fd < nfds; fd++) {
142 int ops, t, type = -1, r;
143 struct filp *filp;
145 if (!(ops = tab2ops(fd, se)))
146 continue; /* No operations set; nothing to do for this fd */
148 /* Get filp belonging to this fd */
149 filp = se->filps[fd] = get_filp(fd);
150 if (filp == NIL_FILP) {
151 if (err_code == EBADF) {
152 select_cancel_all(se);
153 return(EBADF);
156 /* File descriptor is 'ready' to return EIO */
157 printf("VFS do_select: EIO after driver failure\n");
158 ops2tab(SEL_RD|SEL_WR|SEL_ERR, fd, se);
159 continue;
162 /* Figure out what type of file we're dealing with */
163 for(t = 0; t < SEL_FDS; t++) {
164 if (fdtypes[t].select_match) {
165 if (fdtypes[t].select_match(filp)) {
166 type = t;
168 } else if (select_major_match(fdtypes[t].select_major, filp)) {
169 type = t;
173 if (type == -1) return(EBADF);
174 se->type[fd] = type;
176 /* Test filp for select operations if not already done so. e.g., files
177 * sharing a filp and both doing a select on that filp. */
178 if ((se->filps[fd]->filp_select_ops & ops) != ops) {
179 int wantops;
181 wantops = (se->filps[fd]->filp_select_ops |= ops);
182 r = fdtypes[type].select_request(filp, &wantops, se->block);
183 if (r != SEL_OK) {
184 if (r == SEL_DEFERRED) {
185 se->deferred = TRUE;
186 se->deferred_fd = 0;
187 continue;
190 /* Error or bogus return code; cancel select. */
191 select_cancel_all(se);
192 return(EINVAL);
195 /* The select request above might have turned on/off some
196 * operations because they were 'ready' or not meaningful.
197 * Either way, we might have a result and we need to store them
198 * in the select table entry. */
199 if (wantops & ops) ops2tab(wantops, fd, se);
202 se->nfds = fd+1;
203 se->filps[fd]->filp_selectors++;
206 if (se->nreadyfds > 0 || (!se->block && !se->deferred)) {
207 /* fd's were found that were ready to go right away, and/or
208 * we were instructed not to block at all. Must return
209 * immediately.
211 r = copy_fdsets(se, se->nfds, TO_PROC);
212 select_cancel_all(se);
213 se->requestor = NULL;
215 if (r != OK) return(r);
216 else return(se->nreadyfds);
219 /* Convert timeval to ticks and set the timer. If it fails, undo
220 * all, return error.
222 if (do_timeout) {
223 int ticks;
224 /* Open Group:
225 * "If the requested timeout interval requires a finer
226 * granularity than the implementation supports, the
227 * actual timeout interval shall be rounded up to the next
228 * supported value."
230 #define USECPERSEC 1000000
231 while(timeout.tv_usec >= USECPERSEC) {
232 /* this is to avoid overflow with *system_hz below */
233 timeout.tv_usec -= USECPERSEC;
234 timeout.tv_sec++;
236 ticks = timeout.tv_sec * system_hz +
237 (timeout.tv_usec * system_hz + USECPERSEC-1) / USECPERSEC;
238 se->expiry = ticks;
239 fs_set_timer(&se->timer, ticks, select_timeout_check, s);
242 /* if we're blocking, the table entry is now valid. */
243 se->requestor = fp;
245 /* process now blocked */
246 suspend(FP_BLOCKED_ON_SELECT);
247 return(SUSPEND);
251 /*===========================================================================*
252 * select_request_file *
253 *===========================================================================*/
254 PRIVATE int select_request_file(struct filp *f, int *ops, int block)
256 /* output *ops is input *ops */
257 return(SEL_OK);
261 /*===========================================================================*
262 * select_match_file *
263 *===========================================================================*/
264 PRIVATE int select_match_file(struct filp *file)
266 return(file && file->filp_vno && (file->filp_vno->v_mode & I_REGULAR));
270 /*===========================================================================*
271 * select_request_general *
272 *===========================================================================*/
273 PRIVATE int select_request_general(struct filp *f, int *ops, int block)
275 int rops = *ops;
276 if (block) rops |= SEL_NOTIFY;
277 *ops = dev_io(VFS_DEV_SELECT, f->filp_vno->v_sdev, rops, NULL,
278 cvu64(0), 0, 0, FALSE);
279 if (*ops < 0)
280 return(SEL_ERR);
282 return(SEL_OK);
286 /*===========================================================================*
287 * select_request_asynch *
288 *===========================================================================*/
289 PRIVATE int select_request_asynch(struct filp *f, int *ops, int block)
291 int r, rops;
292 struct dmap *dp;
294 rops = *ops;
295 f->filp_select_flags |= FSF_UPDATE;
296 if (block) {
297 rops |= SEL_NOTIFY;
298 f->filp_select_flags |= FSF_BLOCK;
301 if (f->filp_select_flags & FSF_BUSY)
302 return(SEL_DEFERRED);
304 dp = &dmap[((f->filp_vno->v_sdev) >> MAJOR) & BYTE];
305 if (dp->dmap_sel_filp)
306 return(SEL_DEFERRED);
308 f->filp_select_flags &= ~FSF_UPDATE;
309 r = dev_io(VFS_DEV_SELECT, f->filp_vno->v_sdev, rops, NULL,
310 cvu64(0), 0, 0, FALSE);
311 if (r < 0 && r != SUSPEND)
312 return(SEL_ERR);
314 if (r != SUSPEND)
315 panic(__FILE__, "select_request_asynch: expected SUSPEND got", r);
317 f->filp_count++;
318 dp->dmap_sel_filp = f;
319 f->filp_select_flags |= FSF_BUSY;
321 return(SEL_DEFERRED);
325 /*===========================================================================*
326 * select_major_match *
327 *===========================================================================*/
328 PRIVATE int select_major_match(int match_major, struct filp *file)
330 int major;
331 if (!(file && file->filp_vno &&
332 (file->filp_vno->v_mode & I_TYPE) == I_CHAR_SPECIAL))
333 return(0);
334 major = (file->filp_vno->v_sdev >> MAJOR) & BYTE;
335 if (major == match_major) return 1;
336 return 0;
340 /*===========================================================================*
341 * tab2ops *
342 *===========================================================================*/
343 PRIVATE int tab2ops(int fd, struct selectentry *e)
345 int ops = 0;
346 if (FD_ISSET(fd, &e->readfds)) ops |= SEL_RD;
347 if (FD_ISSET(fd, &e->writefds)) ops |= SEL_WR;
348 if (FD_ISSET(fd, &e->errorfds)) ops |= SEL_ERR;
350 return(ops);
354 /*===========================================================================*
355 * ops2tab *
356 *===========================================================================*/
357 PRIVATE void ops2tab(int ops, int fd, struct selectentry *e)
359 if ((ops & SEL_RD) && e->vir_readfds && FD_ISSET(fd, &e->readfds) &&
360 !FD_ISSET(fd, &e->ready_readfds)) {
361 FD_SET(fd, &e->ready_readfds);
362 e->nreadyfds++;
365 if ((ops & SEL_WR) && e->vir_writefds && FD_ISSET(fd, &e->writefds) &&
366 !FD_ISSET(fd, &e->ready_writefds)) {
367 FD_SET(fd, &e->ready_writefds);
368 e->nreadyfds++;
371 if ((ops & SEL_ERR) && e->vir_errorfds && FD_ISSET(fd, &e->errorfds) &&
372 !FD_ISSET(fd, &e->ready_errorfds)) {
373 FD_SET(fd, &e->ready_errorfds);
374 e->nreadyfds++;
379 /*===========================================================================*
380 * copy_fdsets *
381 *===========================================================================*/
382 PRIVATE int copy_fdsets(struct selectentry *se, int nfds, int direction)
384 int fd_setsize, r;
385 endpoint_t src_e, dst_e;
386 fd_set *src_fds, *dst_fds;
388 if(nfds < 0 || nfds > OPEN_MAX)
389 panic(__FILE__, "select copy_fdsets: nfds wrong", nfds);
391 /* Only copy back as many bits as the user expects. */
392 fd_setsize = _FDSETWORDS(nfds) * _FDSETBITSPERWORD/8;
394 /* Set source and destination endpoints */
395 src_e = (direction == FROM_PROC) ? se->req_endpt : SELF;
396 dst_e = (direction == FROM_PROC) ? SELF : se->req_endpt;
398 /* read set */
399 src_fds = (direction == FROM_PROC) ? se->vir_readfds : &se->ready_readfds;
400 dst_fds = (direction == FROM_PROC) ? &se->readfds : se->vir_readfds;
401 if (se->vir_readfds) {
402 r = sys_vircopy(src_e, D, (vir_bytes) src_fds, dst_e, D,
403 (vir_bytes) dst_fds, fd_setsize);
404 if (r != OK) return(r);
407 /* write set */
408 src_fds = (direction == FROM_PROC) ? se->vir_writefds : &se->ready_writefds;
409 dst_fds = (direction == FROM_PROC) ? &se->writefds : se->vir_writefds;
410 if (se->vir_writefds) {
411 r = sys_vircopy(src_e, D, (vir_bytes) src_fds, dst_e, D,
412 (vir_bytes) dst_fds, fd_setsize);
413 if (r != OK) return(r);
416 /* error set */
417 src_fds = (direction == FROM_PROC) ? se->vir_errorfds : &se->ready_errorfds;
418 dst_fds = (direction == FROM_PROC) ? &se->errorfds : se->vir_errorfds;
419 if (se->vir_errorfds) {
420 r = sys_vircopy(src_e, D, (vir_bytes) src_fds, dst_e, D,
421 (vir_bytes) dst_fds, fd_setsize);
422 if (r != OK) return(r);
425 return(OK);
429 /*===========================================================================*
430 * select_cancel_all *
431 *===========================================================================*/
432 PRIVATE void select_cancel_all(struct selectentry *e)
434 int fd;
436 for(fd = 0; fd < e->nfds; fd++) {
437 struct filp *fp;
438 fp = e->filps[fd];
439 if (!fp) {
440 #if DEBUG_SELECT
441 printf("[ fd %d/%d NULL ] ", fd, e->nfds);
442 #endif
443 continue;
445 if (fp->filp_selectors < 1) {
446 #if DEBUG_SELECT
447 printf("select: %d selectors?!\n", fp->filp_selectors);
448 #endif
449 continue;
451 fp->filp_selectors--;
452 e->filps[fd] = NULL;
453 select_reevaluate(fp);
456 if (e->expiry > 0) {
457 #if DEBUG_SELECT
458 printf("cancelling timer %d\n", e - selecttab);
459 #endif
460 fs_cancel_timer(&e->timer);
461 e->expiry = 0;
464 return;
468 /*===========================================================================*
469 * select_wakeup *
470 *===========================================================================*/
471 PRIVATE void select_wakeup(struct selectentry *e, int r)
473 revive(e->req_endpt, r);
477 /*===========================================================================*
478 * select_reevaluate *
479 *===========================================================================*/
480 PRIVATE int select_reevaluate(struct filp *fp)
482 int s, remain_ops = 0, fd, type = -1;
484 if (!fp) {
485 printf("fs: select: reevalute NULL fp\n");
486 return 0;
489 for(s = 0; s < MAXSELECTS; s++) {
490 if (selecttab[s].requestor != NULL) continue;
492 for(fd = 0; fd < selecttab[s].nfds; fd++)
493 if (fp == selecttab[s].filps[fd]) {
494 remain_ops |= tab2ops(fd, &selecttab[s]);
495 type = selecttab[s].type[fd];
499 /* If there are any select()s open that want any operations on
500 * this fd that haven't been satisfied by this callback, then we're
501 * still in the market for it.
503 fp->filp_select_ops = remain_ops;
504 #if DEBUG_SELECT
505 printf("remaining operations on fp are %d\n", fp->filp_select_ops);
506 #endif
508 return remain_ops;
512 /*===========================================================================*
513 * select_return *
514 *===========================================================================*/
515 PRIVATE void select_return(struct selectentry *se, int r)
517 select_cancel_all(se);
518 copy_fdsets(se, se->nfds, TO_PROC); /* FIXME, return error status */
519 select_wakeup(se, r ? r : se->nreadyfds);
520 se->requestor = NULL;
524 /*===========================================================================*
525 * select_callback *
526 *===========================================================================*/
527 PUBLIC int select_callback(struct filp *fp, int ops)
529 int s, fd, want_ops, type;
531 /* We are being notified that file pointer fp is available for
532 * operations 'ops'. We must re-register the select for
533 * operations that we are still interested in, if any.
536 want_ops = 0;
537 type = -1;
538 for(s = 0; s < MAXSELECTS; s++) {
539 int wakehim = 0;
540 if (selecttab[s].requestor == NULL) continue;
542 for(fd = 0; fd < selecttab[s].nfds; fd++) {
543 if (!selecttab[s].filps[fd])
544 continue;
545 if (selecttab[s].filps[fd] == fp) {
546 int this_want_ops;
547 this_want_ops = tab2ops(fd, &selecttab[s]);
548 want_ops |= this_want_ops;
549 if (this_want_ops & ops) {
550 /* this select() has been satisfied. */
551 ops2tab(ops, fd, &selecttab[s]);
552 wakehim = 1;
554 type = selecttab[s].type[fd];
557 if (wakehim)
558 select_return(&selecttab[s], 0);
561 return 0;
565 /*===========================================================================*
566 * select_notified *
567 *===========================================================================*/
568 PUBLIC int select_notified(int major, int minor, int selected_ops)
570 int s, f, t;
572 #if DEBUG_SELECT
573 printf("select callback: %d, %d: %d\n", major, minor, selected_ops);
574 #endif
576 for(t = 0; t < SEL_FDS; t++)
577 if (!fdtypes[t].select_match && fdtypes[t].select_major == major)
578 break;
580 if (t >= SEL_FDS) {
581 #if DEBUG_SELECT
582 printf("select callback: no fdtype found for device %d\n", major);
583 #endif
584 return OK;
587 /* We have a select callback from major device no.
588 * d, which corresponds to our select type t.
591 for(s = 0; s < MAXSELECTS; s++) {
592 int s_minor, ops;
593 if (selecttab[s].requestor == NULL) continue;
594 for(f = 0; f < selecttab[s].nfds; f++) {
595 if (!selecttab[s].filps[f] ||
596 !select_major_match(major, selecttab[s].filps[f]))
597 continue;
598 ops = tab2ops(f, &selecttab[s]);
599 s_minor =
600 (selecttab[s].filps[f]->filp_vno->v_sdev >> MINOR)
601 & BYTE;
602 if ((s_minor == minor) &&
603 (selected_ops & ops)) {
604 select_callback(selecttab[s].filps[f], (selected_ops & ops));
609 return OK;
613 /*===========================================================================*
614 * init_select *
615 *===========================================================================*/
616 PUBLIC void init_select(void)
618 int s;
620 for(s = 0; s < MAXSELECTS; s++)
621 fs_init_timer(&selecttab[s].timer);
625 /*===========================================================================*
626 * select_forget *
627 *===========================================================================*/
628 PUBLIC void select_forget(int proc_e)
630 /* something has happened (e.g. signal delivered that interrupts
631 * select()). totally forget about the select().
633 int s;
635 for(s = 0; s < MAXSELECTS; s++) {
636 if (selecttab[s].requestor != NULL &&
637 selecttab[s].req_endpt == proc_e) {
638 break;
642 if (s >= MAXSELECTS) {
643 #if DEBUG_SELECT
644 printf("select: cancelled select() not found");
645 #endif
646 return;
649 select_cancel_all(&selecttab[s]);
650 selecttab[s].requestor = NULL;
652 return;
656 /*===========================================================================*
657 * select_timeout_check *
658 *===========================================================================*/
659 PUBLIC void select_timeout_check(timer_t *timer)
661 int s;
662 struct selectentry *se;
664 s = tmr_arg(timer)->ta_int;
665 if (s < 0 || s >= MAXSELECTS) {
666 #if DEBUG_SELECT
667 printf("select: bogus slot arg to watchdog %d\n", s);
668 #endif
669 return;
671 se = &selecttab[s]; /* Point to select table entry */
673 if (se->requestor == NULL) {
674 #if DEBUG_SELECT
675 printf("select: no requestor in watchdog\n");
676 #endif
677 return;
680 if (se->expiry <= 0) {
681 #if DEBUG_SELECT
682 printf("select: strange expiry value in watchdog\n", s);
683 #endif
684 return;
687 se->expiry = 0;
688 select_return(se, 0);
693 /*===========================================================================*
694 * select_unsuspend_by_endpt *
695 *===========================================================================*/
696 PUBLIC void select_unsuspend_by_endpt(endpoint_t proc_e)
698 int fd, s, maj;
700 for(s = 0; s < MAXSELECTS; s++) {
701 if (selecttab[s].requestor == NULL) continue;
703 for(fd = 0; fd < selecttab[s].nfds; fd++) {
704 if (selecttab[s].filps[fd] == NIL_FILP ||
705 selecttab[s].filps[fd]->filp_vno == NIL_VNODE) {
706 continue;
709 maj = (selecttab[s].filps[fd]->filp_vno->v_sdev >> MAJOR)&BYTE;
710 if (dmap_driver_match(proc_e, maj))
711 select_return(&selecttab[s], EAGAIN);
718 /*===========================================================================*
719 * select_reply1 *
720 *===========================================================================*/
721 PUBLIC void select_reply1()
723 int i, s, minor, status;
724 endpoint_t driver_e;
725 dev_t dev;
726 struct filp *fp;
727 struct dmap *dp;
728 struct vnode *vp;
730 driver_e= m_in.m_source;
731 minor= m_in.DEV_MINOR;
732 status= m_in.DEV_SEL_OPS;
734 /* Locate dmap entry */
735 for (i= 0, dp= dmap; i<NR_DEVICES; i++, dp++)
737 if (dp->dmap_driver == driver_e)
738 break;
740 if (i >= NR_DEVICES)
742 printf("select_reply1: proc %d is not a recoqnized driver\n",
743 driver_e);
744 return;
746 dev= (i << MAJOR) | (minor & BYTE);
748 fp= dp->dmap_sel_filp;
749 if (!fp)
751 printf("select_reply1: strange, no dmap_sel_filp\n");
752 return;
755 if (!(fp->filp_select_flags & FSF_BUSY))
756 panic(__FILE__, "select_reply1: strange, not FSF_BUSY", NO_NUM);
758 vp= fp->filp_vno;
759 if (!vp)
760 panic(__FILE__, "select_reply1: FSF_BUSY but no vp", NO_NUM);
762 if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL)
764 panic(__FILE__, "select_reply1: FSF_BUSY but not char special",
765 NO_NUM);
768 if (vp->v_sdev != dev)
770 printf("select_reply1: strange, reply from wrong dev\n");
771 return;
774 dp->dmap_sel_filp= NULL;
775 fp->filp_select_flags &= ~FSF_BUSY;
776 if (!(fp->filp_select_flags & (FSF_UPDATE|FSF_BLOCK)))
777 fp->filp_select_ops= 0;
778 if (status != 0)
780 if (status > 0)
782 /* Clear the replied bits from the request mask unless
783 * FSF_UPDATE is set.
785 if (!(fp->filp_select_flags & FSF_UPDATE))
786 fp->filp_select_ops &= ~status;
788 filp_status(fp, status);
790 if (fp->filp_count > 1)
791 fp->filp_count--;
792 else
794 if (fp->filp_count != 1)
796 panic(__FILE__, "select_reply1: bad filp_count",
797 fp->filp_count);
799 close_filp(fp);
801 sel_restart_dev();
805 /*===========================================================================*
806 * select_reply2 *
807 *===========================================================================*/
808 PUBLIC void select_reply2()
810 int i, s, minor, status;
811 endpoint_t driver_e;
812 dev_t dev;
813 struct filp *fp;
814 struct dmap *dp;
815 struct vnode *vp;
817 driver_e= m_in.m_source;
818 minor= m_in.DEV_MINOR;
819 status= m_in.DEV_SEL_OPS;
821 /* Locate dmap entry */
822 for (i= 0, dp= dmap; i<NR_DEVICES; i++, dp++)
824 if (dp->dmap_driver == driver_e)
825 break;
827 if (i >= NR_DEVICES)
829 printf("select_reply2: proc %d is not a recognized driver\n",
830 driver_e);
831 return;
833 dev= (i << MAJOR) | (minor & BYTE);
835 /* Find filedescriptors for this device */
836 for (s= 0; s<MAXSELECTS; s++)
838 if (selecttab[s].requestor == NULL)
839 continue; /* empty slot */
841 for (i= 0; i<OPEN_MAX; i++)
843 fp= selecttab[s].filps[i];
844 if (!fp)
845 continue;
846 vp= fp->filp_vno;
847 if (!vp)
848 continue;
849 if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL)
850 continue;
852 if (vp->v_sdev != dev)
853 continue;
855 if (status < 0)
857 printf("select_reply2: should handle error\n");
859 else
861 /* Clear the replied bits from the request
862 * mask unless FSF_UPDATE is set.
864 if (!(fp->filp_select_flags & FSF_UPDATE))
865 fp->filp_select_ops &= ~status;
866 ops2tab(status, i, &selecttab[s]);
869 if (selecttab[s].nreadyfds > 0)
870 restart_proc(s);
875 PRIVATE void sel_restart_dev()
877 int i, s;
878 struct filp *fp;
879 struct vnode *vp;
880 struct dmap *dp;
882 /* Locate filps that can be restarted */
883 for (s= 0; s<MAXSELECTS; s++)
885 if (selecttab[s].requestor == NULL)
886 continue; /* empty slot */
887 if (!selecttab[s].deferred)
888 continue; /* process is not waiting for an
889 * initial reply.
891 for (i= 0; i<OPEN_MAX; i++)
893 fp= selecttab[s].filps[i];
894 if (!fp)
895 continue;
896 if (fp->filp_select_flags & FSF_BUSY)
897 continue;
898 if (!(fp->filp_select_flags & FSF_UPDATE))
899 continue;
901 vp= fp->filp_vno;
902 if (!vp)
904 panic(__FILE__,
905 "sel_restart_dev: FSF_UPDATE but no vp",
906 NO_NUM);
908 if ((vp->v_mode & I_TYPE) != I_CHAR_SPECIAL)
910 panic(__FILE__,
911 "sel_restart_dev: FSF_UPDATE but not char special",
912 NO_NUM);
915 dp = &dmap[((vp->v_sdev) >> MAJOR) & BYTE];
916 if (dp->dmap_sel_filp)
917 continue;
919 printf(
920 "sel_restart_dev: should consider fd %d in slot %d\n",
921 i, s);
927 PRIVATE void filp_status(fp, status)
928 struct filp *fp;
929 int status;
931 int i, s;
933 /* Locate processes that need to know about this result */
934 for (s= 0; s<MAXSELECTS; s++)
936 if (selecttab[s].requestor == NULL) continue; /* empty slot */
938 for (i= 0; i<OPEN_MAX; i++)
940 if (selecttab[s].filps[i] != fp)
941 continue;
943 if (status < 0)
945 printf("filp_status: should handle error\n");
947 else
948 ops2tab(status, i, &selecttab[s]);
950 restart_proc(s);
956 PRIVATE void restart_proc(slot)
957 int slot;
959 int fd;
960 struct selectentry *se;
961 struct filp *fp;
963 se= &selecttab[slot];
964 if (se->deferred)
966 for (fd= se->deferred_fd; fd < OPEN_MAX; fd++)
968 fp= se->filps[fd];
969 if (!fp)
970 continue;
971 if (fp->filp_select_flags & (FSF_UPDATE|FSF_BUSY))
972 break;
974 if (fd < OPEN_MAX)
976 se->deferred_fd= fd;
977 return;
979 se->deferred= FALSE;
981 if (se->nreadyfds > 0 || !se->block) {
982 copy_fdsets(se, se->nfds, TO_PROC); /* FIXME, return error */
983 select_wakeup(se, se->nreadyfds);
984 se->requestor = NULL;
988 /*===========================================================================*
989 * wipe_select *
990 *===========================================================================*/
991 PRIVATE void wipe_select(struct selectentry *se)
993 se->deferred = FALSE;
994 se->nfds = 0;
995 se->nreadyfds = 0;
996 /* memset(se->filps, 0, OPEN_MAX * sizeof(struct filp *)); */
997 memset(se->filps, 0, sizeof(se->filps));
999 FD_ZERO(&se->readfds);
1000 FD_ZERO(&se->writefds);
1001 FD_ZERO(&se->errorfds);
1002 FD_ZERO(&se->ready_readfds);
1003 FD_ZERO(&se->ready_writefds);
1004 FD_ZERO(&se->ready_errorfds);