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