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
11 #include <sys/select.h>
13 #include <minix/com.h>
14 #include <minix/u64.h>
23 /* max. number of simultaneously pending select() calls */
28 static struct selectentry
{
29 struct fproc
*requestor
; /* slot is free iff this is NULL */
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
];
40 timer_t timer
; /* if expiry > 0 */
41 } selecttab
[MAXSELECTS
];
43 static int copy_fdsets(struct selectentry
*se
, int nfds
, int
45 static int do_select_request(struct selectentry
*se
, int fd
, int *ops
);
46 static void filp_status(struct filp
*fp
, int status
);
47 static int is_deferred(struct selectentry
*se
);
48 static void restart_proc(struct selectentry
*se
);
49 static void ops2tab(int ops
, int fd
, struct selectentry
*e
);
50 static int is_regular_file(struct filp
*f
);
51 static int is_pipe(struct filp
*f
);
52 static int is_supported_major(struct filp
*f
);
53 static void select_lock_filp(struct filp
*f
, int ops
);
54 static int select_request_async(struct filp
*f
, int *ops
, int block
);
55 static int select_request_file(struct filp
*f
, int *ops
, int block
);
56 static int select_request_major(struct filp
*f
, int *ops
, int block
);
57 static int select_request_pipe(struct filp
*f
, int *ops
, int block
);
58 static int select_request_sync(struct filp
*f
, int *ops
, int block
);
59 static void select_cancel_all(struct selectentry
*e
);
60 static void select_cancel_filp(struct filp
*f
);
61 static void select_return(struct selectentry
*);
62 static void select_restart_filps(void);
63 static int tab2ops(int fd
, struct selectentry
*e
);
64 static void wipe_select(struct selectentry
*s
);
66 static struct fdtype
{
67 int (*select_request
)(struct filp
*, int *ops
, int block
);
68 int (*type_match
)(struct filp
*f
);
70 { select_request_major
, is_supported_major
},
71 { select_request_file
, is_regular_file
},
72 { select_request_pipe
, is_pipe
},
74 #define SEL_FDS (sizeof(fdtypes) / sizeof(fdtypes[0]))
75 static int select_majors
[] = { /* List of majors that support selecting on */
81 #define SEL_MAJORS (sizeof(select_majors) / sizeof(select_majors[0]))
83 /*===========================================================================*
85 *===========================================================================*/
88 /* Implement the select(nfds, readfds, writefds, errorfds, timeout) system
89 * call. First we copy the arguments and verify their sanity. Then we check
90 * whether there are file descriptors that satisfy the select call right of the
91 * bat. If so, or if there are no ready file descriptors but the process
92 * requested to return immediately, we return the result. Otherwise we set a
93 * timeout and wait for either the file descriptors to become ready or the
94 * timer to go off. If no timeout value was provided, we wait indefinitely. */
96 int r
, nfds
, do_timeout
= 0, fd
, s
;
97 struct timeval timeout
;
98 struct selectentry
*se
;
101 nfds
= job_m_in
.SEL_NFDS
;
102 vtimeout
= (vir_bytes
) job_m_in
.SEL_TIMEOUT
;
104 /* Sane amount of file descriptors? */
105 if (nfds
< 0 || nfds
> OPEN_MAX
) return(EINVAL
);
107 /* Find a slot to store this select request */
108 for (s
= 0; s
< MAXSELECTS
; s
++)
109 if (selecttab
[s
].requestor
== NULL
) /* Unused slot */
111 if (s
>= MAXSELECTS
) return(ENOSPC
);
114 wipe_select(se
); /* Clear results of previous usage */
116 se
->req_endpt
= who_e
;
117 se
->vir_readfds
= (fd_set
*) job_m_in
.SEL_READFDS
;
118 se
->vir_writefds
= (fd_set
*) job_m_in
.SEL_WRITEFDS
;
119 se
->vir_errorfds
= (fd_set
*) job_m_in
.SEL_ERRORFDS
;
121 /* Copy fdsets from the process */
122 if ((r
= copy_fdsets(se
, nfds
, FROM_PROC
)) != OK
) {
123 se
->requestor
= NULL
;
127 /* Did the process set a timeout value? If so, retrieve it. */
130 r
= sys_vircopy(who_e
, (vir_bytes
) vtimeout
, SELF
,
131 (vir_bytes
) &timeout
, sizeof(timeout
));
133 se
->requestor
= NULL
;
138 /* No nonsense in the timeval */
139 if (do_timeout
&& (timeout
.tv_sec
< 0 || timeout
.tv_usec
< 0)) {
140 se
->requestor
= NULL
;
144 /* If there is no timeout, we block forever. Otherwise, we block up to the
145 * specified time interval.
147 if (!do_timeout
) /* No timeout value set */
149 else if (do_timeout
&& (timeout
.tv_sec
> 0 || timeout
.tv_usec
> 0))
151 else /* timeout set as (0,0) - this effects a poll */
153 se
->expiry
= 0; /* no timer set (yet) */
155 /* Verify that file descriptors are okay to select on */
156 for (fd
= 0; fd
< nfds
; fd
++) {
158 unsigned int type
, ops
;
160 /* Because the select() interface implicitly includes file descriptors
161 * you might not want to select on, we have to figure out whether we're
162 * interested in them. Typically, these file descriptors include fd's
163 * inherited from the parent proc and file descriptors that have been
164 * close()d, but had a lower fd than one in the current set.
166 if (!(ops
= tab2ops(fd
, se
)))
167 continue; /* No operations set; nothing to do for this fd */
169 /* Get filp belonging to this fd */
170 f
= se
->filps
[fd
] = get_filp(fd
, VNODE_READ
);
172 if (err_code
== EBADF
)
174 else /* File descriptor is 'ready' to return EIO */
177 se
->requestor
= NULL
;
181 /* Check file types. According to POSIX 2008:
182 * "The pselect() and select() functions shall support regular files,
183 * terminal and pseudo-terminal devices, FIFOs, pipes, and sockets. The
184 * behavior of pselect() and select() on file descriptors that refer to
185 * other types of file is unspecified."
187 * In our case, terminal and pseudo-terminal devices are handled by the
188 * TTY major and sockets by either INET major (socket type AF_INET) or
189 * PFS major (socket type AF_UNIX). PFS acts as an FS when it handles
190 * pipes and as a driver when it handles sockets. Additionally, we
191 * support select on the LOG major to handle kernel logging, which is
192 * beyond the POSIX spec. */
195 for (type
= 0; type
< SEL_FDS
; type
++) {
196 if (fdtypes
[type
].type_match(f
)) {
199 se
->filps
[fd
]->filp_selectors
++;
204 if (se
->type
[fd
] == -1) { /* Type not found */
205 se
->requestor
= NULL
;
210 /* Check all file descriptors in the set whether one is 'ready' now */
211 for (fd
= 0; fd
< nfds
; fd
++) {
215 /* Again, check for involuntarily selected fd's */
216 if (!(ops
= tab2ops(fd
, se
)))
217 continue; /* No operations set; nothing to do for this fd */
219 /* Test filp for select operations if not already done so. e.g.,
220 * processes sharing a filp and both doing a select on that filp. */
222 if ((f
->filp_select_ops
& ops
) != ops
) {
225 wantops
= (f
->filp_select_ops
|= ops
);
226 r
= do_select_request(se
, fd
, &wantops
);
227 if (r
!= OK
&& r
!= SUSPEND
)
228 break; /* Error or bogus return code; abort */
230 /* The select request above might have turned on/off some
231 * operations because they were 'ready' or not meaningful.
232 * Either way, we might have a result and we need to store them
233 * in the select table entry. */
234 if (wantops
& ops
) ops2tab(wantops
, fd
, se
);
238 if ((se
->nreadyfds
> 0 || !se
->block
) && !is_deferred(se
)) {
239 /* fd's were found that were ready to go right away, and/or
240 * we were instructed not to block at all. Must return
243 r
= copy_fdsets(se
, se
->nfds
, TO_PROC
);
244 select_cancel_all(se
);
245 se
->requestor
= NULL
;
249 else if (se
->error
!= OK
)
252 return(se
->nreadyfds
);
255 /* Convert timeval to ticks and set the timer. If it fails, undo
261 * "If the requested timeout interval requires a finer
262 * granularity than the implementation supports, the
263 * actual timeout interval shall be rounded up to the next
266 #define USECPERSEC 1000000
267 while(timeout
.tv_usec
>= USECPERSEC
) {
268 /* this is to avoid overflow with *system_hz below */
269 timeout
.tv_usec
-= USECPERSEC
;
272 ticks
= timeout
.tv_sec
* system_hz
+
273 (timeout
.tv_usec
* system_hz
+ USECPERSEC
-1) / USECPERSEC
;
275 set_timer(&se
->timer
, ticks
, select_timeout_check
, s
);
278 /* process now blocked */
279 suspend(FP_BLOCKED_ON_SELECT
);
283 /*===========================================================================*
285 *===========================================================================*/
286 static int is_deferred(struct selectentry
*se
)
288 /* Find out whether this select has pending initial replies */
293 for (fd
= 0; fd
< se
->nfds
; fd
++) {
294 if ((f
= se
->filps
[fd
]) == NULL
) continue;
295 if (f
->filp_select_flags
& (FSF_UPDATE
|FSF_BUSY
)) return(TRUE
);
302 /*===========================================================================*
304 *===========================================================================*/
305 static int is_regular_file(struct filp
*f
)
307 return(f
&& f
->filp_vno
&& S_ISREG(f
->filp_vno
->v_mode
));
310 /*===========================================================================*
312 *===========================================================================*/
313 static int is_pipe(struct filp
*f
)
315 /* Recognize either anonymous pipe or named pipe (FIFO) */
316 return(f
&& f
->filp_vno
&& S_ISFIFO(f
->filp_vno
->v_mode
));
319 /*===========================================================================*
320 * is_supported_major *
321 *===========================================================================*/
322 static int is_supported_major(struct filp
*f
)
324 /* See if this filp is a handle on a device on which we support select() */
327 if (!(f
&& f
->filp_vno
)) return(FALSE
);
328 if (!S_ISCHR(f
->filp_vno
->v_mode
)) return(FALSE
);
330 for (m
= 0; m
< SEL_MAJORS
; m
++)
331 if (major(f
->filp_vno
->v_sdev
) == select_majors
[m
])
337 /*===========================================================================*
338 * select_request_async *
339 *===========================================================================*/
340 static int select_request_async(struct filp
*f
, int *ops
, int block
)
347 /* By default, nothing to do */
350 if (!block
&& (f
->filp_select_flags
& FSF_BLOCKED
)) {
351 /* This filp is blocked waiting for a reply, but we don't want to
352 * block ourselves. Unless we're awaiting the initial reply, these
353 * operations won't be ready */
354 if (!(f
->filp_select_flags
& FSF_BUSY
)) {
355 if ((rops
& SEL_RD
) && (f
->filp_select_flags
& FSF_RD_BLOCK
))
357 if ((rops
& SEL_WR
) && (f
->filp_select_flags
& FSF_WR_BLOCK
))
359 if ((rops
& SEL_ERR
) && (f
->filp_select_flags
& FSF_ERR_BLOCK
))
361 if (!(rops
& (SEL_RD
|SEL_WR
|SEL_ERR
)))
366 f
->filp_select_flags
|= FSF_UPDATE
;
369 if (rops
& SEL_RD
) f
->filp_select_flags
|= FSF_RD_BLOCK
;
370 if (rops
& SEL_WR
) f
->filp_select_flags
|= FSF_WR_BLOCK
;
371 if (rops
& SEL_ERR
) f
->filp_select_flags
|= FSF_ERR_BLOCK
;
374 if (f
->filp_select_flags
& FSF_BUSY
)
377 major
= major(f
->filp_vno
->v_sdev
);
378 if (major
< 0 || major
>= NR_DEVICES
) return(ENXIO
);
380 if (dp
->dmap_sel_filp
)
383 f
->filp_select_flags
&= ~FSF_UPDATE
;
384 r
= dev_io(VFS_DEV_SELECT
, f
->filp_vno
->v_sdev
, rops
, NULL
,
385 cvu64(0), 0, 0, FALSE
);
386 if (r
< 0 && r
!= SUSPEND
)
390 panic("select_request_asynch: expected SUSPEND got: %d", r
);
392 dp
->dmap_sel_filp
= f
;
393 f
->filp_select_flags
|= FSF_BUSY
;
398 /*===========================================================================*
399 * select_request_file *
400 *===========================================================================*/
401 static int select_request_file(struct filp
*UNUSED(f
), int *UNUSED(ops
),
404 /* Files are always ready, so output *ops is input *ops */
408 /*===========================================================================*
409 * select_request_major *
410 *===========================================================================*/
411 static int select_request_major(struct filp
*f
, int *ops
, int block
)
415 major
= major(f
->filp_vno
->v_sdev
);
416 if (major
< 0 || major
>= NR_DEVICES
) return(ENXIO
);
418 if (dmap
[major
].dmap_style
== STYLE_DEVA
||
419 dmap
[major
].dmap_style
== STYLE_CLONE_A
)
420 r
= select_request_async(f
, ops
, block
);
422 r
= select_request_sync(f
, ops
, block
);
427 /*===========================================================================*
428 * select_request_sync *
429 *===========================================================================*/
430 static int select_request_sync(struct filp
*f
, int *ops
, int block
)
435 if (block
) rops
|= SEL_NOTIFY
;
436 *ops
= dev_io(VFS_DEV_SELECT
, f
->filp_vno
->v_sdev
, rops
, NULL
,
437 cvu64(0), 0, 0, FALSE
);
444 /*===========================================================================*
445 * select_request_pipe *
446 *===========================================================================*/
447 static int select_request_pipe(struct filp
*f
, int *ops
, int block
)
449 int orig_ops
, r
= 0, err
;
453 if ((*ops
& (SEL_RD
|SEL_ERR
))) {
454 err
= pipe_check(f
->filp_vno
, READING
, 0, 1, f
->filp_pos
, 1);
458 if (err
< 0 && err
!= SUSPEND
)
460 if (err
== SUSPEND
&& !(f
->filp_mode
& R_BIT
)) {
461 /* A "meaningless" read select, therefore ready
462 * for reading and no error set. */
468 if ((*ops
& (SEL_WR
|SEL_ERR
))) {
469 err
= pipe_check(f
->filp_vno
, WRITING
, 0, 1, f
->filp_pos
, 1);
473 if (err
< 0 && err
!= SUSPEND
)
475 if (err
== SUSPEND
&& !(f
->filp_mode
& W_BIT
)) {
476 /* A "meaningless" write select, therefore ready
477 for writing and no error set. */
483 /* Some options we collected might not be requested. */
487 f
->filp_pipe_select_ops
|= orig_ops
;
492 /*===========================================================================*
494 *===========================================================================*/
495 static int tab2ops(int fd
, struct selectentry
*e
)
498 if (FD_ISSET(fd
, &e
->readfds
)) ops
|= SEL_RD
;
499 if (FD_ISSET(fd
, &e
->writefds
)) ops
|= SEL_WR
;
500 if (FD_ISSET(fd
, &e
->errorfds
)) ops
|= SEL_ERR
;
506 /*===========================================================================*
508 *===========================================================================*/
509 static void ops2tab(int ops
, int fd
, struct selectentry
*e
)
511 if ((ops
& SEL_RD
) && e
->vir_readfds
&& FD_ISSET(fd
, &e
->readfds
) &&
512 !FD_ISSET(fd
, &e
->ready_readfds
)) {
513 FD_SET(fd
, &e
->ready_readfds
);
517 if ((ops
& SEL_WR
) && e
->vir_writefds
&& FD_ISSET(fd
, &e
->writefds
) &&
518 !FD_ISSET(fd
, &e
->ready_writefds
)) {
519 FD_SET(fd
, &e
->ready_writefds
);
523 if ((ops
& SEL_ERR
) && e
->vir_errorfds
&& FD_ISSET(fd
, &e
->errorfds
) &&
524 !FD_ISSET(fd
, &e
->ready_errorfds
)) {
525 FD_SET(fd
, &e
->ready_errorfds
);
531 /*===========================================================================*
533 *===========================================================================*/
534 static int copy_fdsets(struct selectentry
*se
, int nfds
, int direction
)
538 endpoint_t src_e
, dst_e
;
539 fd_set
*src_fds
, *dst_fds
;
541 if (nfds
< 0 || nfds
> OPEN_MAX
)
542 panic("select copy_fdsets: nfds wrong: %d", nfds
);
544 /* Only copy back as many bits as the user expects. */
546 fd_setsize
= (size_t) (howmany(nfds
, __NFDBITS
) * sizeof(__fd_mask
));
548 fd_setsize
= (size_t) (_FDSETWORDS(nfds
) * _FDSETBITSPERWORD
/8);
551 /* Set source and destination endpoints */
552 src_e
= (direction
== FROM_PROC
) ? se
->req_endpt
: SELF
;
553 dst_e
= (direction
== FROM_PROC
) ? SELF
: se
->req_endpt
;
556 src_fds
= (direction
== FROM_PROC
) ? se
->vir_readfds
: &se
->ready_readfds
;
557 dst_fds
= (direction
== FROM_PROC
) ? &se
->readfds
: se
->vir_readfds
;
558 if (se
->vir_readfds
) {
559 r
= sys_vircopy(src_e
, (vir_bytes
) src_fds
, dst_e
,
560 (vir_bytes
) dst_fds
, fd_setsize
);
561 if (r
!= OK
) return(r
);
565 src_fds
= (direction
== FROM_PROC
) ? se
->vir_writefds
: &se
->ready_writefds
;
566 dst_fds
= (direction
== FROM_PROC
) ? &se
->writefds
: se
->vir_writefds
;
567 if (se
->vir_writefds
) {
568 r
= sys_vircopy(src_e
, (vir_bytes
) src_fds
, dst_e
,
569 (vir_bytes
) dst_fds
, fd_setsize
);
570 if (r
!= OK
) return(r
);
574 src_fds
= (direction
== FROM_PROC
) ? se
->vir_errorfds
: &se
->ready_errorfds
;
575 dst_fds
= (direction
== FROM_PROC
) ? &se
->errorfds
: se
->vir_errorfds
;
576 if (se
->vir_errorfds
) {
577 r
= sys_vircopy(src_e
, (vir_bytes
) src_fds
, dst_e
,
578 (vir_bytes
) dst_fds
, fd_setsize
);
579 if (r
!= OK
) return(r
);
586 /*===========================================================================*
587 * select_cancel_all *
588 *===========================================================================*/
589 static void select_cancel_all(struct selectentry
*se
)
591 /* Cancel select. Decrease select usage and cancel timer */
596 for (fd
= 0; fd
< se
->nfds
; fd
++) {
597 if ((f
= se
->filps
[fd
]) == NULL
) continue;
598 se
->filps
[fd
] = NULL
;
599 select_cancel_filp(f
);
602 if (se
->expiry
> 0) {
603 cancel_timer(&se
->timer
);
607 se
->requestor
= NULL
;
610 /*===========================================================================*
611 * select_cancel_filp *
612 *===========================================================================*/
613 static void select_cancel_filp(struct filp
*f
)
615 /* Reduce number of select users of this filp */
618 assert(f
->filp_selectors
>= 0);
619 if (f
->filp_selectors
== 0) return;
620 if (f
->filp_count
== 0) return;
622 select_lock_filp(f
, f
->filp_select_ops
);
625 if (f
->filp_selectors
== 0) {
626 /* No one selecting on this filp anymore, forget about select state */
627 f
->filp_select_ops
= 0;
628 f
->filp_select_flags
= 0;
629 f
->filp_pipe_select_ops
= 0;
635 /*===========================================================================*
637 *===========================================================================*/
638 static void select_return(struct selectentry
*se
)
642 assert(!is_deferred(se
)); /* Not done yet, first wait for async reply */
644 select_cancel_all(se
);
646 r1
= copy_fdsets(se
, se
->nfds
, TO_PROC
);
649 else if (se
->error
!= OK
)
654 revive(se
->req_endpt
, r
);
658 /*===========================================================================*
660 *===========================================================================*/
661 void select_callback(struct filp
*f
, int status
)
663 filp_status(f
, status
);
666 /*===========================================================================*
668 *===========================================================================*/
669 void init_select(void)
673 for (s
= 0; s
< MAXSELECTS
; s
++)
674 init_timer(&selecttab
[s
].timer
);
678 /*===========================================================================*
680 *===========================================================================*/
681 void select_forget(endpoint_t proc_e
)
683 /* Something has happened (e.g. signal delivered that interrupts select()).
684 * Totally forget about the select(). */
687 struct selectentry
*se
;
689 for (slot
= 0; slot
< MAXSELECTS
; slot
++) {
690 se
= &selecttab
[slot
];
691 if (se
->requestor
!= NULL
&& se
->req_endpt
== proc_e
)
695 if (slot
>= MAXSELECTS
) return; /* Entry not found */
697 if (is_deferred(se
)) return; /* Still awaiting initial reply */
699 select_cancel_all(se
);
703 /*===========================================================================*
704 * select_timeout_check *
705 *===========================================================================*/
706 void select_timeout_check(timer_t
*timer
)
709 struct selectentry
*se
;
711 s
= tmr_arg(timer
)->ta_int
;
712 if (s
< 0 || s
>= MAXSELECTS
) return; /* Entry does not exist */
715 if (se
->requestor
== NULL
) return;
717 if (se
->expiry
<= 0) return; /* Strange, did we even ask for a timeout? */
719 if (is_deferred(se
)) return; /* Wait for initial replies to DEV_SELECT */
724 /*===========================================================================*
725 * select_unsuspend_by_endpt *
726 *===========================================================================*/
727 void select_unsuspend_by_endpt(endpoint_t proc_e
)
729 /* Revive blocked processes when a driver has disappeared */
732 struct selectentry
*se
;
735 for (s
= 0; s
< MAXSELECTS
; s
++) {
738 if (se
->requestor
== NULL
) continue;
739 if (se
->requestor
->fp_endpoint
== proc_e
) {
740 assert(se
->requestor
->fp_flags
& FP_EXITING
);
741 select_cancel_all(se
);
745 for (fd
= 0; fd
< se
->nfds
; fd
++) {
746 if ((f
= se
->filps
[fd
]) == NULL
|| f
->filp_vno
== NULL
)
749 major
= major(f
->filp_vno
->v_sdev
);
750 if (dmap_driver_match(proc_e
, major
)) {
751 se
->filps
[fd
] = NULL
;
753 select_cancel_filp(f
);
758 if (wakehim
&& !is_deferred(se
))
763 /*===========================================================================*
765 *===========================================================================*/
766 void select_reply1(driver_e
, minor
, status
)
771 /* Handle reply to DEV_SELECT request */
779 /* Figure out which device is replying */
780 if ((dp
= get_dmap(driver_e
)) == NULL
) return;
783 dev
= makedev(major
, minor
);
785 /* Get filp belonging to character special file */
786 if ((f
= dp
->dmap_sel_filp
) == NULL
) {
787 printf("VFS (%s:%d): major %d was not expecting a DEV_SELECT reply\n",
788 __FILE__
, __LINE__
, major
);
792 /* Is the filp still in use and busy waiting for a reply? The owner might
793 * have vanished before the driver was able to reply. */
794 if (f
->filp_count
>= 1 && (f
->filp_select_flags
& FSF_BUSY
)) {
795 /* Find vnode and check we got a reply from the device we expected */
798 assert(S_ISCHR(vp
->v_mode
));
799 if (vp
->v_sdev
!= dev
) {
800 printf("VFS (%s:%d): expected reply from dev %d not %d\n",
801 __FILE__
, __LINE__
, vp
->v_sdev
, dev
);
806 /* No longer waiting for a reply from this device */
807 dp
->dmap_sel_filp
= NULL
;
809 /* Process select result only if requestor is still around. That is, the
810 * corresponding filp is still in use.
812 if (f
->filp_count
>= 1) {
813 select_lock_filp(f
, f
->filp_select_ops
);
814 f
->filp_select_flags
&= ~FSF_BUSY
;
816 /* The select call is done now, except when
817 * - another process started a select on the same filp with possibly a
818 * different set of operations.
819 * - a process does a select on the same filp but using different file
821 * - the select has a timeout. Upon receiving this reply the operations
822 * might not be ready yet, so we want to wait for that to ultimately
824 * Therefore we need to keep remembering what the operations are.
826 if (!(f
->filp_select_flags
& (FSF_UPDATE
|FSF_BLOCKED
)))
827 f
->filp_select_ops
= 0; /* done selecting */
828 else if (!(f
->filp_select_flags
& FSF_UPDATE
))
829 /* there may be operations pending */
830 f
->filp_select_ops
&= ~status
;
832 /* Record new filp status */
833 if (!(status
== 0 && (f
->filp_select_flags
& FSF_BLOCKED
))) {
834 if (status
> 0) { /* operations ready */
836 f
->filp_select_flags
&= ~FSF_RD_BLOCK
;
838 f
->filp_select_flags
&= ~FSF_WR_BLOCK
;
839 if (status
& SEL_ERR
)
840 f
->filp_select_flags
&= ~FSF_ERR_BLOCK
;
841 } else if (status
< 0) { /* error */
842 /* Always unblock upon error */
843 f
->filp_select_flags
&= ~FSF_BLOCKED
;
848 filp_status(f
, status
); /* Tell filp owners about the results */
851 select_restart_filps();
855 /*===========================================================================*
857 *===========================================================================*/
858 void select_reply2(driver_e
, minor
, status
)
863 /* Handle secondary reply to DEV_SELECT request. A secondary reply occurs when
864 * the select request is 'blocking' until an operation becomes ready. */
870 struct selectentry
*se
;
873 printf("VFS (%s:%d): weird status (%d) to report\n",
874 __FILE__
, __LINE__
, status
);
878 /* Figure out which device is replying */
879 if ((dp
= get_dmap(driver_e
)) == NULL
) {
880 printf("VFS (%s:%d): endpoint %d is not a known driver endpoint\n",
881 __FILE__
, __LINE__
, driver_e
);
885 dev
= makedev(major
, minor
);
887 /* Find all file descriptors selecting for this device */
888 for (slot
= 0; slot
< MAXSELECTS
; slot
++) {
889 se
= &selecttab
[slot
];
890 if (se
->requestor
== NULL
) continue; /* empty slot */
892 for (fd
= 0; fd
< se
->nfds
; fd
++) {
893 if ((f
= se
->filps
[fd
]) == NULL
) continue;
894 if ((vp
= f
->filp_vno
) == NULL
) continue;
895 if (!S_ISCHR(vp
->v_mode
)) continue;
896 if (vp
->v_sdev
!= dev
) continue;
898 select_lock_filp(f
, f
->filp_select_ops
);
899 if (status
> 0) { /* Operations ready */
900 /* Clear the replied bits from the request
901 * mask unless FSF_UPDATE is set.
903 if (!(f
->filp_select_flags
& FSF_UPDATE
))
904 f
->filp_select_ops
&= ~status
;
906 f
->filp_select_flags
&= ~FSF_RD_BLOCK
;
908 f
->filp_select_flags
&= ~FSF_WR_BLOCK
;
909 if (status
& SEL_ERR
)
910 f
->filp_select_flags
&= ~FSF_ERR_BLOCK
;
912 ops2tab(status
, fd
, se
);
914 f
->filp_select_flags
&= ~FSF_BLOCKED
;
915 ops2tab(SEL_RD
|SEL_WR
|SEL_ERR
, fd
, se
);
918 if (se
->nreadyfds
> 0) restart_proc(se
);
922 select_restart_filps();
925 /*===========================================================================*
926 * select_restart_filps *
927 *===========================================================================*/
928 static void select_restart_filps()
933 struct selectentry
*se
;
935 /* Locate filps that can be restarted */
936 for (slot
= 0; slot
< MAXSELECTS
; slot
++) {
937 se
= &selecttab
[slot
];
938 if (se
->requestor
== NULL
) continue; /* empty slot */
940 /* Only 'deferred' processes are eligible to restart */
941 if (!is_deferred(se
)) continue;
943 /* Find filps that are not waiting for a reply, but have an updated
944 * status (i.e., another select on the same filp with possibly a
945 * different set of operations is to be done), and thus requires the
946 * select request to be sent again).
948 for (fd
= 0; fd
< se
->nfds
; fd
++) {
950 if ((f
= se
->filps
[fd
]) == NULL
) continue;
951 if (f
->filp_select_flags
& FSF_BUSY
) /* Still waiting for */
952 continue; /* initial reply */
953 if (!(f
->filp_select_flags
& FSF_UPDATE
)) /* Must be in */
954 continue; /* 'update' state */
956 wantops
= ops
= f
->filp_select_ops
;
958 assert(S_ISCHR(vp
->v_mode
));
959 r
= do_select_request(se
, fd
, &wantops
);
960 if (r
!= OK
&& r
!= SUSPEND
)
961 break; /* Error or bogus return code; abort */
962 if (wantops
& ops
) ops2tab(wantops
, fd
, se
);
967 /*===========================================================================*
968 * do_select_request *
969 *===========================================================================*/
970 static int do_select_request(se
, fd
, ops
)
971 struct selectentry
*se
;
975 /* Perform actual select request for file descriptor fd */
982 select_lock_filp(f
, *ops
);
983 r
= fdtypes
[type
].select_request(f
, ops
, se
->block
);
985 if (r
!= OK
&& r
!= SUSPEND
) {
987 se
->block
= 0; /* Stop blocking to return asap */
988 if (!is_deferred(se
)) select_cancel_all(se
);
994 /*===========================================================================*
996 *===========================================================================*/
997 static void filp_status(f
, status
)
1001 /* Tell processes that need to know about the status of this filp */
1003 struct selectentry
*se
;
1005 for (slot
= 0; slot
< MAXSELECTS
; slot
++) {
1006 se
= &selecttab
[slot
];
1007 if (se
->requestor
== NULL
) continue; /* empty slot */
1009 for (fd
= 0; fd
< se
->nfds
; fd
++) {
1010 if (se
->filps
[fd
] != f
) continue;
1012 ops2tab(SEL_RD
|SEL_WR
|SEL_ERR
, fd
, se
);
1014 ops2tab(status
, fd
, se
);
1020 /*===========================================================================*
1022 *===========================================================================*/
1023 static void restart_proc(se
)
1024 struct selectentry
*se
;
1026 /* Tell process about select results (if any) unless there are still results
1029 if ((se
->nreadyfds
> 0 || !se
->block
) && !is_deferred(se
))
1033 /*===========================================================================*
1035 *===========================================================================*/
1036 static void wipe_select(struct selectentry
*se
)
1042 memset(se
->filps
, 0, sizeof(se
->filps
));
1044 FD_ZERO(&se
->readfds
);
1045 FD_ZERO(&se
->writefds
);
1046 FD_ZERO(&se
->errorfds
);
1047 FD_ZERO(&se
->ready_readfds
);
1048 FD_ZERO(&se
->ready_writefds
);
1049 FD_ZERO(&se
->ready_errorfds
);
1052 /*===========================================================================*
1053 * select_lock_filp *
1054 *===========================================================================*/
1055 static void select_lock_filp(struct filp
*f
, int ops
)
1057 /* Lock a filp and vnode based on which operations are requested */
1058 tll_access_t locktype
;;
1060 locktype
= VNODE_READ
; /* By default */
1062 if (ops
& (SEL_WR
|SEL_ERR
))
1063 /* Selecting for error or writing requires exclusive access */
1064 locktype
= VNODE_WRITE
;
1066 lock_filp(f
, locktype
);