Subject: Call for assistance: porters wanted for nathanw_sa support
To: None <tech-kern@netbsd.org>
From: Nathan J. Williams <nathanw@wasabisystems.com>
List: tech-kern
Date: 10/31/2001 19:44:54
As many of you know, I've been working for some time on an
implementation of scheduler activations for NetBSD, and a
POSIX-compatible thread library built on top of it.

I believe that the MI kernel code is stable enough to merge into the
main source tree. However, there is a certain amount of MD work needed
to make each platform build and run with the new code. I have done
this work on the i386 and alpha, and powerpc code is forthcoming. I
would like to ask for volunteers to port the nathanw_sa branch to
other platforms.

Attached to this message is my (rough) set of directions for porting;
porters are also encouraged to look at the i386 and alpha code. I
would like to coordinate the work on the branch, so please contact me
if wou would like to work on a particular architecture.

   - Nathan



How to Add nathanw_sa branch support to an additional port.

I) Administrivia
 
 0) Tell me that you're working on it!

 1) Branch the architecture directories:
   cvs rtag nathanw_sa_base syssrc/sys/arch/PORT
   cvs rtag -b nathanw_sa syssrc/sys/arch/PORT

II) LWP support

 2) Add mcontext support if it doesn't already exist. 
  - sys/arch/PORT/include/mcontext.h should define mcontext_t.
  - sys/arch/PORT/PORT/machdep.c should define cpu_getmcontext() and
    cpu_setmcontext() (prototypes in sys/sys/ucontext.h). The copying
    of data from the trapframe to the mcontext should be similar to
    the existing code in sendsig() and sys__sigreturn14().

 3) Split struct mdproc in sys/arch/PORT/include/proc.h into the
    lwp-specific part, struct mdlwp, and the proc-specific part,
    struct mdproc.  

    Generally, syscall entry pointers go in mdproc; some flags, such
    as per-process AST flags go in mdproc (since they're used by
    signals as well as scheduling); everything else goes in
    mdlwp. struct mdproc may be empty.

 4) Slow and grungy part: Audit all uses of struct proc * and curproc,
    and figure out whether they're trying to refer to the process state
    or execution state, and change appropriately.

    System calls (such as those in sys/arch/PORT/PORT/sys_machdep.c)
    change signature to sys_foo(struct lwp *, void *, register_t
    *). Often the easiest way to convert a syscall is just to add a
    "struct proc *p = l->l_proc;" to the local variable declarations.

    Uses of curproc should remain curproc if they refer to the current
    LWP. If they refer to the current process, change them to
    curproc->l_proc. If they are used in a context where curproc could
    be NULL (such as interrupt context), use something like:

    "l = curproc; p = l ? l->l_proc : NULL;"

    to avoid the l->l_proc dereference when l is NULL.

    open/close/poll/ioctl entry points keep proc * in their signature.

    References to "p->p_md" change to "l->l_md".
    References to "p->p_addr" change to "l->l_addr".

    Replace P_* flags with L_* flags where appropriate. See <sys/lwp.h>
    for a list.

    References to proc0 need to be split into references to proc0 and
    lwp0. Be especially careful about this in locore.s.

    Add "#include <sys/lwp.h>" to files modified to use l->l_*.


 5) PORT/userret.h: Add code to check for P_WEXIT and L_SA_UPCALL to
    userret(). XXX this is apparantly MI, but all of the userret path
    is MD...

 6) Adjuct vm_machdep.c:cpu_exit() to take a second int argument ("proc") and
    to call switch_exit() if it is nonzero, and switch_lwp_exit() if it
    is zero.
 
 7) Modify cpu_switch() to return 0 if no better LWP was found to
    switch to and 1 if another LWP was switched to and switched back to
    this one.


 8) Implement the following functions:
    (locations are just suggestions)

   cpu_preempt(struct lwp *current, struct lwp *new) (locore.s)
        Variant of cpu_switch, but instead of picking a new LWP
        from the run queue, switch to the indicated new LWP.

   switch_lwp_exit(struct lwp *l) (locore.s)
        Clone of switch_exit() but calls lwp_exit2() instead of exit2(). 

   cpu_upcall() (machdep.c)
        Copies out upcall arguments and sets up trapframe for return
        through upcall trampoline, much like sendsig().

   cpu_stashcontext() (machdep.c)
        Puts a ucontext_t representing the current user-level state on
        the user stack, below the currently used area.


   These two can be textually copied from the i386 or alpha trap.c; they
   could be #included from somewhere, but I find #including functions
   distasteful:

   startlwp()  (machdep.c; it's only MD because userret is)
        Takes a ucontext_t * argument (from the lwp_uc_pool), calls
        cpu_setmcontext() in it, returns the ucontext_t to the pool,
        and calls userret().

   upcallret() (ditto)
        Takes a struct lwp * as an argument and calls userret().

   cpu_setfunc() (parallels cpu_fork() in purpose, so it should probably
       go in vm_machdep.c)
       Set the given LWP to start at the given function, via
       proc_trampoline, similar to the way cpu_fork() arranges to call
       func(arg). 

At this point a kernel should build and run normally.

III) Non-SA userlevel support:

 10) In libc/arch/PORT/gen/makecontext.c, implement makecontext(3).
 11) In libc/arch/PORT/{gen,sys}, implement asm stubs for
     resumecontext(), swapcontext(), and getcontext()
 12) In libc/arch/PORT/gen/_lwp.c, implement _lwp_makecontext().


III) pthread support

 13) On the target machine, install the new headers ("make includes" in
     the sa-branch sys/ and include/). Build and install sa-branch libc.

 14) In the pthread/arch/PORT directory (this should be per-CPU, not
     per-platform), implement _getcontext_u(), _setcontext_u(),
     _swapcontext_u() (in _context_u.S), and pthread__switch(),
     pthread__locked_switch(), and pthread__upcall_switch() (in
     pthread_switch.S). In pthread_md, define pthread__sp() as an
     inline function which returns the value of the stack pointer, and
     pthread___uc_sp() as a macro that takes a ucontext_t and extracts
     the stack pointer from it.