IOPROC(3)                                               IOPROC(3)

          closeioproc, iocall, ioclose, iointerrupt, iodial, ioopen,
          ioproc, ioread, ioread9pmsg, ioreadn, iorecvfd, iosendfd,
          iosleep, iowrite - slave I/O processes for threaded programs

          #include <u.h>
          #include <libc.h>
          #include <thread.h>

          typedef struct Ioproc Ioproc;

          Ioproc* ioproc(void);

          int     ioclose(Ioproc *io, int fd);
          int     iodial(Ioproc *io, char *addr, char *local, char *dir, char *cdfp);
          int     ioopen(Ioproc *io, char *file, int omode);
          long    ioread(Ioproc *io, int fd, void *a, long n);
          int     ioread9pmsg(Ioproc *io, int fd, void *a, uint n);
          long    ioreadn(Ioproc *io, int fd, void *a, long n);
          int     iorecvfd(Ioproc *io, int socket);
          int     iosendfd(Ioproc *io, int socket, int fd);
          int     iosleep(Ioproc *io, long milli);
          long    iowrite(Ioproc *io, int fd, void *a, long n);

          void    iointerrupt(Ioproc *io);
          void    closeioproc(Ioproc *io);

          long    iocall(Ioproc *io, long (*op)(va_list *arg), ...);

          These routines provide access to I/O in slave procs.  Since
          the I/O itself is done in a slave proc, other threads in the
          calling proc can run while the calling thread waits for the
          I/O to complete.

          Ioproc forks a new slave proc and returns a pointer to the
          Ioproc associated with it.  Ioproc uses mallocz and
          proccreate; if either fails, it calls sysfatal rather than
          return an error.

          Ioclose, iodial, ioopen, ioread, ioread9pmsg, ioreadn,
          iorecvfd, iosendfd, iosleep, and iowrite execute the simi-
          larly named library or system calls (see close(2), dial(3),
          open(3), read(3), fcall(3), sendfd(3), and sleep(3)) in the
          slave process associated with io. It is an error to execute
          more than one call at a time in an I/O proc.

          Iointerrupt interrupts the call currently executing in the
          I/O proc.  If no call is executing, iointerrupt is a no-op.

     IOPROC(3)                                               IOPROC(3)

          Closeioproc terminates the I/O proc and frees the associated
          Ioproc .

          Iocall is a primitive that may be used to implement more
          slave I/O routines.  Iocall arranges for op to be called in
          io's proc, with arg set to the variable parameter list,
          returning the value that op returns.

          Relay messages between two file descriptors, counting the
          total number of bytes seen:

               int tot;

               relaythread(void *v)
                   int *fd, n;
                   char buf[1024];
                   Ioproc *io;

                   fd = v;
                   io = ioproc();
                   while((n = ioread(io, fd[0], buf, sizeof buf)) > 0){
                       if(iowrite(io, fd[1], buf, n) != n)
                           sysfatal("iowrite: %r");
                       tot += n;

               relay(int fd0, int fd1)
                   int fd[4];

                   fd[0] = fd[3] = fd0;
                   fd[1] = fd[2] = fd1;
                   threadcreate(relaythread, fd, 8192);
                   threadcreate(relaythread, fd+2, 8192);

          The two relaythread instances are running in the same proc,
          so the common access to tot is safe.

          Implement ioread:

               static long
               _ioread(va_list *arg)
                   int fd;
                   void *a;

     IOPROC(3)                                               IOPROC(3)

                   long n;

                   fd = va_arg(*arg, int);
                   a = va_arg(*arg, void*);
                   n = va_arg(*arg, long);
                   return read(fd, a, n);

               ioread(Ioproc *io, int fd, void *a, long n)
                   return iocall(io, _ioread, fd, a, n);


          dial(3), open(3), read(3), thread(3)

          Iointerrupt is currently unimplemented.

          C99 disallows the use of pointers to va_list.  This inter-
          face will have to change to use pointers to a structure con-
          taining a va_list.