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
.m_lc_vfs_pipe2
.flags
;
48 r
= create_pipe(fil_des
, flags
);
50 job_m_out
.m_lc_vfs_pipe2
.fd0
= fil_des
[0];
51 job_m_out
.m_lc_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. */
229 /* We ignore notouch voluntary here. */
231 release(vp
, VFS_WRITE
, susp_count
);
238 /* Process is writing to a pipe. */
239 if (find_filp(vp
, R_BIT
) == NULL
) {
243 /* Calculate how many bytes can be written. */
244 if (pos
+ bytes
> PIPE_BUF
) {
245 if (oflags
& O_NONBLOCK
) {
246 if (bytes
<= PIPE_BUF
) {
247 /* Write has to be atomic */
251 /* Compute available space */
252 bytes
= PIPE_BUF
- pos
;
255 /* Do a partial write. Need to wakeup reader */
257 release(vp
, VFS_READ
, susp_count
);
265 if (bytes
> PIPE_BUF
) {
266 /* Compute available space */
267 bytes
= PIPE_BUF
- pos
;
270 /* Do a partial write. Need to wakeup reader
271 * since we'll suspend ourself in read_write()
274 release(vp
, VFS_READ
, susp_count
);
283 /* Writing to an empty pipe. Search for suspended reader. */
284 if (pos
== 0 && !notouch
)
285 release(vp
, VFS_READ
, susp_count
);
287 /* Requested amount fits */
292 /*===========================================================================*
294 *===========================================================================*/
295 void suspend(int why
)
297 /* Take measures to suspend the processing of the present system call.
298 * Store the parameters to be used upon resuming in the process table.
299 * (Actually they are not used when a process is waiting for an I/O device,
300 * but they are needed for pipes, and it is not worth making the distinction.)
301 * The SUSPEND pseudo error should be returned after calling suspend().
304 if (why
== FP_BLOCKED_ON_POPEN
|| why
== FP_BLOCKED_ON_PIPE
)
305 /* #procs susp'ed on pipe*/
308 fp
->fp_blocked_on
= why
;
309 assert(fp
->fp_grant
== GRANT_INVALID
|| !GRANT_VALID(fp
->fp_grant
));
310 fp
->fp_block_callnr
= job_call_nr
;
313 /*===========================================================================*
315 *===========================================================================*/
316 void wait_for(endpoint_t who
)
318 if(who
== NONE
|| who
== ANY
)
319 panic("suspend on NONE or ANY");
320 suspend(FP_BLOCKED_ON_OTHER
);
325 /*===========================================================================*
327 *===========================================================================*/
328 void pipe_suspend(filp
, buf
, size
)
333 /* Take measures to suspend the processing of the present system call.
334 * Store the parameters to be used upon resuming in the process table.
337 scratch(fp
).file
.filp
= filp
;
338 scratch(fp
).io
.io_buffer
= buf
;
339 scratch(fp
).io
.io_nbytes
= size
;
340 suspend(FP_BLOCKED_ON_PIPE
);
344 /*===========================================================================*
345 * unsuspend_by_endpt *
346 *===========================================================================*/
347 void unsuspend_by_endpt(endpoint_t proc_e
)
349 /* Revive processes waiting for drivers (SUSPENDed) that have disappeared with
350 * return code EAGAIN.
354 for (rp
= &fproc
[0]; rp
< &fproc
[NR_PROCS
]; rp
++) {
355 if (rp
->fp_pid
== PID_FREE
) continue;
356 if (rp
->fp_blocked_on
== FP_BLOCKED_ON_OTHER
&& rp
->fp_task
== proc_e
)
357 revive(rp
->fp_endpoint
, EIO
);
360 /* Revive processes waiting in drivers on select()s with EAGAIN too */
361 select_unsuspend_by_endpt(proc_e
);
367 /*===========================================================================*
369 *===========================================================================*/
370 void release(vp
, op
, count
)
371 register struct vnode
*vp
; /* inode of pipe */
372 int op
; /* VFS_READ, VFS_WRITE, or VFS_OPEN */
373 int count
; /* max number of processes to release */
375 /* Check to see if any process is hanging on vnode 'vp'. If one is, and it
376 * was trying to perform the call indicated by 'op', release it.
379 register struct fproc
*rp
;
383 /* Trying to perform the call also includes SELECTing on it with that
386 if (op
== VFS_READ
|| op
== VFS_WRITE
) {
392 for (f
= &filp
[0]; f
< &filp
[NR_FILPS
]; f
++) {
393 if (f
->filp_count
< 1 || !(f
->filp_pipe_select_ops
& selop
) ||
397 select_callback(f
, selop
);
399 f
->filp_pipe_select_ops
&= ~selop
;
403 /* Search the proc table. */
404 for (rp
= &fproc
[0]; rp
< &fproc
[NR_PROCS
] && count
> 0; rp
++) {
405 if (rp
->fp_pid
!= PID_FREE
&& fp_is_blocked(rp
) &&
406 !(rp
->fp_flags
& FP_REVIVED
) && rp
->fp_block_callnr
== op
) {
407 /* Find the vnode. Depending on the reason the process was
408 * suspended, there are different ways of finding it.
411 if (rp
->fp_blocked_on
== FP_BLOCKED_ON_POPEN
||
412 rp
->fp_blocked_on
== FP_BLOCKED_ON_LOCK
||
413 rp
->fp_blocked_on
== FP_BLOCKED_ON_OTHER
) {
414 f
= rp
->fp_filp
[scratch(rp
).file
.fd_nr
];
415 if (f
== NULL
|| f
->filp_mode
== FILP_CLOSED
)
417 if (rp
->fp_filp
[scratch(rp
).file
.fd_nr
]->filp_vno
!= vp
)
419 } else if (rp
->fp_blocked_on
== FP_BLOCKED_ON_PIPE
) {
420 if (scratch(rp
).file
.filp
== NULL
)
422 if (scratch(rp
).file
.filp
->filp_vno
!= vp
)
427 /* We found the vnode. Revive process. */
428 revive(rp
->fp_endpoint
, 0);
429 susp_count
--; /* keep track of who is suspended */
431 panic("susp_count now negative: %d", susp_count
);
432 if (--count
== 0) return;
438 /*===========================================================================*
440 *===========================================================================*/
441 void revive(endpoint_t proc_e
, int returned
)
443 /* Revive a previously blocked process. When a process hangs on tty, this
444 * is the way it is eventually released. For processes blocked on _SELECT and
445 * _OTHER, this function MUST NOT block its calling thread.
451 if (proc_e
== NONE
|| isokendpt(proc_e
, &slot
) != OK
) return;
454 if (!fp_is_blocked(rfp
) || (rfp
->fp_flags
& FP_REVIVED
)) return;
456 /* The 'reviving' flag only applies to pipes. Processes waiting for TTY get
457 * a message right away. The revival process is different for TTY and pipes.
458 * For select and TTY revival, the work is already done, for pipes it is not:
459 * the proc must be restarted so it can try again.
461 blocked_on
= rfp
->fp_blocked_on
;
462 fd_nr
= scratch(rfp
).file
.fd_nr
;
463 if (blocked_on
== FP_BLOCKED_ON_PIPE
|| blocked_on
== FP_BLOCKED_ON_LOCK
) {
464 /* Revive a process suspended on a pipe or lock. */
465 rfp
->fp_flags
|= FP_REVIVED
;
466 reviving
++; /* process was waiting on pipe or lock */
468 rfp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
469 scratch(rfp
).file
.fd_nr
= 0;
470 if (blocked_on
== FP_BLOCKED_ON_POPEN
) {
471 /* process blocked in open or create */
472 replycode(proc_e
, fd_nr
);
473 } else if (blocked_on
== FP_BLOCKED_ON_SELECT
) {
474 replycode(proc_e
, returned
);
476 /* Revive a process suspended on TTY or other device.
477 * Pretend it wants only what there is.
479 scratch(rfp
).io
.io_nbytes
= returned
;
480 /* If a grant has been issued by FS for this I/O, revoke
481 * it again now that I/O is done.
483 if (GRANT_VALID(rfp
->fp_grant
)) {
484 if(cpf_revoke(rfp
->fp_grant
)) {
485 panic("VFS: revoke failed for grant: %d",
488 rfp
->fp_grant
= GRANT_INVALID
;
490 replycode(proc_e
, returned
);/* unblock the process */
496 /*===========================================================================*
498 *===========================================================================*/
501 /* A signal has been sent to a user who is paused on the file system.
502 * Abort the system call with the EINTR error message.
504 int blocked_on
, fild
, status
= EINTR
;
509 if (!fp_is_blocked(fp
)) return;
510 blocked_on
= fp
->fp_blocked_on
;
512 /* Clear the block status now. The procedure below might make blocking calls
513 * and it is imperative that while at least cdev_cancel() is executing, other
514 * parts of VFS do not perceive this process as blocked on something.
516 fp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
518 if (fp
->fp_flags
& FP_REVIVED
) {
519 fp
->fp_flags
&= ~FP_REVIVED
;
524 switch (blocked_on
) {
525 case FP_BLOCKED_ON_PIPE
:/* process trying to read or write a pipe */
526 /* If the operation succeeded partially, return the bytes
527 * processed so far, and clear the remembered state. Otherwise,
528 * return EINTR as usual.
530 if (fp
->fp_cum_io_partial
> 0) {
531 status
= fp
->fp_cum_io_partial
;
533 fp
->fp_cum_io_partial
= 0;
537 case FP_BLOCKED_ON_LOCK
:/* process trying to set a lock with FCNTL */
540 case FP_BLOCKED_ON_SELECT
:/* process blocking on select() */
544 case FP_BLOCKED_ON_POPEN
: /* process trying to open a fifo */
547 case FP_BLOCKED_ON_OTHER
:/* process trying to do device I/O (e.g. tty)*/
548 fild
= scratch(fp
).file
.fd_nr
;
549 if (fild
< 0 || fild
>= OPEN_MAX
)
550 panic("file descriptor out-of-range");
551 f
= fp
->fp_filp
[fild
];
553 sys_diagctl_stacktrace(fp
->fp_endpoint
);
554 panic("process %d blocked on empty fd %d",
555 fp
->fp_endpoint
, fild
);
557 dev
= f
->filp_vno
->v_sdev
; /* device hung on */
559 status
= cdev_cancel(dev
);
563 panic("VFS: unknown block reason: %d", blocked_on
);
566 if ((blocked_on
== FP_BLOCKED_ON_PIPE
|| blocked_on
== FP_BLOCKED_ON_POPEN
)&&
571 replycode(fp
->fp_endpoint
, status
); /* signal interrupted call */