.TH THREAD 2.SH NAMEalt,chanclose,chanclosing,chancreate,chanfree,chaninit,chanprint,mainstacksize,nbrecv,nbrecvp,nbrecvul,nbsend,nbsendp,nbsendul,needstack,proccreate,procdata,procexec,procexecl,procrfork,recv,recvp,recvul,send,sendp,sendul,threadcreate,threaddata,threadexits,threadexitsall,threadgetgrp,threadgetname,threadid,threadint,threadintgrp,threadkill,threadkillgrp,threadmain,threadnotify,threadpid,threadsetgrp,threadsetname,threadwaitchan,tprivaddr,tprivalloc,tprivfree,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>.sptypedef enum { CHANEND, CHANSND, CHANRCV, CHANNOP, CHANNOBLK,} ChanOp;.sp.ta \w' 'u +\w'Channel 'utypedef 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 +4nvoid threadmain(int argc, char *argv[])int mainstacksizeint 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).XXint threadid(void)int threadgrp(void)int threadsetgrp(int group)int threadpid(int id).XXint threadint(int id)void threadintgrp(int group)void threadkill(int id)int threadkillgrp(int group).XXvoid threadsetname(char *name, ...)char* threadgetname(void).XXvoid** threaddata(void)void** procdata(void).XXint chaninit(Channel *c, int elsize, int nel)Channel* chancreate(int elsize, int nel)void chanfree(Channel *c).XXint 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);.XXvoid procexecl(Channel *cpid, char *file, ...)void procexec(Channel *cpid, char *file, char *args[])Channel* threadwaitchan(void).XXint tprivalloc(void)void tprivfree(int i)void** tprivaddr(int i).XXvoid needstack(int nbytes).XXint threadnotify(int (*f)(void*, char*), int in).EE.SH DESCRIPTIONThe thread library provides parallel programming support similar to thatof the languagesAlef and Newsqueak..I Threadsand.I procsoccupy a shared address space,communicating and synchronizing through.I channelsand shared variables..PPA.I procis a Plan 9 process that contains one or more cooperatively-scheduled.IR threads .Programs using threads must replace.I mainby.IR threadmain .The thread library provides a.I mainfunction that sets up a proc with a single thread executing.I threadmainon a stack of size.I mainstacksize(default eight kilobytes).To set.IR mainstacksize ,declare a global variableinitialized to the desired value.RI ( e.g. ,.B int.B mainstacksize.B =.BR 1024 )..SS Creation.I Threadcreatecreates a new thread in the calling proc, returning a unique integeridentifying the thread; the threadexecutes.I fn(arg)on a stack of size.IR stacksize .Thread stacks are allocated in shared memory, making it valid to passpointers to stack variables between threads and procs.Since there is no stack segment protection, the function.I needstackmay be used to.I abortif the caller has not left at least.I nbytesof stack available..I Procrforkcreates a new proc, and inside that proc createsa single thread as.I threadcreatewould,returning the id of the created thread..I Procrforkcreates 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 procsrunning in the same rendezvous group.Do not include.B RFRENDin.IR rforkflag .).I Proccreateis identical to.I procrforkwith.I rforkflagset to zero.Be aware that the calling thread may continueexecution beforethe newly created proc and threadare scheduled.Because of this,.I argshould not point to data on the stack of a function that couldreturn before the new process is scheduled..PP.I Threadexitsterminates the calling thread.If the thread is the last in its proc,.I threadexitsalso terminates the proc, using.I statusas the exit status..I Threadexitsallterminates all procs in the program,using.I statusas the exit status..SS SchedulingThe threads in a proc are coroutines, scheduled non-preemptivelyin a round-robin fashion.A thread must explicitly relinquish control of the processorbefore 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 sendand.IR recv \(emseetheir 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 anotherin arbitrary ways and should synchronize theiractions 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..PPAs 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 Threadidreturns 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 ofthe thread that created it..I Threadgrpreturns the group id for the current thread;.I threadsetgrpsets it..I Threadpidreturns the pid of the Plan 9 process containingthe thread identified by.IR id ,or \-1if no such thread is found..PP.I Threadintinterrupts a thread that is blocked in a channel operationor system call..I Threadintgrpinterrupts all threads with the given group id..I Threadkillmarks 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 Threadkillgrpkills all threads with the given group id.Note that.I threadkilland.I threadkillgrpwill not terminate a thread that never relinquishesthe processor..SS Names and per-thread dataPrimarily for debugging,threads can have string names associated with them..I Threadgetnamereturns the current thread's name;.I threadsetnamesets it.The pointer returned by.I threadgetnameis only valid until the next call to.IR threadsetname ..PP.I Threaddatareturns a pointer to a per-thread pointerthat may be modified by threaded programs forper-thread storage.Similarly,.I procdatareturns a pointer to a per-proc pointer..SS Executing new programs.I Procexecland.I procexecare threaded analogues of.I execand.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 cpidis not null, the pid of the invoked programwill be sent along.I cpidonce the program has been started, or \-1 will be sent if anerror occurs..I Procexecand.I procexeclwill not access their arguments after sending a resultalong.IR cpid .Thus, programs that malloc the.I argvpassed to.I procexeccan safely free it once they havereceived the.I cpidresponse.Note that the mount point.B /mnt/tempmust exist;.I procexec(l)mount pipes there..PP.I Threadwaitchanreturns a channel of pointers to.B Waitmsgstructures (see.IR wait (2)).When an exec'ed process exits, a pointer to a.B Waitmsgis sent to this channel.These.B Waitmsgstructures have been allocated with.IR malloc (2)and should be freed after use..SS ChannelsA.B Channelis a buffered or unbuffered queue for fixed-size messages.Procs and threads.I sendmessages into the channel and.I recvmessages from the channel. If the channel is unbuffered, a.I sendoperation blocks until the corresponding.I recvoperation occurs and.IR "vice versa" ..I Chaninitinitializes a.B Channelfor messages of size.I elsizeand with a buffer holding.I nelmessages.If.I nelis zero, the channel is unbuffered..IR Chancreateallocates a new channel and initializes it..I Chanfreefrees a channel that is no longer used..I Chanfreecan be called by either sender or receiver after the last item has beensent or received. Freeing the channel will be delayed if there is a threadblocked on it until that thread unblocks (but.I chanfreereturns immediately)..PP.I Sendsends the element pointed at by.I vto the channel.IR c .If.I vis null, zeros are sent..I Recvreceives an element from.I cand stores it in.IR v .If.I vis null,the received value is discarded..I Sendand.I recvreturn 1 on success, \-1 if interrupted..I Nbsendand.I nbrecvbehave similarly, but return 0 rather than blocking..PP.IR Sendp ,.IR nbsendp ,.IR sendul ,and.I nbsendulsend a pointer or an unsigned long; the channel musthave been initialized with the appropriate.IR elsize ..IR Recvp ,.IR nbrecvp ,.IR recvul ,and.I nbrecvulreceive a pointer or an unsigned long;they return zero when a zero is received,when interrupted, or(for.I nbrecvpand.IR nbrecvul )when the operation would have blocked.To distinguish between these three cases,use.I recvor.IR nbrecv ..PP.I Altcan be used to recv from or send to one of a number of channels,as directed by an array of.B Altstructures,each of which describes a potential send or receive operation.In an.B Altstructure,.B cis the channel;.B vthe value pointer (which may be null); and.B opthe operation:.B CHANSNDfor a send operation,Lines 1–500 of 669. Load more
.TH THREAD 2 .SH NAME alt, chanclose, chanclosing, chancreate, chanfree, chaninit, chanprint, mainstacksize, nbrecv, nbrecvp, nbrecvul, nbsend, nbsendp, nbsendul, needstack, proccreate, procdata, procexec, procexecl, procrfork, recv, recvp, recvul, send, sendp, sendul, threadcreate, threaddata, threadexits, threadexitsall, threadgetgrp, threadgetname, threadid, threadint, threadintgrp, threadkill, threadkillgrp, threadmain, threadnotify, threadpid, threadsetgrp, threadsetname, threadwaitchan, tprivaddr, tprivalloc, tprivfree, 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 tprivalloc(void) void tprivfree(int i) void** tprivaddr(int i) .XX void needstack(int nbytes) .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. Since there is no stack segment protection, the function .I needstack may be used to .I abort if the caller has not left at least .I nbytes of stack available. .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,