186 lines
3.2 KiB
Text
186 lines
3.2 KiB
Text
.TH IOPROC 2
|
|
.SH NAME
|
|
closeioproc,
|
|
iocall,
|
|
ioclose,
|
|
ioflush,
|
|
iointerrupt,
|
|
iodial,
|
|
ioopen,
|
|
ioproc,
|
|
ioread,
|
|
ioreadn,
|
|
iosleep,
|
|
iowrite \- slave I/O processes for threaded programs
|
|
.SH SYNOPSIS
|
|
.PP
|
|
.de XX
|
|
.ift .sp 0.5
|
|
.ifn .sp
|
|
..
|
|
.EX
|
|
.ta \w'Ioproc* 'u
|
|
#include <u.h>
|
|
#include <libc.h>
|
|
#include <thread.h>
|
|
.sp
|
|
typedef struct Ioproc Ioproc;
|
|
.sp
|
|
Ioproc* ioproc(void);
|
|
.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);
|
|
.XX
|
|
int ioflush(Ioproc *io);
|
|
void iointerrupt(Ioproc *io);
|
|
void closeioproc(Ioproc *io);
|
|
.XX
|
|
long iocall(Ioproc *io, long (*op)(va_list *arg), ...);
|
|
.EE
|
|
.SH DESCRIPTION
|
|
.PP
|
|
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.
|
|
.PP
|
|
.I Ioproc
|
|
forks a new slave proc and returns a pointer to the
|
|
.B Ioproc
|
|
associated with it.
|
|
.I Ioproc
|
|
uses
|
|
.I mallocz
|
|
and
|
|
.IR proccreate ;
|
|
if either fails, it calls
|
|
.I sysfatal
|
|
rather than return an error.
|
|
.PP
|
|
.IR Ioopen ,
|
|
.IR ioclose ,
|
|
.IR ioread ,
|
|
.IR ioreadn ,
|
|
.IR iowrite ,
|
|
.IR iosleep ,
|
|
and
|
|
.IR iodial
|
|
execute the
|
|
similarly named library or system calls
|
|
(see
|
|
.IR open (2),
|
|
.IR read (2),
|
|
and
|
|
.IR dial (2))
|
|
in the slave process associated with
|
|
.IR io .
|
|
.PP
|
|
.I 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.
|
|
.PP
|
|
.I Ioflush
|
|
executes a non-op in the I/O proc. It is commonly called after
|
|
.IR iointerrupt
|
|
to clear a pending interrupt.
|
|
.PP
|
|
.I Closeioproc
|
|
terminates the I/O proc and frees the associated
|
|
.BR Ioproc .
|
|
.PP
|
|
.I Iocall
|
|
is a primitive that may be used to implement
|
|
more slave I/O routines.
|
|
.I Iocall
|
|
arranges for
|
|
.I op
|
|
to be called in
|
|
.IR io 's
|
|
proc, with
|
|
.I arg
|
|
set to the variable parameter list,
|
|
returning the value that
|
|
.I op
|
|
returns.
|
|
.SH EXAMPLE
|
|
Relay messages between two file descriptors,
|
|
counting the total number of bytes seen:
|
|
.IP
|
|
.EX
|
|
.ta +\w'xxxx'u +\w'xxxx'u +\w'xxxx'u
|
|
int tot;
|
|
|
|
void
|
|
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;
|
|
}
|
|
closeioproc(io);
|
|
}
|
|
|
|
void
|
|
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);
|
|
}
|
|
.EE
|
|
.LP
|
|
If the two
|
|
.I relaythread
|
|
instances were running in different procs, the
|
|
common access to
|
|
.I tot
|
|
would be unsafe.
|
|
.PP
|
|
Implement
|
|
.IR ioread :
|
|
.IP
|
|
.EX
|
|
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);
|
|
}
|
|
|
|
long
|
|
ioread(Ioproc *io, int fd, void *a, long n)
|
|
{
|
|
return iocall(io, _ioread, fd, a, n);
|
|
}
|
|
.EE
|
|
.SH SOURCE
|
|
.B /sys/src/libthread/io*.c
|
|
.SH SEE ALSO
|
|
.IR dial (2),
|
|
.IR open (2),
|
|
.IR read (2),
|
|
.IR sleep (2),
|
|
.IR thread (2)
|
|
|