THREAD(2)                                               THREAD(2)

          alt, chanclose, chancreate, chanfree, 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

          #include <u.h>
          #include <libc.h>
          #include <thread.h>

          typedef enum {
          } ChanOp;

          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 */

          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)

          int      threadid(void)

     Page 1                       Plan 9             (printed 4/13/24)

     THREAD(2)                                               THREAD(2)

          int      threadgetgrp(void)
          int      threadsetgrp(int group)
          int      threadpid(int id)

          void     threadint(int id)
          void     threadintgrp(int group)
          void     threadkill(int id)
          void     threadkillgrp(int group)

          void     threadsetname(char *fmt, ...)
          char*    threadgetname(void)

          void**   threaddata(void)
          void**   procdata(void)

          Channel* chancreate(int elsize, int nel)
          void     chanfree(Channel *c)

          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);

          void     procexecl(Channel *cpid, char *file, ...)
          void     procexec(Channel *cpid, char *file, char *args[])
          Channel* threadwaitchan(void)

          int      threadnotify(int (*f)(void*, char*), int in)

          The thread library provides parallel programming support
          similar to that of the languages Alef and Newsqueak.
          Threads and procs occupy a shared address space, communicat-
          ing and synchronizing through channels and shared variables.

          A proc is a Plan 9 process that contains one or more
          cooperatively-scheduled threads. Programs using threads must
          replace main by threadmain. The thread library provides a
          main function that sets up a proc with a single thread exe-
          cuting threadmain on a stack of size mainstacksize (default

     Page 2                       Plan 9             (printed 4/13/24)

     THREAD(2)                                               THREAD(2)

          eight kilobytes).  To set mainstacksize, declare a global
          variable initialized to the desired value (e.g., int
          mainstacksize = 1024).

          Threadcreate creates a new thread in the calling proc,
          returning a unique integer identifying the thread; the
          thread executes fn(arg) on a stack of size stacksize. Thread
          stacks are allocated in shared memory, making it valid to
          pass pointers to stack variables between threads and procs.
          Procrfork creates a new proc, and inside that proc creates a
          single thread as threadcreate would, returning the id of the
          created thread.  Procrfork creates the new proc by calling
          rfork (see fork(2)) with flags
          RFPROC|RFMEM|RFNOWAIT|rforkflag.  (The thread library
          depends on all its procs running in the same rendezvous
          group.  Do not include RFREND in rforkflag.) Proccreate is
          identical to procrfork with 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, arg should not point to data on the stack of a func-
          tion that could return before the new process is scheduled.

          Threadexits terminates the calling thread.  If the thread is
          the last in its proc, threadexits also terminates the proc,
          using status as the exit status.  Threadexitsall terminates
          all procs in the program, using status as the exit status.

          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 yield, proccreate, procexec, procexecl, threadexits,
          alt, send, and recv (and the calls related to send and
          recv-see their descriptions further on), plus these from
          lock(2): qlock, rlock, wlock, rsleep. Procs are scheduled by
          the operating system.  Therefore, threads in different procs
          can preempt one another in arbitrary ways and should syn-
          chronize their actions using qlocks (see lock(2)) or channel
          communication.  System calls such as read(2) block the
          entire proc; all threads in a proc block until the system
          call finishes.

          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.  Threadid returns the id for the cur-
          rent 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.
          Threadgetgrp returns the group id for the current thread;
          threadsetgrp sets it.  Threadpid returns the pid of the Plan

     Page 3                       Plan 9             (printed 4/13/24)

     THREAD(2)                                               THREAD(2)

          9 process containing the thread identified by id, or -1 if
          no such thread is found.

          Threadint interrupts a thread that is blocked in a channel
          operation or system call.  Threadintgrp interrupts all
          threads with the given group id.  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.
          Threadkillgrp kills all threads with the given group id.
          Note that threadkill and threadkillgrp will not terminate a
          thread that never relinquishes the processor.

        Names and per-thread data
          Primarily for debugging, threads can have string names asso-
          ciated with them.  Threadgetname returns the current
          thread's name; threadsetname sets it.  The pointer returned
          by threadgetname is only valid until the next call to

          Threaddata returns a pointer to a per-thread pointer that
          may be modified by threaded programs for per-thread storage.
          Similarly, procdata returns a pointer to a per-proc pointer.

        Executing new programs
          Procexecl and procexec are threaded analogues of exec and
          execl (see 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 and set errstr. If cpid is not null, the pid of
          the invoked program will be sent along cpid once the program
          has been started, or -1 will be sent if an error occurs.
          Procexec and procexecl will not access their arguments after
          sending a result along cpid. Thus, programs that malloc the
          argv passed to procexec can safely free it once they have
          received the cpid response.

          Threadwaitchan returns a channel of pointers to Waitmsg
          structures (see wait(2)). When an exec'ed process exits, a
          pointer to a Waitmsg is sent to this channel.  These Waitmsg
          structures have been allocated with malloc(2) and should be
          freed after use.

          A Channel is a buffered or unbuffered queue for fixed-size
          messages.  Procs and threads send messages into the channel
          and recv messages from the channel.  If the channel is
          unbuffered, a send operation blocks until the corresponding
          recv operation occurs and vice versa. Chancreate allocates a
          new channel for messages of size elsize and with a buffer
          holding nel messages.  If nel is zero, the channel is
          unbuffered.  Chanfree frees a channel that is no longer

     Page 4                       Plan 9             (printed 4/13/24)

     THREAD(2)                                               THREAD(2)

          used.  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 chanfree returns immedi-

          Send sends the element pointed at by v to the channel c. If
          v is null, zeros are sent.  Recv receives an element from c
          and stores it in v. If v is null, the received value is dis-
          carded.  Send and recv return 1 on success, -1 if inter-
          rupted.  Nbsend and nbrecv behave similarly, but return 0
          rather than blocking.

          Sendp, nbsendp, sendul, and nbsendul send a pointer or an
          unsigned long; the channel must have been initialized with
          the appropriate elsize. Recvp, nbrecvp, recvul, and nbrecvul
          receive a pointer or an unsigned long; they return zero when
          a zero is received, when interrupted, or (for nbrecvp and
          nbrecvul) when the operation would have blocked.  To distin-
          guish between these three cases, use recv or nbrecv.

          Alt can be used to recv from or send to one of a number of
          channels, as directed by an array of Alt structures, each of
          which describes a potential send or receive operation.  In
          an Alt structure, c is the channel; v the value pointer
          (which may be null); and op the operation: CHANSND for a
          send operation, CHANRCV for a recv operation; CHANNOP for no
          operation (useful when alt is called with a varying set of
          operations).  The array of Alt structures is terminated by
          an entry with op CHANEND or CHANNOBLK.  If at least one Alt
          structure can proceed, one of them is chosen at random to be
          executed.  Alt returns the index of the chosen structure.
          If no operations can proceed and the list is terminated with
          CHANNOBLK, alt returns the index of the terminating
          CHANNOBLK structure.  Otherwise, alt blocks until one of the
          operations can proceed, eventually returning the index of
          the structure it executes.  Alt returns -1 when interrupted.
          The tag and entryno fields in the Alt structure are used
          internally by alt and need not be initialized.  They are not
          used between alt calls.

          Chanprint formats its arguments in the manner of print(2)
          and sends the result to the channel c. The string delivered
          by chanprint is allocated with malloc(2) and should be freed
          upon receipt.

          Chanclose prevents further elements being sent to the chan-
          nel c. After closing a channel, send and recv never block.
          Send always returns -1.  Recv returns -1 if the channel is
          empty.  Alt may choose a CHANSND or CHANRCV that failed
          because the channel was closed.  In this case, the err field
          of the Alt entry points to an error string stating that the

     Page 5                       Plan 9             (printed 4/13/24)

     THREAD(2)                                               THREAD(2)

          channel was closed and the operation was completed with
          failure.  If all entries have been selected and failed
          because they were closed, alt returns -1.

        Errors, notes and resources
          Thread library functions do not return on failure; if errors
          occur, the entire program is aborted.

          Chanclosing returns -1 if no one called chanclose on the
          channel, and otherwise the number of elements still in the

          Threaded programs should use threadnotify in place of
          atnotify (see notify(2)).

          It is safe to use sysfatal (see perror(2)) in threaded pro-
          grams.  Sysfatal will print the error string and call

          It is safe to use rfork (see fork(2)) to manage the names-
          pace, file descriptors, note group, and environment of a
          single process.  That is, it is safe to call rfork with the
          (To create new processes, use proccreate and procrfork.) As
          mentioned above, the thread library depends on all procs
          being in the same rendezvous group; do not change the ren-
          dezvous group with rfork.

          /sys/lib/acid/thread  useful acid(1) functions for debugging
                                threaded programs.
                                a full example program.


          intro(2), ioproc(2), lock(2)

     Page 6                       Plan 9             (printed 4/13/24)