| .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, |
| threadnotify, |
| threadid, |
| threadpid, |
| threadpin, |
| threadunpin, |
| threadsetgrp, |
| threadsetname, |
| threadsetstate, |
| threadspawn, |
| 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 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 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 ). |
| .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. |
| .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 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 |
| .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 |
| .IR 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 |
| .IR 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. |
| .PP |
| .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" . |
| .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 |
| .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 |
| .IR 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 |
| .IR 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 |
| .IR intro (3), |
| .IR 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 |
| .IR 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. |