Programs that want to background themselves now need to define threadmaybackground returning 1. This avoids a confusing (to people and debuggers) extra parent process for all the threaded programs that will never want to background themselves.
738 lines
15 KiB
Groff
738 lines
15 KiB
Groff
.TH THREAD 3
|
|
.SH NAME
|
|
alt,
|
|
chancreate,
|
|
chanfree,
|
|
chanprint,
|
|
chansetname,
|
|
mainstacksize,
|
|
proccreate,
|
|
procdata,
|
|
recv,
|
|
recvp,
|
|
recvul,
|
|
send,
|
|
sendp,
|
|
sendul,
|
|
nbrecv,
|
|
nbrecvp,
|
|
nbrecvul,
|
|
nbsend,
|
|
nbsendp,
|
|
nbsendul,
|
|
threadcreate,
|
|
threaddata,
|
|
threadexec,
|
|
threadexecl,
|
|
threadexits,
|
|
threadexitsall,
|
|
threadgetgrp,
|
|
threadgetname,
|
|
threadint,
|
|
threadintgrp,
|
|
threadkill,
|
|
threadkillgrp,
|
|
threadmain,
|
|
threadmaybackground,
|
|
threadnotify,
|
|
threadid,
|
|
threadpid,
|
|
threadpin,
|
|
threadunpin,
|
|
threadsetgrp,
|
|
threadsetname,
|
|
threadsetstate,
|
|
threadspawn,
|
|
threadspawnd,
|
|
threadspawnl,
|
|
threadwaitchan,
|
|
yield \- thread and proc management
|
|
.SH SYNOPSIS
|
|
.PP
|
|
.EX
|
|
.ta 4n +4n +4n +4n +4n +4n +4n
|
|
#include <u.h>
|
|
#include <libc.h>
|
|
#include <thread.h>
|
|
.sp
|
|
#define CHANEND 0
|
|
#define CHANSND 1
|
|
#define CHANRCV 2
|
|
#define CHANNOP 3
|
|
#define CHANNOBLK 4
|
|
.sp
|
|
.ta \w' 'u +\w'Channel 'u
|
|
typedef struct Alt Alt;
|
|
struct Alt {
|
|
Channel *c;
|
|
void *v;
|
|
int op;
|
|
Channel **tag;
|
|
int entryno;
|
|
char *name;
|
|
};
|
|
.fi
|
|
.de XX
|
|
.if t .sp 0.5
|
|
.if n .sp
|
|
..
|
|
.PP
|
|
.nf
|
|
.ft L
|
|
.ta \w'\fLChannel* 'u +4n +4n +4n +4n
|
|
void threadmain(int argc, char *argv[])
|
|
int threadmaybackground(void)
|
|
int mainstacksize
|
|
int proccreate(void (*fn)(void*), void *arg, uint stacksize)
|
|
int threadcreate(void (*fn)(void*), void *arg, uint stacksize)
|
|
void threadexits(char *status)
|
|
void threadexitsall(char *status)
|
|
void yield(void)
|
|
int threadpin(void)
|
|
int threadunpin(void)
|
|
.XX
|
|
int threadid(void)
|
|
int threadgrp(void)
|
|
int threadsetgrp(int group)
|
|
int threadpid(int id)
|
|
.XX
|
|
int threadint(int id)
|
|
int threadintgrp(int group)
|
|
int threadkill(int id)
|
|
int threadkillgrp(int group)
|
|
.XX
|
|
void threadsetname(char *name)
|
|
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, ...)
|
|
.XX
|
|
int threadspawnl(int fd[3], char *file, ...)
|
|
int threadspawn(int fd[3], char *file, char *args[])
|
|
int threadspawnd(int fd[3], char *file, char *args[], char *dir)
|
|
int threadexecl(Channel *cpid, int fd[3], char *file, ...)
|
|
int threadexec(Channel *cpid, int fd[3], char *file, char *args[])
|
|
Channel* threadwaitchan(void)
|
|
.XX
|
|
int threadnotify(int (*f)(void*, char*), int in)
|
|
.EE
|
|
.SH DESCRIPTION
|
|
.PP
|
|
The thread library provides parallel programming support similar to that
|
|
of the languages
|
|
Alef and Newsqueak.
|
|
Threads
|
|
and
|
|
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 ).
|
|
When using the
|
|
.I pthread
|
|
library,
|
|
.B mainstacksize
|
|
is ignored, as is the stack size argument to
|
|
.BR proccreate :
|
|
the first thread in each proc
|
|
runs on the native system stack.
|
|
.PP
|
|
.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 Proccreate
|
|
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 (3))
|
|
.\" 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.
|
|
.PP
|
|
When the last thread in
|
|
.IR threadmain 's
|
|
proc exits, the program will appear to its parent to have exited.
|
|
The remaining procs will still run together, but as a background program.
|
|
This functionality can only be relied upon if the program defines a function
|
|
.I threadmaybackground
|
|
returning a non-zero result.
|
|
Programs that do not define such a
|
|
.I threadmaybackground
|
|
will crash instead should the last thread in
|
|
.IR threadmain 's
|
|
proc exit leaving behind other running procs.
|
|
.PP
|
|
The threads in a proc are coroutines, scheduled nonpreemptively
|
|
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 threadexec ,
|
|
.IR threadexecl ,
|
|
.IR threadexits ,
|
|
.IR threadspawn ,
|
|
.IR threadspawnd ,
|
|
.IR threadspawnl ,
|
|
.IR alt ,
|
|
.IR send ,
|
|
and
|
|
.I recv
|
|
(and the calls related to
|
|
.I send
|
|
and
|
|
.IR recv \(emsee
|
|
their descriptions further on).
|
|
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
|
|
.MR lock (3) )
|
|
or channel communication.
|
|
System calls such as
|
|
.MR read (3)
|
|
block the entire proc;
|
|
all threads in a proc block until the system call finishes.
|
|
.PP
|
|
.I Threadpin
|
|
disables scheduling inside a proc, `pinning' the current
|
|
thread as the only runnable one in the current proc.
|
|
.I Threadunpin
|
|
reenables scheduling, allowing other procs to run once the current
|
|
thread relinquishes the processor.
|
|
.I Threadpin
|
|
and
|
|
.I threadunpin
|
|
can lead to deadlock.
|
|
Used carefully, they can make library routines that use
|
|
.B qlocks
|
|
appear atomic relative to the current proc, like a system call.
|
|
.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 Threadgrp
|
|
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.
|
|
.PP
|
|
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
|
|
Also for debugging,
|
|
threads have a string state associated with them.
|
|
.I Threadsetstate
|
|
sets the state string.
|
|
There is no
|
|
.IR threadgetstate ;
|
|
since the thread scheduler resets the state to
|
|
.B Running
|
|
every time it runs the thread,
|
|
it is only useful for debuggers to inspect the state.
|
|
.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.
|
|
.PP
|
|
.I Threadexecl
|
|
and
|
|
.I threadexec
|
|
are threaded analogues of
|
|
.I exec
|
|
and
|
|
.I execl
|
|
(see
|
|
.MR exec (3) );
|
|
on success,
|
|
they replace the calling thread
|
|
and invoke the external program, never returning.
|
|
(Unlike on Plan 9, the calling thread need not be the only thread in its proc\(emthe other
|
|
threads will continue executing.)
|
|
On error, they return \-1.
|
|
If
|
|
.I cpid
|
|
is not null, the pid of the invoked program
|
|
will be sent along
|
|
.I cpid
|
|
(using
|
|
.IR sendul )
|
|
once the program has been started, or \-1 will be sent if an
|
|
error occurs.
|
|
.I Threadexec
|
|
and
|
|
.I threadexecl
|
|
will not access their arguments after sending a result
|
|
along
|
|
.IR cpid .
|
|
Thus, programs that malloc the
|
|
.I argv
|
|
passed to
|
|
.I threadexec
|
|
can safely free it once they have
|
|
received the
|
|
.I cpid
|
|
response.
|
|
.PP
|
|
.I Threadexecl
|
|
and
|
|
.I threadexec
|
|
will duplicate
|
|
(see
|
|
.MR dup (3) )
|
|
the three file descriptors in
|
|
.I fd
|
|
onto standard input, output, and error for the external program
|
|
and then close them in the calling thread.
|
|
Beware of code that sets
|
|
.IP
|
|
.EX
|
|
fd[0] = 0;
|
|
fd[1] = 1;
|
|
fd[2] = 2;
|
|
.EE
|
|
.LP
|
|
to use the current standard files. The correct code is
|
|
.IP
|
|
.EX
|
|
fd[0] = dup(0, -1);
|
|
fd[1] = dup(1, -1);
|
|
fd[2] = dup(2, -1);
|
|
.EE
|
|
.PP
|
|
.I Threadspawnl
|
|
and
|
|
.I threadspawn
|
|
are like
|
|
.I threadexecl
|
|
and
|
|
.I threadexec
|
|
but do not replace the current thread.
|
|
They return the pid of the invoked program on success, or
|
|
\-1 on error.
|
|
.I Threadspawnd
|
|
is like
|
|
.I threadspawn
|
|
but takes as its final argument the directory in which to run the invoked program.
|
|
The child will attempt to change into that directory before running the program,
|
|
but it is only best effort: failure to change into the directory does not
|
|
stop the running of the program.
|
|
.PP
|
|
.I Threadwaitchan
|
|
returns a channel of pointers to
|
|
.B Waitmsg
|
|
structures (see
|
|
.MR wait (3) ).
|
|
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
|
|
.MR malloc (3)
|
|
and should be freed after use.
|
|
.PP
|
|
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" .
|
|
.IR 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
|
|
The
|
|
.B name
|
|
element in the
|
|
.B Channel
|
|
structure is a description intended for use in debugging.
|
|
.I Chansetname
|
|
sets the name.
|
|
.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 CHANRECV
|
|
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 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
|
|
.MR print (3)
|
|
and sends the result to the channel
|
|
.IR c.
|
|
The string delivered by
|
|
.I chanprint
|
|
is allocated with
|
|
.MR malloc (3)
|
|
and should be freed upon receipt.
|
|
.PP
|
|
Thread library functions do not return on failure;
|
|
if errors occur, the entire program is aborted.
|
|
.PP
|
|
Threaded programs should use
|
|
.I threadnotify
|
|
in place of
|
|
.I atnotify
|
|
(see
|
|
.MR notify (3) ).
|
|
.PP
|
|
It is safe to use
|
|
.MR sysfatal (3)
|
|
in threaded programs.
|
|
.I Sysfatal
|
|
will print the error string and call
|
|
.IR threadexitsall .
|
|
.PP
|
|
It is not safe to call
|
|
.IR rfork
|
|
in a threaded program, except to call
|
|
.B rfork(RFNOTEG)
|
|
from the main proc before any other procs have been created.
|
|
To create new processes, use
|
|
.IR proccreate .
|
|
.\" .PP
|
|
.\" It is safe to use
|
|
.\" .IR rfork
|
|
.\" (see
|
|
.\" .IR fork (3))
|
|
.\" 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
|
|
.B \*9/acid/thread
|
|
contains useful
|
|
.MR acid (1)
|
|
functions for debugging threaded programs.
|
|
.PP
|
|
.B \*9/src/libthread/test
|
|
contains some example programs.
|
|
.SH SOURCE
|
|
.B \*9/src/libthread
|
|
.SH SEE ALSO
|
|
.MR intro (3) ,
|
|
.MR ioproc (3)
|
|
.SH BUGS
|
|
To avoid name conflicts,
|
|
.IR alt ,
|
|
.IR nbrecv ,
|
|
.IR nbrecvp ,
|
|
.IR nbrecvul ,
|
|
.IR nbsend ,
|
|
.IR nbsendp ,
|
|
.IR nbsendul ,
|
|
.IR recv ,
|
|
.IR recvp ,
|
|
.IR recvul ,
|
|
.IR send ,
|
|
.IR sendp ,
|
|
and
|
|
.IR sendul
|
|
are defined as macros that expand to
|
|
.IR chanalt ,
|
|
.IR channbrecv ,
|
|
and so on.
|
|
.I Yield
|
|
is defined as a macro that expands to
|
|
.IR threadyield .
|
|
See
|
|
.MR intro (3) .
|
|
.PP
|
|
Threadint,
|
|
threadintgrp,
|
|
threadkill,
|
|
threadkillgrp and threadpid are unimplemented.
|
|
.PP
|
|
The implementation of
|
|
.I threadnotify
|
|
may not be correct.
|
|
.PP
|
|
There appears to be a race in the Linux NPTL
|
|
implementation of
|
|
.I pthread_exit .
|
|
Call
|
|
.I threadexitsall
|
|
rather than coordinating a simultaneous
|
|
.I threadexits
|
|
among many threads.
|