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_pipe2: perform the PIPE2 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
23 #include <minix/callnr.h>
24 #include <minix/endpoint.h>
25 #include <minix/com.h>
26 #include <minix/u64.h>
27 #include <sys/select.h>
30 #include "scratchpad.h"
31 #include <minix/vfsif.h>
35 static int create_pipe(int fil_des
[2], int flags
);
37 /*===========================================================================*
39 *===========================================================================*/
42 /* Perform the pipe2(fil_des[2], flags) system call. */
44 int fil_des
[2]; /* reply goes here */
46 flags
= job_m_in
.VFS_PIPE2_FLAGS
;
48 r
= create_pipe(fil_des
, flags
);
50 job_m_out
.VFS_PIPE2_FD0
= fil_des
[0];
51 job_m_out
.VFS_PIPE2_FD1
= fil_des
[1];
57 /*===========================================================================*
59 *===========================================================================*/
60 static int create_pipe(int fil_des
[2], int flags
)
62 register struct fproc
*rfp
;
64 struct filp
*fil_ptr0
, *fil_ptr1
;
67 struct node_details res
;
69 /* Get a lock on PFS */
70 if ((vmp
= find_vmnt(PFS_PROC_NR
)) == NULL
) panic("PFS gone");
71 if ((r
= lock_vmnt(vmp
, VMNT_READ
)) != OK
) return(r
);
73 /* See if a free vnode is available */
74 if ((vp
= get_free_vnode()) == NULL
) {
78 lock_vnode(vp
, VNODE_OPCL
);
80 /* Acquire two file descriptors. */
82 if ((r
= get_fd(fp
, 0, R_BIT
, &fil_des
[0], &fil_ptr0
)) != OK
) {
87 rfp
->fp_filp
[fil_des
[0]] = fil_ptr0
;
88 fil_ptr0
->filp_count
= 1; /* mark filp in use */
89 if ((r
= get_fd(fp
, 0, W_BIT
, &fil_des
[1], &fil_ptr1
)) != OK
) {
90 rfp
->fp_filp
[fil_des
[0]] = NULL
;
91 fil_ptr0
->filp_count
= 0; /* mark filp free */
92 unlock_filp(fil_ptr0
);
97 rfp
->fp_filp
[fil_des
[1]] = fil_ptr1
;
98 fil_ptr1
->filp_count
= 1;
100 /* Create a named pipe inode on PipeFS */
101 r
= req_newnode(PFS_PROC_NR
, fp
->fp_effuid
, fp
->fp_effgid
, I_NAMED_PIPE
,
105 rfp
->fp_filp
[fil_des
[0]] = NULL
;
106 fil_ptr0
->filp_count
= 0;
107 rfp
->fp_filp
[fil_des
[1]] = NULL
;
108 fil_ptr1
->filp_count
= 0;
109 unlock_filp(fil_ptr1
);
110 unlock_filp(fil_ptr0
);
117 vp
->v_fs_e
= res
.fs_e
;
118 vp
->v_mapfs_e
= res
.fs_e
;
119 vp
->v_inode_nr
= res
.inode_nr
;
120 vp
->v_mapinode_nr
= res
.inode_nr
;
121 vp
->v_mode
= res
.fmode
;
123 vp
->v_mapfs_count
= 1;
129 /* Fill in filp objects */
130 fil_ptr0
->filp_vno
= vp
;
132 fil_ptr1
->filp_vno
= vp
;
133 fil_ptr0
->filp_flags
= O_RDONLY
| (flags
& ~O_ACCMODE
);
134 fil_ptr1
->filp_flags
= O_WRONLY
| (flags
& ~O_ACCMODE
);
135 if (flags
& O_CLOEXEC
) {
136 FD_SET(fil_des
[0], &rfp
->fp_cloexec_set
);
137 FD_SET(fil_des
[1], &rfp
->fp_cloexec_set
);
140 unlock_filps(fil_ptr0
, fil_ptr1
);
147 /*===========================================================================*
149 *===========================================================================*/
150 int map_vnode(vp
, map_to_fs_e
)
152 endpoint_t map_to_fs_e
;
156 struct node_details res
;
158 if(vp
->v_mapfs_e
!= NONE
) return(OK
); /* Already mapped; nothing to do. */
160 if ((vmp
= find_vmnt(map_to_fs_e
)) == NULL
)
161 panic("Can't map to unknown endpoint");
162 if ((r
= lock_vmnt(vmp
, VMNT_WRITE
)) != OK
) {
164 vmp
= NULL
; /* Already locked, do not unlock */
170 /* Create a temporary mapping of this inode to another FS. Read and write
171 * operations on data will be handled by that FS. The rest by the 'original'
172 * FS that holds the inode. */
173 if ((r
= req_newnode(map_to_fs_e
, fp
->fp_effuid
, fp
->fp_effgid
, I_NAMED_PIPE
,
174 vp
->v_dev
, &res
)) == OK
) {
175 vp
->v_mapfs_e
= res
.fs_e
;
176 vp
->v_mapinode_nr
= res
.inode_nr
;
177 vp
->v_mapfs_count
= 1;
180 if (vmp
) unlock_vmnt(vmp
);
185 /*===========================================================================*
187 *===========================================================================*/
189 struct filp
*filp
, /* the filp of the pipe */
190 int rw_flag
, /* READING or WRITING */
191 int oflags
, /* flags set by open or fcntl */
192 int bytes
, /* bytes to be read or written (all chunks) */
193 int notouch
/* check only */
196 /* Pipes are a little different. If a process reads from an empty pipe for
197 * which a writer still exists, suspend the reader. If the pipe is empty
198 * and there is no writer, return 0 bytes. If a process is writing to a
199 * pipe and no one is reading from it, give a broken pipe error.
207 /* Reads start at the beginning; writes append to pipes */
208 if (notouch
) /* In this case we don't actually care whether data transfer
209 * would succeed. See POSIX 1003.1-2008 */
211 else if (rw_flag
== READING
)
217 /* If reading, check for empty pipe. */
218 if (rw_flag
== READING
) {
219 if (vp
->v_size
== 0) {
220 /* Process is reading from an empty pipe. */
221 if (find_filp(vp
, W_BIT
) != NULL
) {
223 if (oflags
& O_NONBLOCK
)
228 /* If need be, activate sleeping writers. */
230 release(vp
, VFS_WRITE
, susp_count
);
237 /* Process is writing to a pipe. */
238 if (find_filp(vp
, R_BIT
) == NULL
) {
242 /* Calculate how many bytes can be written. */
243 if (pos
+ bytes
> PIPE_BUF
) {
244 if (oflags
& O_NONBLOCK
) {
245 if (bytes
<= PIPE_BUF
) {
246 /* Write has to be atomic */
250 /* Compute available space */
251 bytes
= PIPE_BUF
- pos
;
254 /* Do a partial write. Need to wakeup reader */
256 release(vp
, VFS_READ
, susp_count
);
264 if (bytes
> PIPE_BUF
) {
265 /* Compute available space */
266 bytes
= PIPE_BUF
- pos
;
269 /* Do a partial write. Need to wakeup reader
270 * since we'll suspend ourself in read_write()
273 release(vp
, VFS_READ
, susp_count
);
282 /* Writing to an empty pipe. Search for suspended reader. */
283 if (pos
== 0 && !notouch
)
284 release(vp
, VFS_READ
, susp_count
);
286 /* Requested amount fits */
291 /*===========================================================================*
293 *===========================================================================*/
294 void suspend(int why
)
296 /* Take measures to suspend the processing of the present system call.
297 * Store the parameters to be used upon resuming in the process table.
298 * (Actually they are not used when a process is waiting for an I/O device,
299 * but they are needed for pipes, and it is not worth making the distinction.)
300 * The SUSPEND pseudo error should be returned after calling suspend().
303 if (why
== FP_BLOCKED_ON_POPEN
|| why
== FP_BLOCKED_ON_PIPE
)
304 /* #procs susp'ed on pipe*/
307 fp
->fp_blocked_on
= why
;
308 assert(fp
->fp_grant
== GRANT_INVALID
|| !GRANT_VALID(fp
->fp_grant
));
309 fp
->fp_block_callnr
= job_call_nr
;
312 /*===========================================================================*
314 *===========================================================================*/
315 void wait_for(endpoint_t who
)
317 if(who
== NONE
|| who
== ANY
)
318 panic("suspend on NONE or ANY");
319 suspend(FP_BLOCKED_ON_OTHER
);
324 /*===========================================================================*
326 *===========================================================================*/
327 void pipe_suspend(filp
, buf
, size
)
332 /* Take measures to suspend the processing of the present system call.
333 * Store the parameters to be used upon resuming in the process table.
336 scratch(fp
).file
.filp
= filp
;
337 scratch(fp
).io
.io_buffer
= buf
;
338 scratch(fp
).io
.io_nbytes
= size
;
339 suspend(FP_BLOCKED_ON_PIPE
);
343 /*===========================================================================*
344 * unsuspend_by_endpt *
345 *===========================================================================*/
346 void unsuspend_by_endpt(endpoint_t proc_e
)
348 /* Revive processes waiting for drivers (SUSPENDed) that have disappeared with
349 * return code EAGAIN.
353 for (rp
= &fproc
[0]; rp
< &fproc
[NR_PROCS
]; rp
++) {
354 if (rp
->fp_pid
== PID_FREE
) continue;
355 if (rp
->fp_blocked_on
== FP_BLOCKED_ON_OTHER
&& rp
->fp_task
== proc_e
)
356 revive(rp
->fp_endpoint
, EIO
);
359 /* Revive processes waiting in drivers on select()s with EAGAIN too */
360 select_unsuspend_by_endpt(proc_e
);
366 /*===========================================================================*
368 *===========================================================================*/
369 void release(vp
, op
, count
)
370 register struct vnode
*vp
; /* inode of pipe */
371 int op
; /* VFS_READ, VFS_WRITE, or VFS_OPEN */
372 int count
; /* max number of processes to release */
374 /* Check to see if any process is hanging on vnode 'vp'. If one is, and it
375 * was trying to perform the call indicated by 'op', release it.
378 register struct fproc
*rp
;
382 /* Trying to perform the call also includes SELECTing on it with that
385 if (op
== VFS_READ
|| op
== VFS_WRITE
) {
391 for (f
= &filp
[0]; f
< &filp
[NR_FILPS
]; f
++) {
392 if (f
->filp_count
< 1 || !(f
->filp_pipe_select_ops
& selop
) ||
395 select_callback(f
, selop
);
396 f
->filp_pipe_select_ops
&= ~selop
;
400 /* Search the proc table. */
401 for (rp
= &fproc
[0]; rp
< &fproc
[NR_PROCS
] && count
> 0; rp
++) {
402 if (rp
->fp_pid
!= PID_FREE
&& fp_is_blocked(rp
) &&
403 !(rp
->fp_flags
& FP_REVIVED
) && rp
->fp_block_callnr
== op
) {
404 /* Find the vnode. Depending on the reason the process was
405 * suspended, there are different ways of finding it.
408 if (rp
->fp_blocked_on
== FP_BLOCKED_ON_POPEN
||
409 rp
->fp_blocked_on
== FP_BLOCKED_ON_LOCK
||
410 rp
->fp_blocked_on
== FP_BLOCKED_ON_OTHER
) {
411 f
= rp
->fp_filp
[scratch(rp
).file
.fd_nr
];
412 if (f
== NULL
|| f
->filp_mode
== FILP_CLOSED
)
414 if (rp
->fp_filp
[scratch(rp
).file
.fd_nr
]->filp_vno
!= vp
)
416 } else if (rp
->fp_blocked_on
== FP_BLOCKED_ON_PIPE
) {
417 if (scratch(rp
).file
.filp
== NULL
)
419 if (scratch(rp
).file
.filp
->filp_vno
!= vp
)
424 /* We found the vnode. Revive process. */
425 revive(rp
->fp_endpoint
, 0);
426 susp_count
--; /* keep track of who is suspended */
428 panic("susp_count now negative: %d", susp_count
);
429 if (--count
== 0) return;
435 /*===========================================================================*
437 *===========================================================================*/
438 void revive(endpoint_t proc_e
, int returned
)
440 /* Revive a previously blocked process. When a process hangs on tty, this
441 * is the way it is eventually released. For processes blocked on _SELECT and
442 * _OTHER, this function MUST NOT block its calling thread.
448 if (proc_e
== NONE
|| isokendpt(proc_e
, &slot
) != OK
) return;
451 if (!fp_is_blocked(rfp
) || (rfp
->fp_flags
& FP_REVIVED
)) return;
453 /* The 'reviving' flag only applies to pipes. Processes waiting for TTY get
454 * a message right away. The revival process is different for TTY and pipes.
455 * For select and TTY revival, the work is already done, for pipes it is not:
456 * the proc must be restarted so it can try again.
458 blocked_on
= rfp
->fp_blocked_on
;
459 fd_nr
= scratch(rfp
).file
.fd_nr
;
460 if (blocked_on
== FP_BLOCKED_ON_PIPE
|| blocked_on
== FP_BLOCKED_ON_LOCK
) {
461 /* Revive a process suspended on a pipe or lock. */
462 rfp
->fp_flags
|= FP_REVIVED
;
463 reviving
++; /* process was waiting on pipe or lock */
465 rfp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
466 scratch(rfp
).file
.fd_nr
= 0;
467 if (blocked_on
== FP_BLOCKED_ON_POPEN
) {
468 /* process blocked in open or create */
469 replycode(proc_e
, fd_nr
);
470 } else if (blocked_on
== FP_BLOCKED_ON_SELECT
) {
471 replycode(proc_e
, returned
);
473 /* Revive a process suspended on TTY or other device.
474 * Pretend it wants only what there is.
476 scratch(rfp
).io
.io_nbytes
= returned
;
477 /* If a grant has been issued by FS for this I/O, revoke
478 * it again now that I/O is done.
480 if (GRANT_VALID(rfp
->fp_grant
)) {
481 if(cpf_revoke(rfp
->fp_grant
)) {
482 panic("VFS: revoke failed for grant: %d",
485 rfp
->fp_grant
= GRANT_INVALID
;
487 replycode(proc_e
, returned
);/* unblock the process */
493 /*===========================================================================*
495 *===========================================================================*/
498 /* A signal has been sent to a user who is paused on the file system.
499 * Abort the system call with the EINTR error message.
501 int blocked_on
, fild
, status
= EINTR
;
506 if (!fp_is_blocked(fp
)) return;
507 blocked_on
= fp
->fp_blocked_on
;
509 /* Clear the block status now. The procedure below might make blocking calls
510 * and it is imperative that while at least cdev_cancel() is executing, other
511 * parts of VFS do not perceive this process as blocked on something.
513 fp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
515 if (fp
->fp_flags
& FP_REVIVED
) {
516 fp
->fp_flags
&= ~FP_REVIVED
;
521 switch (blocked_on
) {
522 case FP_BLOCKED_ON_PIPE
:/* process trying to read or write a pipe */
523 /* If the operation succeeded partially, return the bytes
524 * processed so far, and clear the remembered state. Otherwise,
525 * return EINTR as usual.
527 if (fp
->fp_cum_io_partial
> 0) {
528 status
= fp
->fp_cum_io_partial
;
530 fp
->fp_cum_io_partial
= 0;
534 case FP_BLOCKED_ON_LOCK
:/* process trying to set a lock with FCNTL */
537 case FP_BLOCKED_ON_SELECT
:/* process blocking on select() */
541 case FP_BLOCKED_ON_POPEN
: /* process trying to open a fifo */
544 case FP_BLOCKED_ON_OTHER
:/* process trying to do device I/O (e.g. tty)*/
545 fild
= scratch(fp
).file
.fd_nr
;
546 if (fild
< 0 || fild
>= OPEN_MAX
)
547 panic("file descriptor out-of-range");
548 f
= fp
->fp_filp
[fild
];
550 sys_diagctl_stacktrace(fp
->fp_endpoint
);
551 panic("process %d blocked on empty fd %d",
552 fp
->fp_endpoint
, fild
);
554 dev
= f
->filp_vno
->v_sdev
; /* device hung on */
556 status
= cdev_cancel(dev
);
560 panic("VFS: unknown block reason: %d", blocked_on
);
563 if ((blocked_on
== FP_BLOCKED_ON_PIPE
|| blocked_on
== FP_BLOCKED_ON_POPEN
)&&
568 replycode(fp
->fp_endpoint
, status
); /* signal interrupted call */