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
10 #include <sys/fcntl.h>
12 #include <sys/select.h>
14 #include <minix/com.h>
15 #include <minix/u64.h>
24 /* max. number of simultaneously pending select() calls */
29 static struct selectentry
{
30 struct fproc
*requestor
; /* slot is free iff this is NULL */
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
];
41 timer_t timer
; /* if expiry > 0 */
42 } selecttab
[MAXSELECTS
];
44 static int copy_fdsets(struct selectentry
*se
, int nfds
, int
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
);
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 */
82 #define SEL_MAJORS (sizeof(select_majors) / sizeof(select_majors[0]))
84 /*===========================================================================*
86 *===========================================================================*/
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
;
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 */
112 if (s
>= MAXSELECTS
) return(ENOSPC
);
115 wipe_select(se
); /* Clear results of previous usage */
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
;
128 /* Did the process set a timeout value? If so, retrieve it. */
131 r
= sys_vircopy(who_e
, (vir_bytes
) vtimeout
, SELF
,
132 (vir_bytes
) &timeout
, sizeof(timeout
));
134 se
->requestor
= NULL
;
139 /* No nonsense in the timeval */
140 if (do_timeout
&& (timeout
.tv_sec
< 0 || timeout
.tv_usec
< 0)) {
141 se
->requestor
= NULL
;
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 */
150 else if (do_timeout
&& (timeout
.tv_sec
> 0 || timeout
.tv_usec
> 0))
152 else /* timeout set as (0,0) - this effects a poll */
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
++) {
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
);
173 if (err_code
== EBADF
)
175 else /* File descriptor is 'ready' to return EIO */
178 se
->requestor
= NULL
;
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. */
196 for (type
= 0; type
< SEL_FDS
; type
++) {
197 if (fdtypes
[type
].type_match(f
)) {
200 se
->filps
[fd
]->filp_selectors
++;
205 if (se
->type
[fd
] == -1) { /* Type not found */
206 se
->requestor
= NULL
;
211 /* Check all file descriptors in the set whether one is 'ready' now */
212 for (fd
= 0; fd
< nfds
; fd
++) {
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. */
223 if ((f
->filp_select_ops
& ops
) != ops
) {
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
244 r
= copy_fdsets(se
, se
->nfds
, TO_PROC
);
245 select_cancel_all(se
);
246 se
->requestor
= NULL
;
250 else if (se
->error
!= OK
)
253 return(se
->nreadyfds
);
256 /* Convert timeval to ticks and set the timer. If it fails, undo
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
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
;
273 ticks
= timeout
.tv_sec
* system_hz
+
274 (timeout
.tv_usec
* system_hz
+ USECPERSEC
-1) / USECPERSEC
;
276 set_timer(&se
->timer
, ticks
, select_timeout_check
, s
);
279 /* process now blocked */
280 suspend(FP_BLOCKED_ON_SELECT
);
284 /*===========================================================================*
286 *===========================================================================*/
287 static int is_deferred(struct selectentry
*se
)
289 /* Find out whether this select has pending initial replies */
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
);
303 /*===========================================================================*
305 *===========================================================================*/
306 static int is_regular_file(struct filp
*f
)
308 return(f
&& f
->filp_vno
&& S_ISREG(f
->filp_vno
->v_mode
));
311 /*===========================================================================*
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() */
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
])
338 /*===========================================================================*
339 * select_request_async *
340 *===========================================================================*/
341 static int select_request_async(struct filp
*f
, int *ops
, int block
)
348 /* By default, nothing to do */
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
))
358 if ((rops
& SEL_WR
) && (f
->filp_select_flags
& FSF_WR_BLOCK
))
360 if ((rops
& SEL_ERR
) && (f
->filp_select_flags
& FSF_ERR_BLOCK
))
362 if (!(rops
& (SEL_RD
|SEL_WR
|SEL_ERR
)))
367 f
->filp_select_flags
|= FSF_UPDATE
;
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
)
378 major
= major(f
->filp_vno
->v_sdev
);
379 if (major
< 0 || major
>= NR_DEVICES
) return(ENXIO
);
381 if (dp
->dmap_sel_filp
)
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
)
391 panic("select_request_asynch: expected SUSPEND got: %d", r
);
393 dp
->dmap_sel_filp
= f
;
394 f
->filp_select_flags
|= FSF_BUSY
;
399 /*===========================================================================*
400 * select_request_file *
401 *===========================================================================*/
402 static int select_request_file(struct filp
*UNUSED(f
), int *UNUSED(ops
),
405 /* Files are always ready, so output *ops is input *ops */
409 /*===========================================================================*
410 * select_request_major *
411 *===========================================================================*/
412 static int select_request_major(struct filp
*f
, int *ops
, int block
)
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
);
423 r
= select_request_sync(f
, ops
, block
);
428 /*===========================================================================*
429 * select_request_sync *
430 *===========================================================================*/
431 static int select_request_sync(struct filp
*f
, int *ops
, int block
)
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
);
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
;
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,
461 if (err
< 0 && err
!= SUSPEND
)
463 if (err
== SUSPEND
&& !(f
->filp_mode
& R_BIT
)) {
464 /* A "meaningless" read select, therefore ready
465 * for reading and no error set. */
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,
478 if (err
< 0 && err
!= SUSPEND
)
480 if (err
== SUSPEND
&& !(f
->filp_mode
& W_BIT
)) {
481 /* A "meaningless" write select, therefore ready
482 for writing and no error set. */
488 /* Some options we collected might not be requested. */
492 f
->filp_pipe_select_ops
|= orig_ops
;
497 /*===========================================================================*
499 *===========================================================================*/
500 static int tab2ops(int fd
, struct selectentry
*e
)
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
;
511 /*===========================================================================*
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
);
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
);
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
);
536 /*===========================================================================*
538 *===========================================================================*/
539 static int copy_fdsets(struct selectentry
*se
, int nfds
, int direction
)
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. */
551 fd_setsize
= (size_t) (howmany(nfds
, __NFDBITS
) * sizeof(__fd_mask
));
553 fd_setsize
= (size_t) (_FDSETWORDS(nfds
) * _FDSETBITSPERWORD
/8);
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
;
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
);
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
);
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
);
591 /*===========================================================================*
592 * select_cancel_all *
593 *===========================================================================*/
594 static void select_cancel_all(struct selectentry
*se
)
596 /* Cancel select. Decrease select usage and cancel timer */
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
);
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 */
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
);
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;
640 /*===========================================================================*
642 *===========================================================================*/
643 static void select_return(struct selectentry
*se
)
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
);
654 else if (se
->error
!= OK
)
659 revive(se
->req_endpt
, r
);
663 /*===========================================================================*
665 *===========================================================================*/
666 void select_callback(struct filp
*f
, int status
)
668 filp_status(f
, status
);
671 /*===========================================================================*
673 *===========================================================================*/
674 void init_select(void)
678 for (s
= 0; s
< MAXSELECTS
; s
++)
679 init_timer(&selecttab
[s
].timer
);
683 /*===========================================================================*
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(). */
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
)
700 if (slot
>= MAXSELECTS
) return; /* Entry not found */
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
)
714 struct selectentry
*se
;
716 s
= tmr_arg(timer
)->ta_int
;
717 if (s
< 0 || s
>= MAXSELECTS
) return; /* Entry does not exist */
720 if (se
->requestor
== NULL
) return;
722 if (se
->expiry
<= 0) return; /* Strange, did we even ask for a timeout? */
724 if (is_deferred(se
)) return; /* Wait for initial replies to DEV_SELECT */
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 */
737 struct selectentry
*se
;
740 for (s
= 0; s
< MAXSELECTS
; 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
);
750 for (fd
= 0; fd
< se
->nfds
; fd
++) {
751 if ((f
= se
->filps
[fd
]) == NULL
|| f
->filp_vno
== NULL
)
754 major
= major(f
->filp_vno
->v_sdev
);
755 if (dmap_driver_match(proc_e
, major
)) {
756 se
->filps
[fd
] = NULL
;
758 select_cancel_filp(f
);
763 if (wakehim
&& !is_deferred(se
))
768 /*===========================================================================*
770 *===========================================================================*/
771 void select_reply1(driver_e
, minor
, status
)
776 /* Handle reply to DEV_SELECT request */
784 /* Figure out which device is replying */
785 if ((dp
= get_dmap(driver_e
)) == NULL
) return;
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
);
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 */
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
);
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
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
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 */
841 f
->filp_select_flags
&= ~FSF_RD_BLOCK
;
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
;
853 filp_status(f
, status
); /* Tell filp owners about the results */
856 select_restart_filps();
860 /*===========================================================================*
862 *===========================================================================*/
863 void select_reply2(driver_e
, minor
, 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. */
875 struct selectentry
*se
;
878 printf("VFS (%s:%d): weird status (%d) to report\n",
879 __FILE__
, __LINE__
, status
);
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
);
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
;
911 f
->filp_select_flags
&= ~FSF_RD_BLOCK
;
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
);
919 f
->filp_select_flags
&= ~FSF_BLOCKED
;
920 ops2tab(SEL_RD
|SEL_WR
|SEL_ERR
, fd
, se
);
923 if (se
->nreadyfds
> 0) restart_proc(se
);
927 select_restart_filps();
930 /*===========================================================================*
931 * select_restart_filps *
932 *===========================================================================*/
933 static void select_restart_filps()
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
++) {
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
;
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
;
980 /* Perform actual select request for file descriptor fd */
987 select_lock_filp(f
, *ops
);
988 r
= fdtypes
[type
].select_request(f
, ops
, se
->block
);
990 if (r
!= OK
&& r
!= SUSPEND
) {
992 se
->block
= 0; /* Stop blocking to return asap */
993 if (!is_deferred(se
)) select_cancel_all(se
);
999 /*===========================================================================*
1001 *===========================================================================*/
1002 static void filp_status(f
, status
)
1006 /* Tell processes that need to know about the status of this filp */
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;
1017 ops2tab(SEL_RD
|SEL_WR
|SEL_ERR
, fd
, se
);
1019 ops2tab(status
, fd
, se
);
1025 /*===========================================================================*
1027 *===========================================================================*/
1028 static void restart_proc(se
)
1029 struct selectentry
*se
;
1031 /* Tell process about select results (if any) unless there are still results
1034 if ((se
->nreadyfds
> 0 || !se
->block
) && !is_deferred(se
))
1038 /*===========================================================================*
1040 *===========================================================================*/
1041 static void wipe_select(struct selectentry
*se
)
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
);