home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 (Alt) / MACD 5.bin / workbench / libs / unixlib.lha / unix / src / pipe.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-18  |  8.8 KB  |  387 lines

  1. #include "amiga.h"
  2. #include "files.h"
  3. #include "fifofd.h"
  4. #include "signals.h"
  5. #include <sys/filio.h>
  6. #include <fcntl.h>
  7. #include <signal.h>
  8. #include <string.h>
  9. #include <stdio.h>
  10. #include <exec/memory.h>
  11. #include <amiga/ioctl.h>
  12.  
  13. extern int _sprintf(char *, const char *,...);
  14.  
  15. int __fifo_bufsize = FIFO_BUFSIZE;
  16.  
  17. /* The pipe system call, using fifo: */
  18.  
  19. static struct MsgPort *create_fifo_port(void)
  20. {
  21.     struct MsgPort *port = AllocMem(sizeof(*port), MEMF_CLEAR | MEMF_PUBLIC);
  22.  
  23.     if (!port)
  24.     return 0;
  25.     port->mp_Node.ln_Type = NT_MSGPORT;
  26.     port->mp_Flags = PA_SIGNAL;
  27.     port->mp_SigBit = _fifo_sig;
  28.     port->mp_SigTask = _us;
  29.     NewList(&port->mp_MsgList);
  30.  
  31.     return port;
  32. }
  33.  
  34. static void delete_fifo_port(struct MsgPort *port)
  35. {
  36.     FreeMem(port, sizeof(*port));
  37. }
  38.  
  39. static void free_fifo(struct fifoinfo *fi)
  40. {
  41.     if (fi->rfifo)
  42.     CloseFifo(fi->rfifo, 0);
  43.     if (fi->wfifo)
  44.     CloseFifo(fi->wfifo, FIFOF_EOF);
  45.     if (fi->rmsg)
  46.     free(fi->rmsg);
  47.     if (fi->wmsg)
  48.     free(fi->wmsg);
  49.     delete_fifo_port(fi->reply);
  50.     free(fi);
  51. }
  52.  
  53. /* Code for fd's describing fifos */
  54.  
  55. static ULONG fifo_select_start(void *userinfo, int rd, int wr, int ex)
  56. {
  57.     struct fifoinfo *fi = userinfo;
  58.  
  59.     if (rd || wr) {
  60.     if (rd)
  61.         RequestFifo(fi->rfifo, fi->rmsg, FREQ_RPEND);
  62.     if (wr)
  63.         RequestFifo(fi->wfifo, fi->wmsg, FREQ_WAVAIL);
  64.     return 1UL << _fifo_sig;
  65.     }
  66.     return 0;
  67. }
  68.  
  69. static int fifo_select_poll(void *userinfo, int *rd, int *wr, int *ex)
  70. {
  71.     struct fifoinfo *fi = userinfo;
  72.     int rabort = *rd, wabort = *wr;
  73.     struct Message *msg;
  74.  
  75.     *ex = 0;    /* we don't detect 'exceptional' conditions */
  76.     if (!*rd && !*wr)
  77.     return 0;
  78.  
  79.     while (msg = GetMsg(fi->reply)) {
  80.     if (msg == fi->rmsg)
  81.         rabort = 0;
  82.     else if (msg == fi->wmsg)
  83.         wabort = 0;
  84.     }
  85.     if (rabort) {
  86.     *rd = 0;
  87.     RequestFifo(fi->rfifo, fi->rmsg, FREQ_ABORT);
  88.     }
  89.     if (wabort) {
  90.     *wr = 0;
  91.     RequestFifo(fi->wfifo, fi->wmsg, FREQ_ABORT);
  92.     }
  93.     while (rabort || wabort) {
  94.     while (!(msg = GetMsg(fi->reply)))
  95.         Wait(1UL << _fifo_sig);
  96.     if (msg == fi->rmsg)
  97.         rabort = 0;
  98.     else if (msg == fi->wmsg)
  99.         wabort = 0;
  100.     }
  101.     /* Clear any signals we may have left behind */
  102.     SetSignal(0, 1UL << _fifo_sig);
  103.     return 0;
  104. }
  105.  
  106. /* Using 4.2BSD style semantics, with reads from fifo's returning immediately when
  107.    data is available, and blocking for empty fifo's only when O_NDELAY was not
  108.    specified on open */
  109.  
  110. static int fifo_read(void *userinfo, void *buffer, unsigned int length)
  111. {
  112.     struct fifoinfo *fi = userinfo;
  113.     char *chars;
  114.     long ready;
  115.  
  116.     while (!(ready = ReadFifo(fi->rfifo, &chars, fi->skip))) {
  117.     ULONG sigs;
  118.  
  119.     fi->skip = 0;
  120.     if (fi->flags & O_NDELAY) {
  121.         errno = EWOULDBLOCK;
  122.         return -1;
  123.     }
  124.     Delay(1);        /* Perversely, this improves the performance */
  125.     RequestFifo(fi->rfifo, fi->rmsg, FREQ_RPEND);
  126.     sigs = _wait_signals(1L << fi->reply->mp_SigBit);
  127.     RequestFifo(fi->rfifo, fi->rmsg, FREQ_ABORT);
  128.     while (!GetMsg(fi->reply))
  129.         Wait(1UL << _fifo_sig);
  130.  
  131.     _handle_signals(sigs);
  132.     }
  133.     if (ready == -1)
  134.     ready = 0;
  135.     if (ready > length)
  136.     ready = length;
  137.     memcpy(buffer, chars, ready);
  138.     fi->skip = ready;
  139.  
  140.     return (int) ready;
  141. }
  142.  
  143. static int fifo_write(void *userinfo, void *buffer, unsigned int length)
  144. {
  145.     struct fifoinfo *fi = userinfo;
  146.     long cansend, written;
  147.  
  148.     if (length == 0) {        /* Send EOF */
  149.     char *fname, sname[FIFO_NAMELEN + 2], mname[FIFO_NAMELEN + 2];
  150.  
  151.     /* Send EOF */
  152.     CloseFifo(fi->wfifo, FIFOF_EOF);
  153.     /* And reopen fifo */
  154.     /* Docs say that this clears EOF flag, maybe we should wait a bit ? */
  155.     /* The writer is the "master" in fifo: terms */
  156.     strcpy(mname, fi->name);
  157.     strcat(mname, "_m");
  158.     strcpy(sname, fi->name);
  159.     strcat(sname, "_s");
  160.  
  161.     fname = !(fi->flags & FI_READ) || (fi->flags & FIFO_MASTER) ? mname : sname;
  162.     fi->wfifo = OpenFifo(fname, __fifo_bufsize, FIFOF_NORMAL | FIFOF_NBIO |
  163.                  FIFOF_WRITE | FIFOF_RREQUIRED);
  164.     if (fi->wfifo) {
  165.         fi->maxsend = BufSizeFifo(fi->wfifo) / 2;
  166.         return 0;
  167.     }
  168.     /* We're in trouble. From now on, all writes will fail */
  169.     } else if (fi->wfifo) {
  170.     cansend = fi->maxsend;
  171.     if (cansend > length)
  172.         cansend = length;
  173.     while ((written = WriteFifo(fi->wfifo, buffer, cansend)) == 0) {
  174.         ULONG sigs;
  175.  
  176.         if (fi->flags & O_NDELAY) {
  177.         errno = EWOULDBLOCK;
  178.         return -1;
  179.         }
  180.         RequestFifo(fi->wfifo, fi->wmsg, FREQ_WAVAIL);
  181.         sigs = _wait_signals(1L << fi->reply->mp_SigBit);
  182.         RequestFifo(fi->wfifo, fi->wmsg, FREQ_ABORT);
  183.         while (!GetMsg(fi->reply))
  184.         Wait(1UL << _fifo_sig);
  185.         _handle_signals(sigs);
  186.     }
  187.     if (written >= 0)
  188.         return (int) written;
  189.     }
  190.     /* Some problem has occured */
  191.     _sig_dispatch(SIGPIPE);
  192.     errno = EPIPE;
  193.     return -1;
  194. }
  195.  
  196. static int fifo_lseek(void *userinfo, long rpos, int mode)
  197. {
  198.     errno = ESPIPE;
  199.     return -1;
  200. }
  201.  
  202. static int fifo_close(void *userinfo, int internal)
  203. {
  204.     struct fifoinfo *fi = userinfo;
  205.  
  206.     free_fifo(fi);
  207.     return 0;
  208. }
  209.  
  210. static int fifo_ioctl(void *userinfo, int request, void *data)
  211. {
  212.     struct fifoinfo *fi = userinfo;
  213.  
  214.     switch (request) {
  215.     case FIONBIO:
  216.         if (*(int *) data)
  217.         fi->flags |= O_NDELAY;
  218.         else
  219.         fi->flags &= ~O_NDELAY;
  220.         return 0;
  221.     case _AMIGA_GET_FH: {
  222.         BPTR *fh = data;
  223.         char name[FIFO_NAMELEN + 12];
  224.  
  225.         /* Get an AmigaDOS fifo: onto the same fifo in the same role */
  226.         if ((fi->flags & (FI_READ | FI_WRITE)) == (FI_READ | FI_WRITE))
  227.         _sprintf(name, "fifo:%s/rwesK%s",
  228.              fi->name, fi->flags & FIFO_MASTER ? "m" : "");
  229.         else if (fi->flags & FI_READ)
  230.         _sprintf(name, "fifo:%s/r", fi->name);
  231.         else
  232.         _sprintf(name, "fifo:%s/mweK", fi->name);
  233.  
  234.         *fh = Open(name, MODE_OLDFILE);
  235.         if (*fh)
  236.         return 0;
  237.         ERROR;
  238.     }
  239.     case _AMIGA_FREE_FH: {
  240.         BPTR *fh = data;
  241.  
  242.         if (*fh)
  243.         Close(*fh);
  244.         return 0;
  245.     }
  246.     case _AMIGA_IS_FIFO: {
  247.         int *is_fifo = data;
  248.  
  249.         *is_fifo = TRUE;
  250.         return 0;
  251.     }
  252.     case _AMIGA_IS_SOCK: {
  253.         int *is_sock = data;
  254.  
  255.         *is_sock = FALSE;
  256.         return 0;
  257.     }
  258.     default:
  259.         errno = EINVAL;
  260.         return -1;
  261.     }
  262. }
  263.  
  264. static int alloc_fifo(char *name, int reader, int writer, int master)
  265. {
  266.     struct fifoinfo *fi;
  267.     int fd;
  268.     struct MsgPort *reply = 0;
  269.     struct Message *rmsg = 0, *wmsg = 0;
  270.  
  271.     if ((fi = malloc(sizeof(struct fifoinfo))) &&
  272.      (reply = create_fifo_port()) &&
  273.      (rmsg = malloc(sizeof(struct Message))) &&
  274.      (wmsg = malloc(sizeof(struct Message)))) {
  275.  
  276.     rmsg->mn_Node.ln_Type = NT_MESSAGE;
  277.     rmsg->mn_ReplyPort = reply;
  278.     rmsg->mn_Length = sizeof(*rmsg);
  279.     wmsg->mn_Node.ln_Type = NT_MESSAGE;
  280.     wmsg->mn_ReplyPort = reply;
  281.     wmsg->mn_Length = sizeof(*wmsg);
  282.     fi->reply = reply;
  283.     fi->rmsg = rmsg;
  284.     fi->wmsg = wmsg;
  285.     fi->rfifo = fi->wfifo = 0;
  286.  
  287.     fi->flags = 0;
  288.     if (reader)
  289.         fi->flags |= FI_READ;
  290.     if (writer)
  291.         fi->flags |= FI_WRITE;
  292.     fd = _alloc_fd(fi, fi->flags,
  293.                fifo_select_start, fifo_select_poll, fifo_read,
  294.                fifo_write, fifo_lseek, fifo_close, fifo_ioctl);
  295.     if (fd) {        /* EF: fd == 0 is not valid ??? */
  296.         char *fname, sname[FIFO_NAMELEN + 2], mname[FIFO_NAMELEN + 2];
  297.  
  298.         if (master)
  299.         fi->flags |= FIFO_MASTER;
  300.         strcpy(fi->name, name);
  301.         /* The writer is the "master" in fifo: terms */
  302.         strcpy(mname, fi->name);
  303.         strcat(mname, "_m");
  304.         strcpy(sname, fi->name);
  305.         strcat(sname, "_s");
  306.  
  307.         if (reader) {
  308.         fname = !writer || !master ? mname : sname;
  309.         fi->rfifo = OpenFifo(fname, __fifo_bufsize, FIFOF_NORMAL |
  310.                      FIFOF_NBIO | FIFOF_READ);
  311.         }
  312.         if (writer) {
  313.         fname = !reader || master ? mname : sname;
  314.         fi->wfifo = OpenFifo(fname, __fifo_bufsize, FIFOF_NORMAL |
  315.                  FIFOF_NBIO | FIFOF_WRITE | FIFOF_RREQUIRED);
  316.         }
  317.         if ((fi->rfifo || !reader) && (fi->wfifo || !writer)) {
  318.         if (fi->wfifo)
  319.             fi->maxsend = BufSizeFifo(fi->wfifo) / 2;
  320.         fi->skip = 0;
  321.         return fd;
  322.         }
  323.         if (fi->rfifo)
  324.         CloseFifo(fi->rfifo, 0);
  325.         if (fi->wfifo)
  326.         CloseFifo(fi->wfifo, 0);
  327.     }
  328.     if (fd >= 0)
  329.         _free_fd(fd);
  330.     }
  331.     if (rmsg)
  332.     free(rmsg);
  333.     if (wmsg)
  334.     free(wmsg);
  335.     if (reply)
  336.     delete_fifo_port(reply);
  337.     if (fi)
  338.     free(fi);
  339.     return -1;
  340. }
  341.  
  342. int pipe(int fd[2])
  343. {
  344.     char name[FIFO_NAMELEN];
  345.     struct fileinfo *f0;
  346.  
  347.     __chkabort();
  348.     if (!_fifo_ok) {
  349.     errno = ENXIO;
  350.     return -1;
  351.     }
  352.     _sprintf(name, "uxfifo.%lx", _fifo_base + _fifo_offset++);
  353.  
  354.     if ((fd[0] = alloc_fifo(name, TRUE, FALSE, FALSE)) >= 0)
  355.     if ((fd[1] = alloc_fifo(name, FALSE, TRUE, FALSE)) >= 0)
  356.         return 0;
  357.     else {
  358.         if (f0 = _find_fd(fd[0]))
  359.         free_fifo(f0->userinfo);
  360.         _free_fd(fd[0]);
  361.     }
  362.     return -1;
  363. }
  364.  
  365. int socketpair(int domain, int type, int protocol, int sv[2])
  366. {
  367.     char name[FIFO_NAMELEN];
  368.     struct fileinfo *f0;
  369.  
  370.     __chkabort();
  371.     if (!_fifo_ok) {
  372.     errno = ENXIO;
  373.     return -1;
  374.     }
  375.     _sprintf(name, "uxfifo.%lx", _fifo_base + _fifo_offset++);
  376.  
  377.     if ((sv[0] = alloc_fifo(name, TRUE, TRUE, TRUE)) >= 0)
  378.     if ((sv[1] = alloc_fifo(name, TRUE, TRUE, FALSE)) >= 0)
  379.         return 0;
  380.     else {
  381.         if (f0 = _find_fd(sv[0]))
  382.         free_fifo(f0->userinfo);
  383.         _free_fd(sv[0]);
  384.     }
  385.     return -1;
  386. }
  387.