1 /* This file deals with the suspension and revival of processes. A process can
2 * be suspended because it wants to read or write from a pipe and can't, or
3 * because it wants to read or write from a special file and can't. When a
4 * process can't continue it is suspended, and revived later when it is able
7 * The entry points into this file are
8 * do_pipe: perform the PIPE system call
9 * pipe_check: check to see that a read or write on a pipe is feasible now
10 * suspend: suspend a process that cannot do a requested read or write
11 * release: check to see if a suspended process can be released and do
13 * revive: mark a suspended process as able to run again
14 * unsuspend_by_endpt: revive all processes blocking on a given process
15 * do_unpause: a signal has been sent to a process; see if it suspended
22 #include <minix/callnr.h>
23 #include <minix/endpoint.h>
24 #include <minix/com.h>
25 #include <minix/u64.h>
26 #include <sys/select.h>
32 #include <minix/vfsif.h>
37 /*===========================================================================*
39 *===========================================================================*/
42 /* Perform the pipe(fil_des) system call. */
44 register struct fproc
*rfp
;
46 struct filp
*fil_ptr0
, *fil_ptr1
;
47 int fil_des
[2]; /* reply goes here */
49 struct node_details res
;
51 /* See if a free vnode is available */
52 if ( (vp
= get_free_vnode()) == NIL_VNODE
) return(err_code
);
54 /* Acquire two file descriptors. */
56 if ((r
= get_fd(0, R_BIT
, &fil_des
[0], &fil_ptr0
)) != OK
) return(r
);
57 rfp
->fp_filp
[fil_des
[0]] = fil_ptr0
;
58 FD_SET(fil_des
[0], &rfp
->fp_filp_inuse
);
59 fil_ptr0
->filp_count
= 1;
60 if ((r
= get_fd(0, W_BIT
, &fil_des
[1], &fil_ptr1
)) != OK
) {
61 rfp
->fp_filp
[fil_des
[0]] = NIL_FILP
;
62 FD_CLR(fil_des
[0], &rfp
->fp_filp_inuse
);
63 fil_ptr0
->filp_count
= 0;
66 rfp
->fp_filp
[fil_des
[1]] = fil_ptr1
;
67 FD_SET(fil_des
[1], &rfp
->fp_filp_inuse
);
68 fil_ptr1
->filp_count
= 1;
70 /* Create a named pipe inode on PipeFS */
71 r
= req_newnode(PFS_PROC_NR
, fp
->fp_effuid
, fp
->fp_effgid
, I_NAMED_PIPE
,
75 rfp
->fp_filp
[fil_des
[0]] = NIL_FILP
;
76 FD_CLR(fil_des
[0], &rfp
->fp_filp_inuse
);
77 fil_ptr0
->filp_count
= 0;
78 rfp
->fp_filp
[fil_des
[1]] = NIL_FILP
;
79 FD_CLR(fil_des
[1], &rfp
->fp_filp_inuse
);
80 fil_ptr1
->filp_count
= 0;
85 vp
->v_fs_e
= res
.fs_e
;
86 vp
->v_mapfs_e
= res
.fs_e
;
87 vp
->v_inode_nr
= res
.inode_nr
;
88 vp
->v_mapinode_nr
= res
.inode_nr
;
89 vp
->v_mode
= res
.fmode
;
94 vp
->v_mapfs_count
= 1;
97 vp
->v_vmnt
= NIL_VMNT
;
100 /* Fill in filp objects */
101 fil_ptr0
->filp_vno
= vp
;
103 fil_ptr1
->filp_vno
= vp
;
104 fil_ptr0
->filp_flags
= O_RDONLY
;
105 fil_ptr1
->filp_flags
= O_WRONLY
;
107 m_out
.reply_i1
= fil_des
[0];
108 m_out
.reply_i2
= fil_des
[1];
114 /*===========================================================================*
116 *===========================================================================*/
117 PUBLIC
int map_vnode(vp
)
121 struct node_details res
;
123 if(vp
->v_mapfs_e
!= 0) return(OK
); /* Already mapped; nothing to do. */
125 /* Create a temporary mapping of this inode to PipeFS. Read and write
126 * operations on data will be handled by PipeFS. The rest by the 'original'
127 * FS that holds the inode. */
128 if ((r
= req_newnode(PFS_PROC_NR
, fp
->fp_effuid
, fp
->fp_effgid
, I_NAMED_PIPE
,
129 vp
->v_dev
, &res
)) == OK
) {
130 vp
->v_mapfs_e
= res
.fs_e
;
131 vp
->v_mapinode_nr
= res
.inode_nr
;
132 vp
->v_mapfs_count
= 1;
139 /*===========================================================================*
141 *===========================================================================*/
142 PUBLIC
int pipe_check(vp
, rw_flag
, oflags
, bytes
, position
, notouch
)
143 register struct vnode
*vp
; /* the inode of the pipe */
144 int rw_flag
; /* READING or WRITING */
145 int oflags
; /* flags set by open or fcntl */
146 register int bytes
; /* bytes to be read or written (all chunks) */
147 u64_t position
; /* current file position */
148 int notouch
; /* check only */
150 /* Pipes are a little different. If a process reads from an empty pipe for
151 * which a writer still exists, suspend the reader. If the pipe is empty
152 * and there is no writer, return 0 bytes. If a process is writing to a
153 * pipe and no one is reading from it, give a broken pipe error.
158 if (ex64hi(position
) != 0)
159 panic("pipe_check: position too large in pipe");
160 pos
= ex64lo(position
);
162 /* If reading, check for empty pipe. */
163 if (rw_flag
== READING
) {
164 if (pos
>= vp
->v_size
) {
165 /* Process is reading from an empty pipe. */
166 if (find_filp(vp
, W_BIT
) != NIL_FILP
) {
168 if (oflags
& O_NONBLOCK
)
173 /* If need be, activate sleeping writers. */
175 release(vp
, WRITE
, susp_count
);
182 /* Process is writing to a pipe. */
183 if (find_filp(vp
, R_BIT
) == NIL_FILP
) {
184 /* Process is writing, but there is no reader. Tell kernel to generate
185 * a SIGPIPE signal. */
186 if (!notouch
) sys_kill(fp
->fp_endpoint
, SIGPIPE
);
191 /* Calculate how many bytes can be written. */
192 if (pos
+ bytes
> PIPE_BUF
) {
193 if (oflags
& O_NONBLOCK
) {
194 if (bytes
<= PIPE_BUF
) {
195 /* Write has to be atomic */
199 /* Compute available space */
200 bytes
= PIPE_BUF
- pos
;
203 /* Do a partial write. Need to wakeup reader */
205 release(vp
, READ
, susp_count
);
213 if (bytes
> PIPE_BUF
) {
214 /* Compute available space */
215 bytes
= PIPE_BUF
- pos
;
218 /* Do a partial write. Need to wakeup reader
219 * since we'll suspend ourself in read_write()
222 release(vp
, READ
, susp_count
);
231 /* Writing to an empty pipe. Search for suspended reader. */
232 if (pos
== 0 && !notouch
)
233 release(vp
, READ
, susp_count
);
235 /* Requested amount fits */
240 /*===========================================================================*
242 *===========================================================================*/
243 PUBLIC
void suspend(int why
)
245 /* Take measures to suspend the processing of the present system call.
246 * Store the parameters to be used upon resuming in the process table.
247 * (Actually they are not used when a process is waiting for an I/O device,
248 * but they are needed for pipes, and it is not worth making the distinction.)
249 * The SUSPEND pseudo error should be returned after calling suspend().
253 if (why
== FP_BLOCKED_ON_PIPE
)
254 panic("suspend: called for FP_BLOCKED_ON_PIPE");
256 if(fp_is_blocked(fp
))
257 panic("suspend: called for suspended process");
259 if(why
== FP_BLOCKED_ON_NONE
)
260 panic("suspend: called for FP_BLOCKED_ON_NONE");
263 if (why
== FP_BLOCKED_ON_POPEN
)
264 /* #procs susp'ed on pipe*/
267 fp
->fp_blocked_on
= why
;
268 assert(fp
->fp_grant
== GRANT_INVALID
|| !GRANT_VALID(fp
->fp_grant
));
269 fp
->fp_fd
= m_in
.fd
<< 8 | call_nr
;
270 fp
->fp_flags
&= ~SUSP_REOPEN
; /* Clear this flag. The caller
271 * can set it when needed.
273 if (why
== FP_BLOCKED_ON_LOCK
) {
274 fp
->fp_buffer
= (char *) m_in
.name1
; /* third arg to fcntl() */
275 fp
->fp_nbytes
= m_in
.request
; /* second arg to fcntl() */
277 fp
->fp_buffer
= m_in
.buffer
; /* for reads and writes */
278 fp
->fp_nbytes
= m_in
.nbytes
;
283 /*===========================================================================*
285 *===========================================================================*/
286 PUBLIC
void wait_for(endpoint_t who
)
288 if(who
== NONE
|| who
== ANY
)
289 panic("suspend on NONE or ANY");
290 suspend(FP_BLOCKED_ON_OTHER
);
295 /*===========================================================================*
297 *===========================================================================*/
298 PUBLIC
void pipe_suspend(rw_flag
, fd_nr
, buf
, size
)
304 /* Take measures to suspend the processing of the present system call.
305 * Store the parameters to be used upon resuming in the process table.
306 * (Actually they are not used when a process is waiting for an I/O device,
307 * but they are needed for pipes, and it is not worth making the distinction.)
308 * The SUSPEND pseudo error should be returned after calling suspend().
311 if(fp_is_blocked(fp
))
312 panic("pipe_suspend: called for suspended process");
315 susp_count
++; /* #procs susp'ed on pipe*/
316 fp
->fp_blocked_on
= FP_BLOCKED_ON_PIPE
;
317 assert(!GRANT_VALID(fp
->fp_grant
));
318 fp
->fp_fd
= (fd_nr
<< 8) | ((rw_flag
== READING
) ? READ
: WRITE
);
320 fp
->fp_nbytes
= size
;
324 /*===========================================================================*
325 * unsuspend_by_endpt *
326 *===========================================================================*/
327 PUBLIC
void unsuspend_by_endpt(endpoint_t proc_e
)
331 /* Revive processes waiting for drivers (SUSPENDed) that have
332 * disappeared with return code EAGAIN.
334 for (rp
= &fproc
[0]; rp
< &fproc
[NR_PROCS
]; rp
++)
335 if(rp
->fp_pid
!= PID_FREE
&&
336 rp
->fp_blocked_on
== FP_BLOCKED_ON_OTHER
&& rp
->fp_task
== proc_e
) {
337 revive(rp
->fp_endpoint
, EAGAIN
);
340 /* Revive processes waiting in drivers on select()s
343 select_unsuspend_by_endpt(proc_e
);
349 /*===========================================================================*
351 *===========================================================================*/
352 PUBLIC
void release(vp
, call_nr
, count
)
353 register struct vnode
*vp
; /* inode of pipe */
354 int call_nr
; /* READ, WRITE, OPEN or CREAT */
355 int count
; /* max number of processes to release */
357 /* Check to see if any process is hanging on the pipe whose inode is in 'ip'.
358 * If one is, and it was trying to perform the call indicated by 'call_nr',
362 register struct fproc
*rp
;
365 /* Trying to perform the call also includes SELECTing on it with that
368 if (call_nr
== READ
|| call_nr
== WRITE
) {
374 for(f
= &filp
[0]; f
< &filp
[NR_FILPS
]; f
++) {
375 if (f
->filp_count
< 1 || !(f
->filp_pipe_select_ops
& op
) ||
378 select_callback(f
, op
);
379 f
->filp_pipe_select_ops
&= ~op
;
383 /* Search the proc table. */
384 for (rp
= &fproc
[0]; rp
< &fproc
[NR_PROCS
] && count
> 0; rp
++) {
385 if (rp
->fp_pid
!= PID_FREE
&& fp_is_blocked(rp
) &&
386 rp
->fp_revived
== NOT_REVIVING
&& (rp
->fp_fd
& BYTE
) == call_nr
&&
387 rp
->fp_filp
[rp
->fp_fd
>>8]->filp_vno
== vp
) {
388 revive(rp
->fp_endpoint
, 0);
389 susp_count
--; /* keep track of who is suspended */
391 panic("susp_count now negative: %d", susp_count
);
392 if (--count
== 0) return;
398 /*===========================================================================*
400 *===========================================================================*/
401 PUBLIC
void revive(proc_nr_e
, returned
)
402 int proc_nr_e
; /* process to revive */
403 int returned
; /* if hanging on task, how many bytes read */
405 /* Revive a previously blocked process. When a process hangs on tty, this
406 * is the way it is eventually released.
408 register struct fproc
*rfp
;
411 struct filp
*fil_ptr
;
413 if(isokendpt(proc_nr_e
, &proc_nr
) != OK
) return;
415 rfp
= &fproc
[proc_nr
];
416 if (!fp_is_blocked(rfp
) || rfp
->fp_revived
== REVIVING
) return;
418 /* The 'reviving' flag only applies to pipes. Processes waiting for TTY get
419 * a message right away. The revival process is different for TTY and pipes.
420 * For select and TTY revival, the work is already done, for pipes it is not:
421 * the proc must be restarted so it can try again.
423 blocked_on
= rfp
->fp_blocked_on
;
424 if (blocked_on
== FP_BLOCKED_ON_PIPE
|| blocked_on
== FP_BLOCKED_ON_LOCK
) {
425 /* Revive a process suspended on a pipe or lock. */
426 rfp
->fp_revived
= REVIVING
;
427 reviving
++; /* process was waiting on pipe or lock */
428 } else if (blocked_on
== FP_BLOCKED_ON_DOPEN
) {
429 rfp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
430 fd_nr
= rfp
->fp_fd
>>8;
432 fil_ptr
= rfp
->fp_filp
[fd_nr
];
433 rfp
->fp_filp
[fd_nr
] = NIL_FILP
;
434 FD_CLR(fd_nr
, &rfp
->fp_filp_inuse
);
435 if (fil_ptr
->filp_count
!= 1) {
436 panic("revive: bad count in filp: %d",
437 fil_ptr
->filp_count
);
439 fil_ptr
->filp_count
= 0;
440 put_vnode(fil_ptr
->filp_vno
);
441 fil_ptr
->filp_vno
= NIL_VNODE
;
442 reply(proc_nr_e
, returned
);
444 reply(proc_nr_e
, fd_nr
);
446 rfp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
447 if (blocked_on
== FP_BLOCKED_ON_POPEN
) {
448 /* process blocked in open or create */
449 reply(proc_nr_e
, rfp
->fp_fd
>>8);
450 } else if (blocked_on
== FP_BLOCKED_ON_SELECT
) {
451 reply(proc_nr_e
, returned
);
453 /* Revive a process suspended on TTY or other device.
454 * Pretend it wants only what there is.
456 rfp
->fp_nbytes
= returned
;
457 /* If a grant has been issued by FS for this I/O, revoke
458 * it again now that I/O is done.
460 if(GRANT_VALID(rfp
->fp_grant
)) {
461 if(cpf_revoke(rfp
->fp_grant
)) {
462 panic("FS: revoke failed for grant: %d",
465 rfp
->fp_grant
= GRANT_INVALID
;
467 reply(proc_nr_e
, returned
); /* unblock the process */
473 /*===========================================================================*
475 *===========================================================================*/
476 PUBLIC
void unpause(proc_nr_e
)
479 /* A signal has been sent to a user who is paused on the file system.
480 * Abort the system call with the EINTR error message.
483 register struct fproc
*rfp
;
484 int proc_nr_p
, blocked_on
, fild
, status
= EINTR
;
490 if(isokendpt(proc_nr_e
, &proc_nr_p
) != OK
) {
491 printf("VFS: ignoring unpause for bogus endpoint %d\n", proc_nr_e
);
495 rfp
= &fproc
[proc_nr_p
];
496 if (!fp_is_blocked(rfp
)) return;
497 blocked_on
= rfp
->fp_blocked_on
;
499 if (rfp
->fp_revived
== REVIVING
) {
500 rfp
->fp_revived
= NOT_REVIVING
;
505 switch (blocked_on
) {
506 case FP_BLOCKED_ON_PIPE
:/* process trying to read or write a pipe */
509 case FP_BLOCKED_ON_LOCK
:/* process trying to set a lock with FCNTL */
512 case FP_BLOCKED_ON_SELECT
:/* process blocking on select() */
513 select_forget(proc_nr_e
);
516 case FP_BLOCKED_ON_POPEN
: /* process trying to open a fifo */
519 case FP_BLOCKED_ON_DOPEN
:/* process trying to open a device */
520 /* Don't cancel OPEN. Just wait until the open completes. */
523 case FP_BLOCKED_ON_OTHER
: /* process trying to do device I/O (e.g. tty)*/
524 if (rfp
->fp_flags
& SUSP_REOPEN
) {
525 /* Process is suspended while waiting for a reopen.
528 rfp
->fp_flags
&= ~SUSP_REOPEN
;
533 fild
= (rfp
->fp_fd
>> 8) & BYTE
;/* extract file descriptor */
534 if (fild
< 0 || fild
>= OPEN_MAX
)
535 panic("unpause err 2");
536 f
= rfp
->fp_filp
[fild
];
537 dev
= (dev_t
) f
->filp_vno
->v_sdev
; /* device hung on */
538 mess
.TTY_LINE
= (dev
>> MINOR
) & BYTE
;
539 mess
.IO_ENDPT
= rfp
->fp_ioproc
;
540 mess
.IO_GRANT
= (char *) rfp
->fp_grant
;
542 /* Tell kernel R or W. Mode is from current call, not open. */
543 mess
.COUNT
= (rfp
->fp_fd
& BYTE
) == READ
? R_BIT
: W_BIT
;
544 mess
.m_type
= CANCEL
;
545 fp
= rfp
; /* hack - ctty_io uses fp */
546 (*dmap
[(dev
>> MAJOR
) & BYTE
].dmap_io
)(rfp
->fp_task
, &mess
);
547 status
= mess
.REP_STATUS
;
548 if (status
== SUSPEND
)
549 return; /* Process will be revived at a
553 if(status
== EAGAIN
) status
= EINTR
;
554 if(GRANT_VALID(rfp
->fp_grant
)) {
555 if(cpf_revoke(rfp
->fp_grant
)) {
556 panic("FS: revoke failed for grant (cancel): %d",
559 rfp
->fp_grant
= GRANT_INVALID
;
563 panic("FS: unknown value: %d", blocked_on
);
566 rfp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
568 if ((blocked_on
== FP_BLOCKED_ON_PIPE
||
569 blocked_on
== FP_BLOCKED_ON_POPEN
) &&
574 reply(proc_nr_e
, status
); /* signal interrupted call */
578 /*===========================================================================*
579 * select_request_pipe *
580 *===========================================================================*/
581 PUBLIC
int select_request_pipe(struct filp
*f
, int *ops
, int block
)
583 int orig_ops
, r
= 0, err
;
585 if ((*ops
& (SEL_RD
|SEL_ERR
))) {
586 if ((err
= pipe_check(f
->filp_vno
, READING
, 0,
587 1, f
->filp_pos
, 1)) != SUSPEND
)
589 if (err
< 0 && err
!= SUSPEND
)
591 if(err
== SUSPEND
&& f
->filp_mode
& W_BIT
) {
592 /* A "meaningless" read select, therefore ready
593 for reading and no error set. */
599 if ((*ops
& (SEL_WR
|SEL_ERR
))) {
600 if ((err
= pipe_check(f
->filp_vno
, WRITING
, 0,
601 1, f
->filp_pos
, 1)) != SUSPEND
)
603 if (err
< 0 && err
!= SUSPEND
)
605 if(err
== SUSPEND
&& f
->filp_mode
& R_BIT
) {
606 /* A "meaningless" write select, therefore ready
607 for reading and no error set. */
613 /* Some options we collected might not be requested. */
616 if (!*ops
&& block
) {
617 f
->filp_pipe_select_ops
|= orig_ops
;
624 /*===========================================================================*
625 * select_match_pipe *
626 *===========================================================================*/
627 PUBLIC
int select_match_pipe(struct filp
*f
)
629 /* recognize either pipe or named pipe (FIFO) */
630 if (f
&& f
->filp_vno
&& (f
->filp_vno
->v_mode
& I_NAMED_PIPE
))
636 /*===========================================================================*
638 *===========================================================================*/
639 PUBLIC
int check_pipe(void)
643 for (rfp
=&fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
644 if (rfp
->fp_pid
== PID_FREE
)
646 if(rfp
->fp_revived
!= REVIVING
&&
647 (rfp
->fp_blocked_on
== FP_BLOCKED_ON_PIPE
||
648 rfp
->fp_blocked_on
== FP_BLOCKED_ON_POPEN
)) {
653 if(mycount
!= susp_count
) {
654 printf("check_pipe: mycount %d susp_count %d\n",
655 mycount
, susp_count
);