shithub: riscv

ref: e48a5c343d3ba76c6dfb949b5178e46a41792f72
dir: /sys/man/2/thread/

View raw version
.TH THREAD 2
.SH NAME
alt,
chanclose,
chancreate,
chanfree,
chanclosing,
chanprint,
mainstacksize,
proccreate,
procdata,
procexec,
procexecl,
procrfork,
recv,
recvp,
recvul,
send,
sendp,
sendul,
nbrecv,
nbrecvp,
nbrecvul,
nbsend,
nbsendp,
nbsendul,
threadcreate,
threaddata,
threadexits,
threadexitsall,
threadgetgrp,
threadgetname,
threadint,
threadintgrp,
threadkill,
threadkillgrp,
threadmain,
threadnotify,
threadid,
threadpid,
threadsetgrp,
threadsetname,
threadwaitchan,
yield \- thread and proc management
.SH SYNOPSIS
.EX
.ta 4n +4n +4n +4n +4n +4n +4n
#include <u.h>
#include <libc.h>
#include <thread.h>
.sp
typedef enum {
	CHANEND,
	CHANSND,
	CHANRCV,
	CHANNOP,
	CHANNOBLK,
} ChanOp;
.sp
.ta \w'    'u +\w'Channel 'u
typedef struct Alt Alt;
struct Alt {
	Channel	*c;   /* channel */
	void	*v;   /* pointer to value */
	ChanOp	op;   /* operation */
	char	*err; /* did the op fail? */
	/*
	 * the next variables are used internally to alt
	 * they need not be initialized
	 */
	Channel	**tag;   /* pointer to rendez-vous tag */
	int	entryno; /* entry number */
};
.fi
.de XX
.ift .sp 0.5
.ifn .sp
..
.PP
.nf
.ft L
.ta \w'\fLChannel* 'u +4n +4n +4n +4n
void	threadmain(int argc, char *argv[])
int	mainstacksize
int	proccreate(void (*fn)(void*), void *arg, uint stacksize)
int	procrfork(void (*fn)(void*), void *arg, uint stacksize,
		int rforkflag)
