groff 1.23.0 added .MR to its -man macro package. The NEWS file states
that the inclusion of the macro "was prompted by its introduction to
Plan 9 from User Space's troff in August 2020." From d32deab it seems
that the name for Plan 9 from User Space's implementation was suggested
by groff maintainer G. Brandon Robinson.
Not sure if the intention was to make these definitions compatible, but
it would be nice if they were.
Currently, Plan 9 from User Space's .MR expects its second argument to
be parenthesized. groff's .MR does not. This results in extra
parentheses appearing in manual references when viewing Plan 9 from User
Space's manual pages on a system using groff.
203 lines
3.5 KiB
Groff
203 lines
3.5 KiB
Groff
.TH IOPROC 3
|
|
.SH NAME
|
|
closeioproc,
|
|
iocall,
|
|
ioclose,
|
|
iointerrupt,
|
|
iodial,
|
|
ioopen,
|
|
ioproc,
|
|
ioread,
|
|
ioread9pmsg,
|
|
ioreadn,
|
|
iorecvfd,
|
|
iosendfd,
|
|
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 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);
|
|
.XX
|
|
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 Ioclose ,
|
|
.IR iodial ,
|
|
.IR ioopen ,
|
|
.IR ioread ,
|
|
.IR ioread9pmsg ,
|
|
.IR ioreadn ,
|
|
.IR iorecvfd ,
|
|
.IR iosendfd ,
|
|
.IR iosleep ,
|
|
and
|
|
.I iowrite
|
|
execute the
|
|
similarly named library or system calls
|
|
(see
|
|
.MR close 2 ,
|
|
.MR dial 3 ,
|
|
.MR open 3 ,
|
|
.MR read 3 ,
|
|
.MR fcall 3 ,
|
|
.MR sendfd 3 ,
|
|
and
|
|
.MR sleep 3 )
|
|
in the slave process associated with
|
|
.IR io .
|
|
It is an error to execute more than one call
|
|
at a time in an I/O proc.
|
|
.PP
|
|
.I Iointerrupt
|
|
interrupts the call currently executing in the I/O proc.
|
|
If no call is executing,
|
|
.IR iointerrupt
|
|
is a no-op.
|
|
.PP
|
|
.I Closeioproc
|
|
terminates the I/O proc and frees the associated
|
|
.B 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
|
|
The two
|
|
.I relaythread
|
|
instances are running in the same proc, so the
|
|
common access to
|
|
.I tot
|
|
is safe.
|
|
.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 \*9/src/libthread
|
|
.SH SEE ALSO
|
|
.MR dial 3 ,
|
|
.MR open 3 ,
|
|
.MR read 3 ,
|
|
.MR thread 3
|
|
.SH BUGS
|
|
.I Iointerrupt
|
|
is currently unimplemented.
|
|
.PP
|
|
C99 disallows the use of pointers to
|
|
.BR va_list .
|
|
This interface will have to change to
|
|
use pointers to a structure containing a
|
|
.BR va_list .
|