home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / pd / programming / gnuc / library / rcs / pipe.c,v < prev    next >
Encoding:
Text File  |  1992-07-04  |  12.4 KB  |  569 lines

  1. head    1.2;
  2. access;
  3. symbols
  4.     version39-41:1.2;
  5. locks;
  6. comment    @ *  @;
  7.  
  8.  
  9. 1.2
  10. date    92.07.04.19.21.08;    author mwild;    state Exp;
  11. branches;
  12. next    1.1;
  13.  
  14. 1.1
  15. date    92.05.14.19.55.40;    author mwild;    state Exp;
  16. branches;
  17. next    ;
  18.  
  19.  
  20. desc
  21. @create pair of pipes
  22. @
  23.  
  24.  
  25. 1.2
  26. log
  27. @(finally..) fix the bug which could cause pipe readers/writers to deadlock
  28. @
  29. text
  30. @/*
  31.  *  This file is part of ixemul.library for the Amiga.
  32.  *  Copyright (C) 1991, 1992  Markus M. Wild
  33.  *
  34.  *  This library is free software; you can redistribute it and/or
  35.  *  modify it under the terms of the GNU Library General Public
  36.  *  License as published by the Free Software Foundation; either
  37.  *  version 2 of the License, or (at your option) any later version.
  38.  *
  39.  *  This library is distributed in the hope that it will be useful,
  40.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  41.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  42.  *  Library General Public License for more details.
  43.  *
  44.  *  You should have received a copy of the GNU Library General Public
  45.  *  License along with this library; if not, write to the Free
  46.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  47.  *
  48.  *  $Id: pipe.c,v 1.1 1992/05/14 19:55:40 mwild Exp $
  49.  *
  50.  *  $Log: pipe.c,v $
  51.  * Revision 1.1  1992/05/14  19:55:40  mwild
  52.  * Initial revision
  53.  *
  54.  */
  55.  
  56. #define KERNEL
  57. #include "ixemul.h"
  58. #include <sys/ioctl.h>
  59. #include "select.h"
  60.  
  61. /* #undef DEBUG */
  62. #ifdef DEBUG
  63. #define DP(a) do {Disable (); kprintf a; Enable ();} while (0)
  64. #else
  65. #define DP(a)
  66. #endif
  67.  
  68. /* information for the temporary implementation of pipes.
  69.    PIPE: has the big disadvantage that it blocks in the most unpleasent
  70.    situations, and doesn't send SIGPIPE to processes that write on
  71.    readerless pipes. Unacceptable for this library ;-)) */
  72.  
  73. #define PIPE_SIZE    5120
  74.  
  75. struct tmp_pipe {
  76.   u_short    tp_flags;        /* see below */
  77.   u_char    tp_buffer[PIPE_SIZE];
  78.   u_char    *tp_reader, *tp_writer;    /* buffer pointers.
  79.                        when tp_reader==tp_writer, no data
  80.                        is available */
  81. };
  82.  
  83. #define TPF_NO_READER    (1<<0)
  84. #define TPF_NO_WRITER    (1<<1)
  85. #define TPF_LOCKED    (1<<2)
  86. #define TPF_WANT_LOCK    (1<<3)
  87.  
  88. static int __pread(), __pwrite(), __pselect(), __pioctl(), __pclose();
  89. static struct tmp_pipe *__pinit();
  90.  
  91. static inline void
  92. __get_pipe (struct file *f)
  93. {
  94.   struct tmp_pipe *tp = f->f_tp;
  95.  
  96. retry:  
  97.   Forbid ();
  98.   for (;;)
  99.     {
  100.       if (!(tp->tp_flags & TPF_LOCKED))
  101.         {
  102.           tp->tp_flags &= ~TPF_WANT_LOCK;
  103.           tp->tp_flags |= TPF_LOCKED;
  104.           /* got it ! */
  105.           break;
  106.     }
  107.       tp->tp_flags |= TPF_WANT_LOCK;
  108. DP(("__get_pipe: going to sleep\n"));
  109.       if (ix_sleep (&tp->tp_flags, "get_pipe") < 0)
  110.         {
  111. DP(("__get_pipe: interrupted\n"));
  112.       Permit ();
  113.       setrun (FindTask (0));
  114.           goto retry;
  115.         }
  116. DP(("__get_pipe: back from sleep (not interrupted)\n"));
  117.       /* have to always recheck whether we really got the lock */
  118.     }
  119.   Permit ();      
  120. }
  121.  
  122. static inline void
  123. __release_pipe (struct file *f)
  124. {
  125.   struct tmp_pipe *tp = f->f_tp;
  126.  
  127.   Forbid ();
  128.   if (tp->tp_flags & TPF_WANT_LOCK)
  129.     ix_wakeup (&tp->tp_flags);
  130.     
  131.   tp->tp_flags &= ~(TPF_WANT_LOCK|TPF_LOCKED);
  132.   Permit ();
  133. }
  134.  
  135.  
  136. int
  137. pipe (int pv[2])
  138. {
  139.   struct file *f1, *f2;
  140.   struct tmp_pipe *tp;
  141.   int res, err, omask;
  142.   
  143.   omask = syscall (SYS_sigsetmask, ~0);
  144.   res = -1; 
  145.   err = EMFILE;
  146.   if (tp = __pinit ())
  147.     {
  148.       if (! falloc (&f1, pv))
  149.         {
  150.           if (! falloc (&f2, pv+1))
  151.             {
  152.           f1->f_tp     = tp;
  153.           f1->f_stb.st_mode = 0666 | S_IFCHR;
  154.           f1->f_stb.st_size = PIPE_SIZE;
  155.           f1->f_stb.st_blksize = 512;
  156.           f1->f_flags  = FREAD;
  157.           f1->f_type   = DTYPE_PIPE;
  158.           f1->f_read   = __pread;
  159.           f1->f_write  = 0;
  160.           f1->f_ioctl  = __pioctl;
  161.           f1->f_close  = __pclose;
  162.           f1->f_select = __pselect;
  163.  
  164.           f2->f_tp     = tp;
  165.           f2->f_stb.st_mode = 0666 | S_IFCHR;
  166.           f2->f_stb.st_size = PIPE_SIZE;
  167.           f2->f_stb.st_blksize = 512;
  168.           f2->f_flags  = FWRITE;
  169.           f2->f_type   = DTYPE_PIPE;
  170.           f2->f_read   = 0;
  171.           f2->f_write  = __pwrite;
  172.           f2->f_ioctl  = __pioctl;
  173.           f2->f_close  = __pclose;
  174.           f2->f_select = __pselect;
  175.  
  176.           res = err =0;
  177.           goto ret;
  178.         }
  179.       f1->f_count = 0;
  180.     }
  181.  
  182.       kfree (tp);
  183.     }
  184.  
  185. ret:
  186.   syscall (SYS_sigsetmask, omask);
  187.  
  188.   errno = err;
  189.   return res;
  190. }
  191.  
  192. static struct tmp_pipe *
  193. __pinit (void)
  194. {
  195.   struct tmp_pipe *tp = (struct tmp_pipe *) kmalloc (sizeof (*tp));
  196.   
  197.   if (tp)
  198.     {
  199.       tp->tp_flags = 0;
  200.       tp->tp_reader = tp->tp_writer = tp->tp_buffer;
  201.     }
  202.  
  203.   return tp;
  204. }
  205.  
  206. static int
  207. __pclose (struct file *f)
  208. {
  209.   int omask;
  210.  
  211.   ix_lock_base ();
  212.  
  213.   f->f_count--;
  214.  
  215.   if (f->f_count == 0)
  216.     {
  217.       if (f->f_read)
  218.         f->f_tp->tp_flags |= TPF_NO_READER;
  219.       else
  220.     f->f_tp->tp_flags |= TPF_NO_WRITER;
  221.     
  222.       if ((f->f_tp->tp_flags & (TPF_NO_READER|TPF_NO_WRITER)) ==
  223.       (TPF_NO_READER|TPF_NO_WRITER))
  224.     kfree (f->f_tp);
  225.       else
  226.     ix_wakeup (f->f_tp);
  227.     }
  228.  
  229.   ix_unlock_base ();
  230.  
  231.   return 0;
  232.   
  233. }
  234.  
  235. static int
  236. __pread (struct file *f, char *buf, int len)
  237. {
  238.   int omask = syscall (SYS_sigsetmask, ~0);
  239.   int err = errno;
  240.   int really_read = 0;
  241.   struct tmp_pipe *tp = f->f_tp;
  242.  
  243.   __get_pipe (f);
  244.  
  245.   while (len)
  246.     {
  247.       if (tp->tp_reader == tp->tp_writer)
  248.     {
  249. DP(("__pread: len == %ld, buffer full\n", len));
  250.       if (tp->tp_flags & TPF_NO_WRITER)
  251.         {
  252. DP(("__pread: EOF\n"));
  253.           err = 0;
  254.           break;
  255.         }
  256.     
  257.       if (f->f_flags & FNDELAY)
  258.         {
  259.           if (! really_read)
  260.         {
  261.           really_read = -1;
  262.           err = EWOULDBLOCK;    /* is this the right thing to do ?????? */
  263.         }
  264.           break;
  265.         }
  266.       else
  267.         {
  268.           int sleep_rc;
  269. DP(("__pread: going to sleep.\n"));
  270.           /* wait for something to be read or all readers to close */
  271.           Forbid ();
  272.           /* sigh.. Forbid() is necessary, or the other end may change
  273.              the pipe, and in the worst case also settle for sleep(), and
  274.              there it is.. deadlock.. */
  275.           __release_pipe (f);
  276.  
  277.           /* make write interruptible */
  278.           syscall (SYS_sigsetmask, omask);
  279.           sleep_rc = ix_sleep (tp, "pwrite");
  280.           Permit ();
  281.           if (sleep_rc < 0)
  282.             setrun (FindTask (0));
  283.           omask = syscall (SYS_sigsetmask, ~0);
  284.  
  285.           __get_pipe (f);
  286.           continue;        /* retry */
  287.         }
  288.     }
  289.       else
  290.     {
  291.       /* okay, there's something to read from the pipe */
  292.       if (tp->tp_reader > tp->tp_writer)
  293.         {
  294.           /* read till end of buffer and wrap around */
  295.           int avail = PIPE_SIZE - (tp->tp_reader - tp->tp_buffer);
  296.           int do_read = len < avail ? len : avail;
  297.  
  298. /* DP(("__pread-1: reading %ld bytes.\n", do_read)); */
  299.  
  300.           really_read += do_read;
  301.           bcopy (tp->tp_reader, buf, do_read);
  302.           len -= do_read;
  303.           buf += do_read;
  304.           tp->tp_reader += do_read;
  305.           if (tp->tp_reader - tp->tp_buffer == PIPE_SIZE)
  306.         /* wrap around */
  307.         tp->tp_reader = tp->tp_buffer;
  308.         }
  309.       if (len && tp->tp_reader < tp->tp_writer)
  310.         {
  311.           int avail = tp->tp_writer - tp->tp_reader;
  312.           int do_read = len < avail ? len : avail;
  313.  
  314. /* DP(("__pread-2: reading %ld bytes.\n", do_read)); */
  315.  
  316.           really_read += do_read;
  317.           bcopy (tp->tp_reader, buf, do_read);
  318.           tp->tp_reader += do_read;
  319.           len -= do_read;
  320.           buf += do_read;
  321.         }
  322.     }
  323.  
  324.       ix_wakeup (tp);
  325.     }
  326.  
  327.   __release_pipe (f);
  328.  
  329.   syscall (SYS_sigsetmask, omask);
  330.   errno = err;
  331.   return really_read;
  332. }
  333.  
  334.  
  335. static int
  336. __pwrite (struct file *f, char *buf, int len)
  337. {
  338.   int  omask = syscall (SYS_sigsetmask, ~0);
  339.   int err = errno;
  340.   int really_written = 0;
  341.   struct tmp_pipe *tp = f->f_tp;
  342.  
  343.   __get_pipe (f);
  344.  
  345.   while (len)
  346.     {
  347.       if (tp->tp_flags & TPF_NO_READER)
  348.     {
  349. DP(("__pwrite: SIGPIPE\n"));
  350.       really_written = -1;
  351.       err = EINTR;
  352.       /* this is something no `real' Amiga pipe handler will do ;-)) */
  353.       _psignal (FindTask (0), SIGPIPE);
  354.       break;
  355.         }
  356.     
  357.       /* buffer full ?? */
  358.       if (tp->tp_reader == tp->tp_writer + 1
  359.       || (tp->tp_reader == tp->tp_buffer 
  360.           && tp->tp_writer == tp->tp_buffer + PIPE_SIZE - 1))
  361.     {
  362. DP(("__pwrite: buffer full, len == %ld\n", len));
  363.       if (f->f_flags & FNDELAY)
  364.         {
  365.           if (! really_written)
  366.             {
  367.               really_written = -1;
  368.               err = EWOULDBLOCK;
  369.             }
  370.           break;
  371.         }
  372.       else
  373.         {
  374.           int sleep_rc;
  375. DP(("__pwrite: going to sleep\n"));
  376.           /* wait for something to be read or all readers to close */
  377.           Forbid ();
  378.           /* sigh.. Forbid() is necessary, or the other end may change
  379.              the pipe, and in the worst case also settle for sleep(), and
  380.              there it is.. deadlock.. */
  381.           __release_pipe (f);
  382.  
  383.           /* make write interruptible */
  384.           syscall (SYS_sigsetmask, omask);
  385.           sleep_rc = ix_sleep (tp, "pwrite");
  386.           Permit ();
  387.           if (sleep_rc < 0)
  388.             setrun (FindTask (0));
  389.           omask = syscall (SYS_sigsetmask, ~0);
  390.  
  391.           __get_pipe (f);
  392.           continue;        /* retry */
  393.         }
  394.     }
  395.       else
  396.     {
  397.       /* okay, there's some space left to write to the pipe */
  398.  
  399.       if (tp->tp_writer >= tp->tp_reader)
  400.         {
  401.           /* write till end of buffer */
  402.           int avail = PIPE_SIZE - 1 - (tp->tp_writer - tp->tp_buffer);
  403.           int do_write;
  404.  
  405.           if (tp->tp_reader > tp->tp_buffer)
  406.             avail++;
  407.           do_write = len < avail ? len : avail;
  408.  
  409. /* DP(("__pwrite-1: writing %ld bytes.\n", do_write)); */
  410.           really_written += do_write;
  411.           bcopy (buf, tp->tp_writer, do_write);
  412.           len -= do_write;
  413.           buf += do_write;
  414.           tp->tp_writer += do_write;
  415.           if (tp->tp_writer - tp->tp_buffer == PIPE_SIZE)
  416.             tp->tp_writer = tp->tp_buffer;
  417.         }
  418.  
  419.       if (tp->tp_writer < tp->tp_reader - 1)
  420.         {
  421.           int avail = tp->tp_reader - tp->tp_writer - 1;
  422.           int do_write = len < avail ? len : avail;
  423.  
  424. /* DP(("__pwrite-2: writing %ld bytes.\n", do_write)); */
  425.           really_written += do_write;
  426.           bcopy (buf, tp->tp_writer, do_write);
  427.           tp->tp_writer += do_write;
  428.           len -= do_write;
  429.           buf += do_write;
  430.         }
  431.     }
  432.     
  433.       ix_wakeup (tp);
  434.     }
  435.  
  436.   __release_pipe (f);
  437.  
  438.   syscall (SYS_sigsetmask, omask);
  439.   errno = err;
  440.   return really_written;
  441. }
  442.  
  443. static int
  444. __pselect (struct file *f, int select_cmd, int io_mode)
  445. {
  446.   struct tmp_pipe *tp = f->f_tp;
  447.  
  448.   /* I currently only check whether io is possible, no setup needed.
  449.      This would be quite different if select() waited the given timeout,
  450.      and wouldn't split the timeout into smaller slices */
  451.  
  452.   if (select_cmd == SELCMD_CHECK)
  453.     {
  454.       /* we support both, read and write checks (hey, something new ;-)) */
  455.       if (io_mode == SELMODE_IN)
  456.     return tp->tp_reader != tp->tp_writer;
  457.  
  458.       else if (io_mode == SELMODE_OUT)
  459.     return !(tp->tp_reader == tp->tp_writer + 1
  460.          || (tp->tp_reader == tp->tp_buffer 
  461.              && tp->tp_writer == tp->tp_buffer + PIPE_SIZE - 1));
  462.     }
  463.  
  464.   return 0;
  465. }
  466.  
  467. static int
  468. __pioctl (struct file *f, unsigned int cmd, unsigned int inout,
  469.           unsigned int arglen, unsigned int arg)
  470. {
  471.   int omask;
  472.   int result;
  473.   struct tmp_pipe *tp = f->f_tp;
  474.   
  475.   omask = syscall (SYS_sigsetmask, ~0);
  476.   __get_pipe (f);
  477.  
  478.   switch (cmd)
  479.     {
  480.     case FIONREAD:
  481.       {
  482.     unsigned int *pt = (unsigned int *)arg;
  483.     if (tp->tp_reader < tp->tp_writer)
  484.       *pt = tp->tp_writer - tp->tp_reader;
  485.     else if (tp->tp_reader > tp->tp_writer)
  486.       *pt = PIPE_SIZE - (tp->tp_reader - tp->tp_writer);
  487.     else
  488.       *pt = 0;
  489.     result = 0;
  490.         break;
  491.       }
  492.  
  493.     case FIONBIO:
  494.       {
  495.     result = f->f_flags & FNDELAY ? 1 : 0;
  496.     if (*(unsigned int *)arg)
  497.       f->f_flags |= FNDELAY;
  498.     else
  499.       f->f_flags &= ~FNDELAY;
  500.     /* I didn't find it documented in a manpage, but I assume, we
  501.      * should return the former state, not just zero.. */
  502.     break;
  503.       }
  504.  
  505.     case FIOASYNC:
  506.       {
  507.     /* DOESN'T WORK YET */
  508.  
  509.     int flags = *(unsigned long*)arg;
  510.     result = f->f_flags & FASYNC ? 1 : 0;
  511.     if (flags)
  512.       f->f_flags |= FASYNC;
  513.     else
  514.       f->f_flags &= ~FASYNC;
  515.  
  516.     /* ATTENTION: have to call some function here in the future !!! */
  517.  
  518.     /* I didn't find it documented in a manpage, but I assume, we
  519.      * should return the former state, not just zero.. */
  520.     break;
  521.       }
  522.  
  523.     case FIOCLEX:
  524.     case FIONCLEX:
  525.     case FIOSETOWN:
  526.     case FIOGETOWN:
  527.       /* this is no error, but nevertheless we don't take any actions.. */      
  528.       result = 0;
  529.       break;
  530.     }
  531.  
  532.   __release_pipe (f);
  533.   syscall (SYS_sigsetmask, omask);
  534.   return result;
  535. }
  536. @
  537.  
  538.  
  539. 1.1
  540. log
  541. @Initial revision
  542. @
  543. text
  544. @d19 1
  545. a19 1
  546.  *  $Id$
  547. d21 4
  548. a24 1
  549.  *  $Log$
  550. d73 1
  551. d80 1
  552. a80 1
  553.       if (ix_sleep (&tp->tp_flags) < 0)
  554. d239 1
  555. d241 5
  556. a245 1
  557.           /* wait for something to arrive or all writers to close */
  558. d248 1
  559. d250 4
  560. a253 2
  561.           if (ix_sleep (tp) < 0)
  562.         setrun (FindTask (0));
  563. d345 1
  564. d348 4
  565. d356 3
  566. a358 1
  567.           if (ix_sleep (tp) < 0)
  568. @
  569.