int	threadcreate(void (*fn)(void*), void *arg, uint stacksize)
void	threadexits(char *status)
void	threadexitsall(char *status)
void	yield(void)
.XX
int	threadid(void)
int	threadgetgrp(void)
int	threadsetgrp(int group)
int	threadpid(int id)
.XX
void	threadint(int id)
void	threadintgrp(int group)
void	threadkill(int id)
void	threadkillgrp(int group)
.XX
void	threadsetname(char *fmt, ...)
char*	threadgetname(void)
.XX
void**	threaddata(void)
void**	procdata(void)
.XX
Channel*	chancreate(int elsize, int nel)
void	chanfree(Channel *c)
.XX
int	alt(Alt *alts)
int	recv(Channel *c, void *v)
void*	recvp(Channel *c)
ulong	recvul(Channel *c)
int	nbrecv(Channel *c, void *v)
void*	nbrecvp(Channel *c)
ulong	nbrecvul(Channel *c)
int	send(Channel *c, void *v)
int	sendp(Channel *c, void *v)
int	sendul(Channel *c, ulong v)
int	nbsend(Channel *c, void *v)
int	nbsendp(Channel *c, void *v)
int	nbsendul(Channel *c, ulong v)
int	chanprint(Channel *c, char *fmt, ...)
int	chanclose(Channel *c);
int	chanclosing(Channel *c);
.XX
void	procexecl(Channel *cpid, char *file, ...)
void	procexec(Channel *cpid, char *file, char *args[])
Channel*	threadwaitchan(void)
.XX
int	threadnotify(int (*f)(void*, char*), int in)
.EE
.SH DESCRIPTION
The thread library provides parallel programming support similar to that
of the languages
Alef and Newsqueak.
.I Threads
and
.I procs
occupy a shared address space,
communicating and synchronizing through
.I channels
and shared variables.
.PP
A
.I proc
is a Plan 9 process that contains one or more cooperatively-scheduled
.IR threads .
Programs using threads must replace
.I main
by
.IR threadmain .
The thread library provides a
.I main
function that sets up a proc with a single thread executing
.I threadmain
on a stack of size
.I mainstacksize
(default eight kilobytes).
To set
.IR mainstacksize ,
declare a global variable
initialized to the desired value
.RI ( e.g. ,
.B int
.B mainstacksize
.B =
.BR 1024 ).
.SS Creation
.I Threadcreate
creates a new thread in the calling proc, returning a unique integer
identifying the thread; the thread
executes
.I fn(arg)
on a stack of size
.IR stacksize .
Thread stacks are allocated in shared memory, making it valid to pass
pointers to stack variables between threads and procs.
.I Procrfork
creates a new proc, and inside that proc creates
a single thread as
.I threadcreate
would,
returning the id of the created thread.
.I Procrfork
creates the new proc by calling
.B rfork
(see
.IR fork (2))
with flags
.BR RFPROC|RFMEM|RFNOWAIT| \fIrforkflag\fR.
(The thread library depends on all its procs
running in the same rendezvous group.
Do not include
.B RFREND
in
.IR rforkflag .)
.I Proccreate
is identical to
.I procrfork
with
.I rforkflag
set to zero.
Be aware that the calling thread may continue
execution before
the newly created proc and thread
are scheduled.
Because of this,
.I arg
should not point to data on the stack of a function that could
return before the new process is scheduled.
.PP
.I Threadexits
terminates the calling thread.
If the thread is the last in its proc,
.I threadexits
also terminates the proc, using
.I status
as the exit status.
.I Threadexitsall
terminates all procs in the program,
using
.I status
as the exit status.
.SS Scheduling
The threads in a proc are coroutines, scheduled non-preemptively
in a round-robin fashion.
A thread must explicitly relinquish control of the processor
before another thread in the same proc is run.
Calls that do this are
.IR yield ,
.IR proccreate ,
.IR procexec ,
.IR procexecl ,
.IR threadexits ,
.IR alt ,
.IR send ,
and
.I recv
(and the calls related to
.I send
and
.IR recv \(emsee
their descriptions further on),
plus these from
.IR lock (2):
.IR qlock ,
.IR rlock ,
.IR wlock ,
.IR rsleep .
Procs are scheduled by the operating system.
Therefore, threads in different procs can preempt one another
in arbitrary ways and should synchronize their
actions using
.B qlocks
(see
.IR lock (2))
or channel communication.
System calls such as
.IR read (2)
block the entire proc;
all threads in a proc block until the system call finishes.
.PP
As mentioned above, each thread has a unique integer thread id.
Thread ids are not reused; they are unique across the life of the program.
.I Threadid
returns the id for the current thread.
Each thread also has a thread group id.
The initial thread has a group id of zero.
Each new thread inherits the group id of
the thread that created it.
.I Threadgetgrp
returns the group id for the current thread;
.I threadsetgrp
sets it.
.I Threadpid
returns the pid of the Plan 9 process containing
the thread identified by
.IR id ,
or \-1
if no such thread is found.
.PP
.I Threadint
interrupts a thread that is blocked in a channel operation
or system call.
.I Threadintgrp
interrupts all threads with the given group id.
.I Threadkill
marks a thread to die when it next relinquishes the processor
(via one of the calls listed above).
If the thread is blocked in a channel operation or system call,
it is also interrupted.
.I Threadkillgrp
kills all threads with the given group id.
Note that
.I threadkill
and
.I threadkillgrp
will not terminate a thread that never relinquishes
the processor.
.SS Names and per-thread data
Primarily for debugging,
threads can have string names associated with them.
.I Threadgetname
returns the current thread's name;
.I threadsetname
sets it.
The pointer returned by
.I threadgetname
is only valid until the next call to
.IR threadsetname .
.PP
.I Threaddata
returns a pointer to a per-thread pointer
that may be modified by threaded programs for
per-thread storage.
Similarly,
.I procdata
returns a pointer to a per-proc pointer.
.SS Executing new programs
.I Procexecl
and
.I procexec
are threaded analogues of
.I exec
and
.I execl
(see
.IR exec (2));
on success,
they replace the calling thread (which must be the only thread in its proc)
and invoke the external program, never returning.
On error, they return and set
.IR errstr .
If
.I cpid
is not null, the pid of the invoked program
will be sent along
.I cpid
once the program has been started, or \-1 will be sent if an
error occurs.
.I Procexec
and
.I procexecl
will not access their arguments after sending a result
along
.IR cpid .
Thus, programs that malloc the
.I argv
passed to
.I procexec
can safely free it once they have
received the
.I cpid
response.
.PP
.I Threadwaitchan
returns a channel of pointers to
.B Waitmsg
structures (see
.IR wait (2)).
When an exec'ed process exits, a pointer to a
.B Waitmsg
is sent to this channel.
These
.B Waitmsg
structures have been allocated with
.IR malloc (2)
and should be freed after use.
.SS Channels
A
.B Channel
is a buffered or unbuffered queue for fixed-size messages.
Procs and threads
.I send
messages into the channel and
.I recv
messages from the channel.  If the channel is unbuffered, a
.I send
operation blocks until the corresponding
.I recv
operation occurs and
.IR "vice versa" .
.I Chancreate
allocates a new channel for messages of size
.I elsize
and with a buffer holding
.I nel
messages.
If
.I nel
is zero, the channel is unbuffered.
.I Chanfree
frees a channel that is no longer used.
.I Chanfree
can be called by either sender or receiver after the last item has been
sent or received.  Freeing the channel will be delayed if there is a thread
blocked on it until that thread unblocks (but
.I chanfree
returns immediately).
.PP
.I Send
sends the element pointed at by
.I v
to the channel
.IR c .
If
.I v
is null, zeros are sent.
.I Recv
receives an element from
.I c
and stores it in
.IR v .
If
.I v
is null,
the received value is discarded.
.I Send
and
.I recv
return 1 on success, \-1 if interrupted.
.I Nbsend
and
.I nbrecv
behave similarly, but return 0 rather than blocking.
.PP
.IR Sendp ,
.IR nbsendp ,
.IR sendul ,
and
.I nbsendul
send a pointer or an unsigned long; the channel must
have been initialized with the appropriate
.IR elsize .
.IR Recvp ,
.IR nbrecvp ,
.IR recvul ,
and
.I nbrecvul
receive a pointer or an unsigned long;
they return zero when a zero is received,
when interrupted, or
(for
.I nbrecvp
and
.IR nbrecvul )
when the operation would have blocked.
To distinguish between these three cases,
use
.I recv
or
.IR nbrecv .
.PP
.I Alt
can be used to recv from or send to one of a number of channels,
as directed by an array of
.B Alt
structures,
each of which describes a potential send or receive operation.
In an
.B Alt
structure,
.B c
is the channel;
.B v
the value pointer (which may be null); and
.B op
the operation:
.B CHANSND
for a send operation,
.B CHANRCV
for a recv operation;
.B CHANNOP
for no operation
(useful
when
.I alt
is called with a varying set of operations).
The array of
.B Alt
structures is terminated by an entry with
.I op
.B CHANEND
or
.BR CHANNOBLK .
If at least one
.B Alt
structure can proceed, one of them is
chosen at random to be executed.
.I Alt
returns the index of the chosen structure.
If no operations can proceed and the list is terminated with
.BR CHANNOBLK ,
.I alt
returns the index of the terminating
.B CHANNOBLK
structure.
Otherwise,
.I alt
blocks until one of the operations can proceed,
eventually returning the index of the structure it executes.
.I Alt
returns \-1 when interrupted.
The
.B tag
and
.B entryno
fields in the
.B Alt
structure are used internally by
.I alt
and need not be initialized.
They are not used between
.I alt
calls.
.PP
.I Chanprint
formats its arguments in the manner of
.IR print (2)
and sends the result to the channel
.IR c .
The string delivered by
.I chanprint
is allocated with
.IR malloc (2)
and should be freed upon receipt.
.PP
.I Chanclose
prevents further elements being sent to the channel
.IR c .
After closing a channel,
.I send
and
.I recv
never block.
.I Send
always
returns \-1.
.I Recv
returns \-1 if the channel is empty.
.I Alt
may choose a
.B CHANSND
or
.B CHANRCV
that failed because the channel was closed.
In this case, the
.B err
field of the
.B Alt
entry points to an error string stating that the
channel was closed and the operation was completed
with failure.
If all entries have been selected and failed because
they were closed,
.I alt
returns \-1.
.SS Errors, notes and resources
Thread library functions do not return on failure;
if errors occur, the entire program is aborted.
.PP
.I Chanclosing
returns \-1 if no one called
.I chanclose
on the channel, and otherwise
the number of elements still in the channel.
.PP
Threaded programs should use
.I threadnotify
in place of
.I atnotify
(see
.IR notify (2)).
.PP
It is safe to use
.B sysfatal
(see
.IR perror (2))
in threaded programs.
.I Sysfatal
will print the error string and call
.IR threadexitsall .
.PP
It is safe to use
.IR rfork
(see
.IR fork (2))
to manage the namespace, file descriptors, note group, and environment of a
single process.
That is, it is safe to call
.I rfork
with the flags
.BR RFNAMEG ,
.BR RFFDG ,
.BR RFCFDG ,
.BR RFNOTEG ,
.BR RFENVG ,
and
.BR RFCENVG.
(To create new processes, use
.I proccreate
and
.IR procrfork .)
As mentioned above,
the thread library depends on all procs being in the
same rendezvous group; do not change the rendezvous
group with
.IR rfork .
.SH FILES
.TF /sys/lib/acid/thread
.TP
.B /sys/lib/acid/thread
useful
.IR acid (1)
functions for debugging threaded programs.
.TP
.B /sys/src/libthread/example.c
a full example program.
.SH SOURCE
.B /sys/src/libthread
.SH SEE ALSO
.IR intro (2),
.IR ioproc (2),
.IR lock (2)