UNIX V6 internals
The internals of UNIX V6 are relatively easy to understand, particularly with the aid of the (justly) famed Lions book, John Lions' Commentary on UNIX 6th Edition.
Here are a few notes on various topics which are covered in a bit more detail than in Lions, and which may be helpful.
savu()/retu()/aretu()
These are the primitives which switch, or otherwise adjust, stacks in the kernel. aretu() is significantly different from retu() - the latter switches to a different process/stack, whereas aretu() does a 'non-local goto' in the current process. (Actually, technically, it switches to a different stack frame on the current stack; when the subroutine which had called aretu() returns, it does not return to its caller, but instead returns to the procedure which had called savu().) In addition to switching to a different stack, retu() also switches to a saved stack frame on that stack, in the same manner as aretu().
Note that in PDP-11 C all stack frames look identical, but this is not true of other machines/compilers. So if subroutine A calls savu(), and subroutine B calls aretu(), when the call to aretu() returns, procedure B is still running, but on procedure A's stack frame. So on machines where A's stack frame looks different from B's, hilarity ensues; this famously caused a problem when Unix Seventh Edition was moved to the Interdata 8/32.
Use of savu()/retu()/aretu()
There are actually three sets of saved stack information stored in the 'user' structure (the swappable per-process data block):
int u_rsav[2]; /* save r5,r6 when exchanging stacks */ int u_qsav[2]; /* label variable for quits and interrupts */ int u_ssav[2]; /* label variable for swapping */
Calls to retu(), the primitive to switch stacks/processes, always use rsav. The others are for 'non-local gotos' inside a process.
One can think of qsav as a poor man's exception handler for process software interrupts. When a process is sleeping on some event, when it is interrupted, rather than the sleep() call returning, it wakes up returning from the procedure that did the savu(qsav). (That is because sleep() - which is the procedure that's running when the call to aretu(qsav) returns - does a return immediately after restoring the stack to the frame saved in qsav.)
The ssav is used in association with swapping; when a process is swapped out, since that can happen in a number of ways/places, the stack can contains calls to various things like expand(), etc. When it's swapped back in, the simplest thing to do is to just throw that all away and have it go back to where it was just before it was decided to swap it out.