THREAD(2)                                               THREAD(2)

     NAME
          alt, chancreate, chanfree, chaninit, proccreate, procdata,
          procexec, procexecl, procrfork, recv, recvp, recvul, send,
          sendp, sendul, nbrecv, nbrecvp, nbrecvul, nbsend, nbsendp,
          nbsendul, threadchdir, threadcreate, threaddata,
          threadexits, threadexitsall, threadgetgrp, threadgetname,
          threadkill, threadkillgrp, threadmain, threadnonotes,
          threadpid, threadprint, threadsetgrp, threadsetname,
          threadwaitchan, yield - thread and proc management

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

          #define CHANEND     0
          #define CHANSND     1
          #define CHANRCV     2
          #define CHANNOP     3
          #define CHANNOBLK   4

          typedef struct Alt {
              Channel *c;
              void    *v;
              int op;
              Channel **tag;
              ulong   q;
          } Alt;

          void  threadmain(int argc, char *argv[])
          int   proccreate(void (*f)(void *arg), void *arg,
                      uint stacksize)
          int   procrfork(void (*f)(void *arg), void *arg,
                      uint stacksize, int rforkflag)
          int   threadcreate(void (*f)(void *arg), void *arg,
                      uint stacksize)
          void  yield(void)
          void  threadexits(char *status)
          void  threadexitsall(char *status)
          Channel *chancreate(int elemsize, int bufsize)
          int chaninit(Channel *c, int elemsize, int elemcnt)
          int   alt(Alt alts[])
          int   recv(Channel *c, void *v)
          ulong recvul(Channel *c)
          void  *recvp(Channel *c)
          int   nbrecv(Channel *c, void *v)
          ulong nbrecvul(Channel *c)
          void  *nbrecvp(Channel *c)
          int   send(Channel *c, void *v)
          int   sendul(Channel *c, ulong v)

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

     THREAD(2)                                               THREAD(2)

          int   sendp(Channel *c, void *v)
          int   nbsend(Channel *c, void *v)
          int   nbsendul(Channel *c, ulong v)
          int   nbsendp(Channel *c, void *v)
          void  chanfree(Channel *c)
          void  threadsetname(char *name)
          char  *threadgetname(void)
          ulong *procdata(void)
          ulong *threaddata(void)
          int   threadgetgrp(void)
          int   threadsetgrp(int group)
          void threadkill(int id)
          void  threadkillgrp(int group)
          int threadpid(int id)
          void  procexecl(Channel *pidc, char *file, ...)
          void  procexec(Channel *pidc, char *file, char *args[])
          Channel *threadwaitchan(void)
          int   threadprint(int fd, char *format, ...)

     DESCRIPTION
          The thread library provides parallel-programming support
          similar to that of the languages Alef and Newsqueak.
          Threads and procs can be created that occupy a shared
          address space in which they can communicate through shared
          variables and channels. A Channel is a buffered or
          unbuffered FIFO for fixed-size messages.  Procs and threads
          can send messages into the fifo and recv messages from the
          fifo.  If the fifo is unbuffered, a send operation blocks
          until the corresponding recv operation occurs and vice
          versa.

          A proc is a Plan 9 process that contains one or more
          threads. The threads in a proc are coroutines.  Runnable
          threads are scheduled nonpreemptively in a round-robin fash-
          ion.  A thread must explicitly relinquish control of the
          processor before another thread in the same proc is run.
          Calls that do this are yield, send, recv (and the calls
          related to send and recv - see their descriptions further
          on), alt, and threadexits.

          Procs are scheduled by the operating system.  Threads in
          different procs, therefore, can preempt one another in arbi-
          trary ways, unless they explicitly synchronize their actions
          using qlocks (see lock(2)) or channel communication.

          Blocking system calls such as read(2) do not cause another
          thread in the same proc to be scheduled.  All threads in a
          proc block until the system call finishes.

          Thread stacks are in shared memory, making it valid to pass
          pointers to stack variables between threads and procs.

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

     THREAD(2)                                               THREAD(2)

          Threads in different procs are scheduled independently and
          preemptively.  Data structures shared between threads in
          different procs need to be protected by a lock(2).

          Programs using threads must replace main by threadmain. The
          thread library will set up a proc with a single thread and
          call threadmain.

          A new proc is created by a call to proccreate. The arguments
          are a function f with a single void* argument to be called
          in the new proc, the argument arg to that function, and the
          size of the stack for the new proc.  Proccreate returns the
          pid of the newly created proc.  Processes are created by
          calling rfork (see fork(2)) with flags RFPROC and RFMEM.
          Procrfork is like proccreate but uses rforkflags or'ed with
          RFPROC and RFMEM.

          Arg can be used to pass arbitrary data to f. Be aware, how-
          ever, that f runs in a new process and that it can take some
          time before f is scheduled.  Arg should not point to data on
          the stack of a function that could return before the new
          process is scheduled.

          Threadcreate creates a new thread in the proc of the calling
          thread.  The arguments are the same as those of proccreate.
          Threadcreate returns a thread id.

          Yield gives up the processor to another thread in the call-
          ing proc.

          Threadexits causes the calling thread to be destroyed.  If
          the thread is the only remaining thread in its proc, the
          proc exits too (using the exit status supplied to
          threadexits).

          Threadexitsall kills all threads in the application (and
          thus all procs) and exits with the status supplied.

          Chancreate creates a buffered or unbuffered Channel.  The
          arguments are the size of the elements in the channel (must
          by greater than zero) and the number of elements in the
          fifo.  If the number is zero, the channel is blocking (syn-
          chronous).  If it is greater than zero, the channel is buf-
          fered and blocks only if the fifo is empty (recv) or full
          (send).  Chancreate returns a pointer to the channel cre-
          ated.

          Chaninit initializes an already allocated channel; elemsize,
          and elemcnt are as in chancreate.

          Recv receives an element from the channel named by its first
          argument and stores it in the location pointed to by its

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

     THREAD(2)                                               THREAD(2)

          second argument.  It returns 1 for success, and -1 when it
          was interrupted.  If the second argument is null, the
          received value is ignored.

          Recvul and recvp receive an unsigned long or a pointer,
          respectively, from a channel whose element size must be
          sizeof(ulong) or sizeof(void *).

          Nbrecv, nbrecvul, and nbrecvp are non-blocking versions of
          recv, recvul, and recvp. Note that nbrecvul and nbrecvp can
          also return 0 when the channel is empty.  Since 0 is both a
          valid data value and an error return, use nbrecv instead if
          you wish to distinguish an empty channel from one that con-
          tains a zero element.

          Send sends the value pointed to by the second parameter to
          the channel pointed to by the first parameter.  If the value
          pointer is 0, zeroes are sent.  Send yields, so, if the
          receiving thread is blocked and in the same proc, it will
          run first.

          Sendul, sendp, nbsend, nbsendul, and nbsendp are the spe-
          cialized and nonblocking versions, analogous to the recv
          family of calls.

          Alt can be used to recv from or send to one of a number of
          channels.  Alt takes as its parameter an array of Alt struc-
          tures.  Each of these structures describes a potential send
          or recv operation: c and v are the channel and value pointer
          (which may be nil) and op specifies the operation: CHANSND
          for a send operation, CHANRECV for a recv operation; CHANNOP
          for no operation-the entry should be skipped.  This can be
          useful when alt calls are used with a varying set of opera-
          tions.  The array of Alt structures is terminated by a null
          entry whose opcode is CHANEND or CHANNOBLK.  CHANNOBLK is a
          default entry that `fires' when none of the other operations
          can fire.  It makes an alt statement non-blocking.

          Alt looks for channel operations in the array of Alt struc-
          tures that can proceed.  If there is one, the associated
          send or recv operation occurs.  If there is more than one,
          one of them is chosen at random and the associated communi-
          cation event occurs.  If there are none, and the list is
          terminated by a CHANEND entry, alt blocks until one of the
          operations can proceed. If there are none and the list is
          terminated by a CHANNOBLK entry, that entry will fire.  Alt
          returns the index of the operation that succeeded.  The
          fields tag and q in the Alt structure are used by the imple-
          mentation of alt.  They are not used between alt calls.

          Chanfree frees a channel that is no longer used.  Chanfree
          can be called by either sender or receiver after the last

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

     THREAD(2)                                               THREAD(2)

          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 instantly).

          Threadgetname and threadsetname can be used to read or set
          the name of a thread.  This can be useful for debugging.

          Threadkill kills the thread identified by its thread ID (as
          returned by threadcreate) and cleans up its stack.

          Procdata returns a pointer to a per-process location (big
          enough to hold a pointer) into which applications can store
          per-proc data.

          Threads have a group number that is inherited on proc and
          thread creation, much like a process group.  Threadsetgrp
          can be used to set this group to an arbitrary integer.
          Threadgetgrp returns the group of the current thread.
          Threadkillgrp can be used to kill all threads in a group.

          Threadpid returns the pid of the proc of the thread whose id
          is given.  If id equals zero, the pid of the proc of the
          current thread is returned and if id does not correspond to
          an existing thread, -1 is returned.

          Procexecl and procexec may only be called from a thread
          which is the sole thread in a proc.  The thread is removed
          from the program and the process executes independently.
          The first argument, if not nil, is a channel on which the
          pid of the exec-ed process will be returned.

          If the pid channel is set, procexec and procexecl will
          return (i.e., fail) if and only if they also send -1 on the
          pid channel.

          The rest of the arguments are the same as those of execl and
          exec (see exec(2)). To simplify resource management, these
          routines first use access(2) to check if the file exists and
          is executable before attempting to exec(2) it.

          Threadwaitchan returns a channel of Waitmsg structures (see
          wait(2)). When a proc exits, a message is sent to this chan-
          nel.  Receiving on this channel will produce the exit status
          of the procs exited.  The wait channel also produces mes-
          sages for procexec-ed processes.

          Threadprint behaves exactly like print (see print(2)) but
          does not suffer from interference with other threads and
          procs, and does not allocate a buffer on the stack.

          An extra note of warning.  Many routines in libc are not
          `thread safe'.  One library routine of particular concern is

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

     THREAD(2)                                               THREAD(2)

          atnotify (see notify(2)). The thread library uses atnotify
          to implement threadexitall, threadkillgrp, and threadkill.
          Do not call notify(2) and expect threadexitall,
          threadkillgrp, and threadkill to continue to work.  Atnotify
          maintains its list of handlers in shared memory.  This
          implies that, if one thread (on proc) installs a handler
          with atnotify, all other procs automatically do so too.

          It is safe to use rfork (see fork(2)) to manage the names-
          pace, file descriptors, or environment of a single process.
          That is, it is safe to call rfork with the flags RFENVG,
          RFCENVG, RFNAMEG, RFCNAMEG, RFFDG, and RFCDFG.  To create
          new processes, use proccreate and procrfork. Because the
          thread library depends on all procs being in the same note
          and rendezvous groups, these groups should not be changed
          with rfork. To deafen a threaded program to notes for the
          parent process's group, call threadnonotes instead of using
          rfork(RFNOTEG).

          Procdata and threaddata return pointers to a single ulong
          that may be used to store per-proc or per-thread data.

     EXAMPLE
          A complete example follows.  Threadmain spawns two subpro-
          cesses, one to read the mouse, and one to receive timer
          events.  The events are sent via a channel to the main proc
          which prints a word when an event comes in.  When mouse but-
          ton three is pressed, the application terminates.

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

          #define STACKSIZE (2*1024)

          void
          error(char *fmt, ...)
          {
              int n;
              va_list arg;

              va_start(arg, fmt);
              fprint(2, fmt, arg);
              threadexitsall("error");
          }

          void
          mouseproc(void *mc) {
              char m[48];
              int mfd;
              Channel* mousechan = mc;

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

     THREAD(2)                                               THREAD(2)

              if ((mfd = open("/dev/mouse", OREAD)) < 0)
                  error("open /dev/mouse: %r\n");
              for (;;) {
                  if (read(mfd, &m, sizeof(m)) != sizeof(m) ||
                    atoi(m+25) & 4) { /* EOF || button 3 down */
                      error("quit\n");
                  }
                  send(mousechan, &m);
              }
          }

          void
          clockproc(void *cc) {
              int t = 0;
              Channel* clockchan = cc;

              while (++t) {
                  sleep(1000);
                  send(clockchan, &t);
              }
          }

          void
          threadmain(int argc, char *argv[]) {
              char m[48];
              int t;
              Alt a[] = {
              /*   c      v       op   */
                  {nil,   &m,     CHANRCV},
                  {nil,   &t,     CHANRCV},
                  {nil,   nil,    CHANEND},
              };

              /* create mouse event channel and mouse process */
              a[0].c = chancreate(sizeof(m), 0);
              proccreate(mouseproc, (void *)(a[0].c), STACKSIZE);

              /* create clock event channel and clock process */
              a[1].c = chancreate(sizeof(t), 0);      /* clock event channel */
              proccreate(clockproc, (void *)(a[1].c), STACKSIZE);

              for (;;) {
                  switch(alt(a)) {
                  case 0: /*mouse event */
                      fprint(2, "click ");
                      break;
                  case 1: /* clock event */
                      fprint(2, "tic ");
                      break;
                  default:
                      error("impossible");

     Page 7                       Plan 9             (printed 4/18/24)

     THREAD(2)                                               THREAD(2)

                  }
              }
          }

     FILES
          /sys/lib/acid/thread contains useful acid(1) functions for
          debugging threaded programs.

     SOURCE
          /sys/src/libthread

     SEE ALSO
          intro(2)

     Page 8                       Plan 9             (printed 4/18/24)