| .TH THREAD 3 |
| .SH NAME |
| alt, |
| chancreate, |
| chanfree, |
| chaninit, |
| 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 |
| .PP |
| .de EX |
| .nf |
| .ft B |
| .. |
| .de EE |
| .fi |
| .ft R |
| .. |
| .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; |
| }; |
| .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 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) |
| 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 |
| 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, ...) |
| .XX |
| int procexecl(Channel *cpid, char *file, ...) |
| int procexec(Channel *cpid, 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 ). |
| .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 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 (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 |
| 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 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). |
| 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 (3)) |
| or channel communication. |
| System calls such as |
| .IR read (3) |
| 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. |
| .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 |
| .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 Procexecl |
| and |
| .I procexec |
| are threaded analogues of |
| .I exec |
| and |
| .I execl |
| (see |
| .IR exec (3)); |
| 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. |
| .I Threadwaitchan |
| returns a channel of pointers to |
| .B Waitmsg |
| structures (see |
| .IR 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 |
| .IR 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" . |
| .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 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 |
| .IR print (3) |
| and sends the result to the channel |
| .IR c. |
| The string delivered by |
| .I chanprint |
| is allocated with |
| .IR 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 |
| .IR notify (3)). |
| .PP |
| It is safe to use |
| .B sysfatal |
| (see |
| .IR perror (3)) |
| 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 (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 /usr/local/plan9/acid/thread |
| contains useful |
| .IR acid (1) |
| functions for debugging threaded programs. |
| .PP |
| .B /usr/local/plan9/src/libthread/example.c |
| contains a full example program. |
| .SH SOURCE |
| .B /usr/local/plan9/src/libthread |
| .SH SEE ALSO |
| .IR intro (3), |
| .IR ioproc (3) |