closeioproc, iocall, ioclose, ioflush, iointerrupt, iodial, ioopen, ioproc, ioread, ioreadn, iosleep, iowrite – slave I/O processes for threaded programs


unhandled troff command .de

unhandled troff command .ift

unhandled troff command .ifn

unhandled troff command ..

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

unhandled troff command .sp

typedef struct Ioproc Ioproc;

unhandled troff command .sp

Ioproc* ioproc(void);

unhandled troff command .XX

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

unhandled troff command .XX

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

unhandled troff command .XX

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.

Ioopen, ioclose, ioread, ioreadn, iowrite, iosleep, and iodial execute the similarly named library or system calls (see open(2), read(2), and dial(2)) in the slave process associated with io.

Iointerrupt interrupts the next or currently executing call in the I/O proc. If there was no call executing, the interrupt will stay pending and the next I/O call will get interrupted.

Ioflush executes a non-op in the I/O proc. It is commonly called after iointerrupt to clear a pending interrupt.

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);

If the two relaythread instances were running in different procs, the common access to tot would be unsafe.

Implement ioread:


static long
_ioread(va_list *arg)
	int fd;
	void *a;
	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(2), open(2), read(2), sleep(2), thread(2)