The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/servers/fs/pipe.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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.
    6  *
    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_proc: revive all processes blocking on a given process
   15  *   do_unpause:  a signal has been sent to a process; see if it suspended
   16  */
   17 
   18 #include "fs.h"
   19 #include <fcntl.h>
   20 #include <signal.h>
   21 #include <minix/callnr.h>
   22 #include <minix/com.h>
   23 #include <sys/select.h>
   24 #include <sys/time.h>
   25 #include "file.h"
   26 #include "fproc.h"
   27 #include "inode.h"
   28 #include "param.h"
   29 #include "super.h"
   30 #include "select.h"
   31 
   32 /*===========================================================================*
   33  *                              do_pipe                                      *
   34  *===========================================================================*/
   35 PUBLIC int do_pipe()
   36 {
   37 /* Perform the pipe(fil_des) system call. */
   38 
   39   register struct fproc *rfp;
   40   register struct inode *rip;
   41   int r;
   42   struct filp *fil_ptr0, *fil_ptr1;
   43   int fil_des[2];               /* reply goes here */
   44 
   45   /* Acquire two file descriptors. */
   46   rfp = fp;
   47   if ( (r = get_fd(0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) return(r);
   48   rfp->fp_filp[fil_des[0]] = fil_ptr0;
   49   fil_ptr0->filp_count = 1;
   50   if ( (r = get_fd(0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) {
   51         rfp->fp_filp[fil_des[0]] = NIL_FILP;
   52         fil_ptr0->filp_count = 0;
   53         return(r);
   54   }
   55   rfp->fp_filp[fil_des[1]] = fil_ptr1;
   56   fil_ptr1->filp_count = 1;
   57 
   58   /* Make the inode on the pipe device. */
   59   if ( (rip = alloc_inode(root_dev, I_REGULAR) ) == NIL_INODE) {
   60         rfp->fp_filp[fil_des[0]] = NIL_FILP;
   61         fil_ptr0->filp_count = 0;
   62         rfp->fp_filp[fil_des[1]] = NIL_FILP;
   63         fil_ptr1->filp_count = 0;
   64         return(err_code);
   65   }
   66 
   67   if (read_only(rip) != OK) 
   68         panic(__FILE__,"pipe device is read only", NO_NUM);
   69  
   70   rip->i_pipe = I_PIPE;
   71   rip->i_mode &= ~I_REGULAR;
   72   rip->i_mode |= I_NAMED_PIPE;  /* pipes and FIFOs have this bit set */
   73   fil_ptr0->filp_ino = rip;
   74   fil_ptr0->filp_flags = O_RDONLY;
   75   dup_inode(rip);               /* for double usage */
   76   fil_ptr1->filp_ino = rip;
   77   fil_ptr1->filp_flags = O_WRONLY;
   78   rw_inode(rip, WRITING);       /* mark inode as allocated */
   79   m_out.reply_i1 = fil_des[0];
   80   m_out.reply_i2 = fil_des[1];
   81   rip->i_update = ATIME | CTIME | MTIME;
   82   return(OK);
   83 }
   84 
   85 /*===========================================================================*
   86  *                              pipe_check                                   *
   87  *===========================================================================*/
   88 PUBLIC int pipe_check(rip, rw_flag, oflags, bytes, position, canwrite, notouch)
   89 register struct inode *rip;     /* the inode of the pipe */
   90 int rw_flag;                    /* READING or WRITING */
   91 int oflags;                     /* flags set by open or fcntl */
   92 register int bytes;             /* bytes to be read or written (all chunks) */
   93 register off_t position;        /* current file position */
   94 int *canwrite;                  /* return: number of bytes we can write */
   95 int notouch;                    /* check only */
   96 {
   97 /* Pipes are a little different.  If a process reads from an empty pipe for
   98  * which a writer still exists, suspend the reader.  If the pipe is empty
   99  * and there is no writer, return 0 bytes.  If a process is writing to a
  100  * pipe and no one is reading from it, give a broken pipe error.
  101  */
  102 
  103   /* If reading, check for empty pipe. */
  104   if (rw_flag == READING) {
  105         if (position >= rip->i_size) {
  106                 /* Process is reading from an empty pipe. */
  107                 int r = 0;
  108                 if (find_filp(rip, W_BIT) != NIL_FILP) {
  109                         /* Writer exists */
  110                         if (oflags & O_NONBLOCK) {
  111                                 r = EAGAIN;
  112                         } else {
  113                                 if (!notouch)
  114                                         suspend(XPIPE); /* block reader */
  115                                 r = SUSPEND;
  116                         }
  117                         /* If need be, activate sleeping writers. */
  118                         if (susp_count > 0 && !notouch)
  119                                 release(rip, WRITE, susp_count);
  120                 }
  121                 return(r);
  122         }
  123   } else {
  124         /* Process is writing to a pipe. */
  125         if (find_filp(rip, R_BIT) == NIL_FILP) {
  126                 /* Tell kernel to generate a SIGPIPE signal. */
  127                 if (!notouch)
  128                         sys_kill((int)(fp - fproc), SIGPIPE);
  129                 return(EPIPE);
  130         }
  131 
  132         if (position + bytes > PIPE_SIZE(rip->i_sp->s_block_size)) {
  133                 if ((oflags & O_NONBLOCK)
  134                  && bytes < PIPE_SIZE(rip->i_sp->s_block_size))
  135                         return(EAGAIN);
  136                 else if ((oflags & O_NONBLOCK)
  137                 && bytes > PIPE_SIZE(rip->i_sp->s_block_size)) {
  138                 if ( (*canwrite = (PIPE_SIZE(rip->i_sp->s_block_size) 
  139                         - position)) > 0)  {
  140                                 /* Do a partial write. Need to wakeup reader */
  141                                 if (!notouch)
  142                                         release(rip, READ, susp_count);
  143                                 return(1);
  144                         } else {
  145                                 return(EAGAIN);
  146                         }
  147                      }
  148                 if (bytes > PIPE_SIZE(rip->i_sp->s_block_size)) {
  149                         if ((*canwrite = PIPE_SIZE(rip->i_sp->s_block_size) 
  150                                 - position) > 0) {
  151                                 /* Do a partial write. Need to wakeup reader
  152                                  * since we'll suspend ourself in read_write()
  153                                  */
  154                                 release(rip, READ, susp_count);
  155                                 return(1);
  156                         }
  157                 }
  158                 if (!notouch)
  159                         suspend(XPIPE); /* stop writer -- pipe full */
  160                 return(SUSPEND);
  161         }
  162 
  163         /* Writing to an empty pipe.  Search for suspended reader. */
  164         if (position == 0 && !notouch)
  165                 release(rip, READ, susp_count);
  166   }
  167 
  168   *canwrite = 0;
  169   return(1);
  170 }
  171 
  172 /*===========================================================================*
  173  *                              suspend                                      *
  174  *===========================================================================*/
  175 PUBLIC void suspend(task)
  176 int task;                       /* who is proc waiting for? (PIPE = pipe) */
  177 {
  178 /* Take measures to suspend the processing of the present system call.
  179  * Store the parameters to be used upon resuming in the process table.
  180  * (Actually they are not used when a process is waiting for an I/O device,
  181  * but they are needed for pipes, and it is not worth making the distinction.)
  182  * The SUSPEND pseudo error should be returned after calling suspend().
  183  */
  184 
  185   if (task == XPIPE || task == XPOPEN) susp_count++;/* #procs susp'ed on pipe*/
  186   fp->fp_suspended = SUSPENDED;
  187   fp->fp_fd = m_in.fd << 8 | call_nr;
  188   fp->fp_task = -task;
  189   if (task == XLOCK) {
  190         fp->fp_buffer = (char *) m_in.name1;    /* third arg to fcntl() */
  191         fp->fp_nbytes = m_in.request;           /* second arg to fcntl() */
  192   } else {
  193         fp->fp_buffer = m_in.buffer;            /* for reads and writes */
  194         fp->fp_nbytes = m_in.nbytes;
  195   }
  196 }
  197 
  198 /*===========================================================================*
  199  *                              unsuspend_by_proc                            *
  200  *===========================================================================*/
  201 PUBLIC void unsuspend_by_proc(int proc)
  202 {
  203   struct fproc *rp;
  204   int client = 0;
  205 
  206   /* Revive processes waiting for drivers (SUSPENDed) that have
  207    * disappeared with return code EAGAIN.
  208    */
  209   for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++, client++)
  210         if(rp->fp_suspended == SUSPENDED && rp->fp_task == -proc)
  211                 revive(client, EAGAIN);
  212 
  213   /* Revive processes waiting in drivers on select()s
  214    * with EAGAIN too.
  215    */
  216   select_unsuspend_by_proc(proc);
  217 
  218   return;
  219 }
  220 
  221 
  222 /*===========================================================================*
  223  *                              release                                      *
  224  *===========================================================================*/
  225 PUBLIC void release(ip, call_nr, count)
  226 register struct inode *ip;      /* inode of pipe */
  227 int call_nr;                    /* READ, WRITE, OPEN or CREAT */
  228 int count;                      /* max number of processes to release */
  229 {
  230 /* Check to see if any process is hanging on the pipe whose inode is in 'ip'.
  231  * If one is, and it was trying to perform the call indicated by 'call_nr',
  232  * release it.
  233  */
  234 
  235   register struct fproc *rp;
  236   struct filp *f;
  237 
  238   /* Trying to perform the call also includes SELECTing on it with that
  239    * operation.
  240    */
  241   if (call_nr == READ || call_nr == WRITE) {
  242           int op;
  243           if (call_nr == READ)
  244                 op = SEL_RD;
  245           else
  246                 op = SEL_WR;
  247           for(f = &filp[0]; f < &filp[NR_FILPS]; f++) {
  248                 if (f->filp_count < 1 || !(f->filp_pipe_select_ops & op) ||
  249                    f->filp_ino != ip)
  250                         continue;
  251                  select_callback(f, op);
  252                 f->filp_pipe_select_ops &= ~op;
  253         }
  254   }
  255 
  256   /* Search the proc table. */
  257   for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) {
  258         if (rp->fp_suspended == SUSPENDED &&
  259                         rp->fp_revived == NOT_REVIVING &&
  260                         (rp->fp_fd & BYTE) == call_nr &&
  261                         rp->fp_filp[rp->fp_fd>>8]->filp_ino == ip) {
  262                 revive((int)(rp - fproc), 0);
  263                 susp_count--;   /* keep track of who is suspended */
  264                 if (--count == 0) return;
  265         }
  266   }
  267 }
  268 
  269 /*===========================================================================*
  270  *                              revive                                       *
  271  *===========================================================================*/
  272 PUBLIC void revive(proc_nr, returned)
  273 int proc_nr;                    /* process to revive */
  274 int returned;                   /* if hanging on task, how many bytes read */
  275 {
  276 /* Revive a previously blocked process. When a process hangs on tty, this
  277  * is the way it is eventually released.
  278  */
  279 
  280   register struct fproc *rfp;
  281   register int task;
  282 
  283   if (proc_nr < 0 || proc_nr >= NR_PROCS)
  284         panic(__FILE__,"revive err", proc_nr);
  285   rfp = &fproc[proc_nr];
  286   if (rfp->fp_suspended == NOT_SUSPENDED || rfp->fp_revived == REVIVING)return;
  287 
  288   /* The 'reviving' flag only applies to pipes.  Processes waiting for TTY get
  289    * a message right away.  The revival process is different for TTY and pipes.
  290    * For select and TTY revival, the work is already done, for pipes it is not:
  291    *  the proc must be restarted so it can try again.
  292    */
  293   task = -rfp->fp_task;
  294   if (task == XPIPE || task == XLOCK) {
  295         /* Revive a process suspended on a pipe or lock. */
  296         rfp->fp_revived = REVIVING;
  297         reviving++;             /* process was waiting on pipe or lock */
  298   } else {
  299         rfp->fp_suspended = NOT_SUSPENDED;
  300         if (task == XPOPEN) /* process blocked in open or create */
  301                 reply(proc_nr, rfp->fp_fd>>8);
  302         else if (task == XSELECT) {
  303                 reply(proc_nr, returned);
  304         } else {
  305                 /* Revive a process suspended on TTY or other device. */
  306                 rfp->fp_nbytes = returned;      /*pretend it wants only what there is*/
  307                 reply(proc_nr, returned);       /* unblock the process */
  308         }
  309   }
  310 }
  311 
  312 /*===========================================================================*
  313  *                              do_unpause                                   *
  314  *===========================================================================*/
  315 PUBLIC int do_unpause()
  316 {
  317 /* A signal has been sent to a user who is paused on the file system.
  318  * Abort the system call with the EINTR error message.
  319  */
  320 
  321   register struct fproc *rfp;
  322   int proc_nr, task, fild;
  323   struct filp *f;
  324   dev_t dev;
  325   message mess;
  326 
  327   if (who > PM_PROC_NR) return(EPERM);
  328   proc_nr = m_in.pro;
  329   if (proc_nr < 0 || proc_nr >= NR_PROCS)
  330         panic(__FILE__,"unpause err 1", proc_nr);
  331   rfp = &fproc[proc_nr];
  332   if (rfp->fp_suspended == NOT_SUSPENDED) return(OK);
  333   task = -rfp->fp_task;
  334 
  335   switch (task) {
  336         case XPIPE:             /* process trying to read or write a pipe */
  337                 break;
  338 
  339         case XLOCK:             /* process trying to set a lock with FCNTL */
  340                 break;
  341 
  342         case XSELECT:           /* process blocking on select() */
  343                 select_forget(proc_nr);
  344                 break;
  345 
  346         case XPOPEN:            /* process trying to open a fifo */
  347                 break;
  348 
  349         default:                /* process trying to do device I/O (e.g. tty)*/
  350                 fild = (rfp->fp_fd >> 8) & BYTE;/* extract file descriptor */
  351                 if (fild < 0 || fild >= OPEN_MAX)
  352                         panic(__FILE__,"unpause err 2",NO_NUM);
  353                 f = rfp->fp_filp[fild];
  354                 dev = (dev_t) f->filp_ino->i_zone[0];   /* device hung on */
  355                 mess.TTY_LINE = (dev >> MINOR) & BYTE;
  356                 mess.PROC_NR = proc_nr;
  357 
  358                 /* Tell kernel R or W. Mode is from current call, not open. */
  359                 mess.COUNT = (rfp->fp_fd & BYTE) == READ ? R_BIT : W_BIT;
  360                 mess.m_type = CANCEL;
  361                 fp = rfp;       /* hack - ctty_io uses fp */
  362                 (*dmap[(dev >> MAJOR) & BYTE].dmap_io)(task, &mess);
  363   }
  364 
  365   rfp->fp_suspended = NOT_SUSPENDED;
  366   reply(proc_nr, EINTR);        /* signal interrupted call */
  367   return(OK);
  368 }
  369 
  370 /*===========================================================================*
  371  *                              select_request_pipe                          *
  372  *===========================================================================*/
  373 PUBLIC int select_request_pipe(struct filp *f, int *ops, int block)
  374 {
  375         int orig_ops, r = 0, err, canwrite;
  376         orig_ops = *ops;
  377         if ((*ops & SEL_RD)) {
  378                 if ((err = pipe_check(f->filp_ino, READING, 0,
  379                         1, f->filp_pos, &canwrite, 1)) != SUSPEND)
  380                         r |= SEL_RD;
  381                 if (err < 0 && err != SUSPEND && (*ops & SEL_ERR))
  382                         r |= SEL_ERR;
  383         }
  384         if ((*ops & SEL_WR)) {
  385                 if ((err = pipe_check(f->filp_ino, WRITING, 0,
  386                         1, f->filp_pos, &canwrite, 1)) != SUSPEND)
  387                         r |= SEL_WR;
  388                 if (err < 0 && err != SUSPEND && (*ops & SEL_ERR))
  389                         r |= SEL_ERR;
  390         }
  391 
  392         *ops = r;
  393 
  394         if (!r && block) {
  395                 f->filp_pipe_select_ops |= orig_ops;
  396         }
  397 
  398         return SEL_OK;
  399 }
  400 
  401 /*===========================================================================*
  402  *                              select_match_pipe                            *
  403  *===========================================================================*/
  404 PUBLIC int select_match_pipe(struct filp *f)
  405 {
  406         /* recognize either pipe or named pipe (FIFO) */
  407         if (f && f->filp_ino && (f->filp_ino->i_mode & I_NAMED_PIPE))
  408                 return 1;
  409         return 0;
  410 }
  411 

Cache object: 878d51fdab42525643253459c58fcb8d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.