more stack for boot
[minix.git] / servers / vfs / pipe.c
blob12148c450c424c308882fce13fbf80fb0256891a
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
5 * to continue.
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
12 * it
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
18 #include "fs.h"
19 #include <fcntl.h>
20 #include <signal.h>
21 #include <assert.h>
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>
27 #include <sys/time.h>
28 #include "file.h"
29 #include "fproc.h"
30 #include "param.h"
31 #include "select.h"
32 #include <minix/vfsif.h>
33 #include "vnode.h"
34 #include "vmnt.h"
37 /*===========================================================================*
38 * do_pipe *
39 *===========================================================================*/
40 PUBLIC int do_pipe()
42 /* Perform the pipe(fil_des) system call. */
44 register struct fproc *rfp;
45 int r;
46 struct filp *fil_ptr0, *fil_ptr1;
47 int fil_des[2]; /* reply goes here */
48 struct vnode *vp;
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. */
55 rfp = fp;
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;
64 return(r);
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,
72 (dev_t) 0, &res);
74 if (r != OK) {
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;
81 return(r);
84 /* Fill in vnode */
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;
90 vp->v_pipe = I_PIPE;
91 vp->v_pipe_rd_pos= 0;
92 vp->v_pipe_wr_pos= 0;
93 vp->v_fs_count = 1;
94 vp->v_mapfs_count = 1;
95 vp->v_ref_count = 1;
96 vp->v_size = 0;
97 vp->v_vmnt = NIL_VMNT;
98 vp->v_dev = NO_DEV;
100 /* Fill in filp objects */
101 fil_ptr0->filp_vno = vp;
102 dup_vnode(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];
110 return(OK);
114 /*===========================================================================*
115 * map_vnode *
116 *===========================================================================*/
117 PUBLIC int map_vnode(vp)
118 struct vnode *vp;
120 int r;
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;
135 return(r);
139 /*===========================================================================*
140 * pipe_check *
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.
155 off_t pos;
156 int r = OK;
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) {
167 /* Writer exists */
168 if (oflags & O_NONBLOCK)
169 r = EAGAIN;
170 else
171 r = SUSPEND;
173 /* If need be, activate sleeping writers. */
174 if (susp_count > 0)
175 release(vp, WRITE, susp_count);
177 return(r);
179 return(bytes);
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);
188 return(EPIPE);
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 */
196 return(EAGAIN);
199 /* Compute available space */
200 bytes = PIPE_BUF - pos;
202 if (bytes > 0) {
203 /* Do a partial write. Need to wakeup reader */
204 if (!notouch)
205 release(vp, READ, susp_count);
206 return(bytes);
207 } else {
208 /* Pipe is full */
209 return(EAGAIN);
213 if (bytes > PIPE_BUF) {
214 /* Compute available space */
215 bytes = PIPE_BUF - pos;
217 if (bytes > 0) {
218 /* Do a partial write. Need to wakeup reader
219 * since we'll suspend ourself in read_write()
221 if (!notouch)
222 release(vp, READ, susp_count);
223 return(bytes);
227 /* Pipe is full */
228 return(SUSPEND);
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 */
236 return(bytes);
240 /*===========================================================================*
241 * suspend *
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().
252 #if DO_SANITYCHECKS
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");
261 #endif
263 if (why == FP_BLOCKED_ON_POPEN)
264 /* #procs susp'ed on pipe*/
265 susp_count++;
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() */
276 } else {
277 fp->fp_buffer = m_in.buffer; /* for reads and writes */
278 fp->fp_nbytes = m_in.nbytes;
283 /*===========================================================================*
284 * wait_for *
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);
291 fp->fp_task = who;
295 /*===========================================================================*
296 * pipe_suspend *
297 *===========================================================================*/
298 PUBLIC void pipe_suspend(rw_flag, fd_nr, buf, size)
299 int rw_flag;
300 int fd_nr;
301 char *buf;
302 size_t 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().
310 #if DO_SANITYCHECKS
311 if(fp_is_blocked(fp))
312 panic("pipe_suspend: called for suspended process");
313 #endif
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);
319 fp->fp_buffer = buf;
320 fp->fp_nbytes = size;
324 /*===========================================================================*
325 * unsuspend_by_endpt *
326 *===========================================================================*/
327 PUBLIC void unsuspend_by_endpt(endpoint_t proc_e)
329 struct fproc *rp;
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
341 * with EAGAIN too.
343 select_unsuspend_by_endpt(proc_e);
345 return;
349 /*===========================================================================*
350 * release *
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',
359 * release it.
362 register struct fproc *rp;
363 struct filp *f;
365 /* Trying to perform the call also includes SELECTing on it with that
366 * operation.
368 if (call_nr == READ || call_nr == WRITE) {
369 int op;
370 if (call_nr == READ)
371 op = SEL_RD;
372 else
373 op = SEL_WR;
374 for(f = &filp[0]; f < &filp[NR_FILPS]; f++) {
375 if (f->filp_count < 1 || !(f->filp_pipe_select_ops & op) ||
376 f->filp_vno != vp)
377 continue;
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 */
390 if(susp_count < 0)
391 panic("susp_count now negative: %d", susp_count);
392 if (--count == 0) return;
398 /*===========================================================================*
399 * revive *
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;
409 int blocked_on;
410 int fd_nr, proc_nr;
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;
431 if (returned < 0) {
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);
443 } else
444 reply(proc_nr_e, fd_nr);
445 } else {
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);
452 } else {
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",
463 rfp->fp_grant);
465 rfp->fp_grant = GRANT_INVALID;
467 reply(proc_nr_e, returned); /* unblock the process */
473 /*===========================================================================*
474 * unpause *
475 *===========================================================================*/
476 PUBLIC void unpause(proc_nr_e)
477 int 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;
485 struct filp *f;
486 dev_t dev;
487 message mess;
488 int wasreviving = 0;
490 if(isokendpt(proc_nr_e, &proc_nr_p) != OK) {
491 printf("VFS: ignoring unpause for bogus endpoint %d\n", proc_nr_e);
492 return;
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;
501 reviving--;
502 wasreviving = 1;
505 switch (blocked_on) {
506 case FP_BLOCKED_ON_PIPE:/* process trying to read or write a pipe */
507 break;
509 case FP_BLOCKED_ON_LOCK:/* process trying to set a lock with FCNTL */
510 break;
512 case FP_BLOCKED_ON_SELECT:/* process blocking on select() */
513 select_forget(proc_nr_e);
514 break;
516 case FP_BLOCKED_ON_POPEN: /* process trying to open a fifo */
517 break;
519 case FP_BLOCKED_ON_DOPEN:/* process trying to open a device */
520 /* Don't cancel OPEN. Just wait until the open completes. */
521 return;
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.
526 * Just reply EINTR.
528 rfp->fp_flags &= ~SUSP_REOPEN;
529 status = EINTR;
530 break;
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
550 * later time.
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",
557 rfp->fp_grant);
559 rfp->fp_grant = GRANT_INVALID;
561 break;
562 default :
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) &&
570 !wasreviving) {
571 susp_count--;
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;
584 orig_ops = *ops;
585 if ((*ops & (SEL_RD|SEL_ERR))) {
586 if ((err = pipe_check(f->filp_vno, READING, 0,
587 1, f->filp_pos, 1)) != SUSPEND)
588 r |= SEL_RD;
589 if (err < 0 && err != SUSPEND)
590 r |= SEL_ERR;
591 if(err == SUSPEND && f->filp_mode & W_BIT) {
592 /* A "meaningless" read select, therefore ready
593 for reading and no error set. */
594 r |= SEL_RD;
595 r &= ~SEL_ERR;
599 if ((*ops & (SEL_WR|SEL_ERR))) {
600 if ((err = pipe_check(f->filp_vno, WRITING, 0,
601 1, f->filp_pos, 1)) != SUSPEND)
602 r |= SEL_WR;
603 if (err < 0 && err != SUSPEND)
604 r |= SEL_ERR;
605 if(err == SUSPEND && f->filp_mode & R_BIT) {
606 /* A "meaningless" write select, therefore ready
607 for reading and no error set. */
608 r |= SEL_WR;
609 r &= ~SEL_ERR;
613 /* Some options we collected might not be requested. */
614 *ops = r & orig_ops;
616 if (!*ops && block) {
617 f->filp_pipe_select_ops |= orig_ops;
620 return(SEL_OK);
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))
631 return 1;
632 return 0;
635 #if DO_SANITYCHECKS
636 /*===========================================================================*
637 * check_pipe *
638 *===========================================================================*/
639 PUBLIC int check_pipe(void)
641 struct fproc *rfp;
642 int mycount = 0;
643 for (rfp=&fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
644 if (rfp->fp_pid == PID_FREE)
645 continue;
646 if(rfp->fp_revived != REVIVING &&
647 (rfp->fp_blocked_on == FP_BLOCKED_ON_PIPE ||
648 rfp->fp_blocked_on == FP_BLOCKED_ON_POPEN)) {
649 mycount++;
653 if(mycount != susp_count) {
654 printf("check_pipe: mycount %d susp_count %d\n",
655 mycount, susp_count);
656 return 0;
659 return 1;
661 #endif