123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642 |
- .TH THREAD 2
- .SH NAME
- alt,
- chanclose,
- chancreate,
- chanfree,
- chaninit,
- 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 threadgrp(void)
- int threadsetgrp(int group)
- int threadpid(int id)
- .XX
- int threadint(int id)
- void threadintgrp(int group)
- void threadkill(int id)
- int threadkillgrp(int group)
- .XX
- void threadsetname(char *name, ...)
- char* threadgetname(void)
- .XX
- void** threaddata(void)
- void** procdata(void)
- .XX
- int chaninit(Channel *c, int elsize, int nel)
- 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 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.
- .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 \-1.
- 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.
- Note that the mount point
- .B /mnt/temp
- must exist;
- .I procexec(l)
- mount pipes there.
- .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 Chaninit
- initializes a
- .B Channel
- for messages of size
- .I elsize
- and with a buffer holding
- .I nel
- messages.
- If
- .I nel
- is zero, the channel is unbuffered.
- .IR Chancreate
- allocates a new channel and initializes it.
- .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 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 closed
- 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.
- .TP
- .B /mnt/temp
- a place for
- .I procexec
- to create pipes.
- .SH SOURCE
- .B /sys/src/libthread
- .SH SEE ALSO
- .IR intro (2),
- .IR ioproc (2),
- .IR lock (2)
|