| /* | |
| * QuickThreads -- Threads-building toolkit. | |
| * Copyright (c) 1993 by David Keppel | |
| * | |
| * Permission to use, copy, modify and distribute this software and | |
| * its documentation for any purpose and without fee is hereby | |
| * granted, provided that the above copyright notice and this notice | |
| * appear in all copies. This software is provided as a | |
| * proof-of-concept and for demonstration purposes; there is no | |
| * representation about the suitability of this software for any | |
| * purpose. | |
| */ | |
| #ifndef QUICKTHREADS_VAX_H | |
| #define QUICKTHREADS_VAX_H | |
| typedef unsigned long qt_word_t; | |
| /* Thread's initial stack layout on the VAX: | |
| non-varargs: | |
| +--- | |
| | arg[2] === `userf' on startup | |
| | arg[1] === `pt' on startup | |
| | arg[0] === `pu' on startup | |
| | ... === `only' on startup. | |
| +--- | |
| | ret pc === `qt_start' on startup | |
| | fp === 0 on startup | |
| | ap === 0 on startup | |
| | <mask> | |
| | 0 (handler) <--- qt_t.sp | |
| +--- | |
| When a non-varargs thread is started, it ``returns'' to the start | |
| routine, which calls the client's `only' function. | |
| The varargs case is clearly bad code. The various values should be | |
| stored in a save area and snarfed in to callee-save registers on | |
| startup. However, it's too painful to figure out the register | |
| mask (right now), so do it the slow way. | |
| +--- | |
| | arg[n-1] | |
| | .. | |
| | arg[0] | |
| | nargs | |
| +--- | |
| | === `cleanup' | |
| | === `vuserf' | |
| | === `startup' | |
| | === `pt' | |
| +--- | |
| | ret pc === `qt_start' on startup | |
| | fp === 0 on startup | |
| | ap === 0 on startup | |
| | <mask> | |
| | 0 (handler) <--- qt_t.sp | |
| +--- | |
| When a varargs thread is started, it ``returns'' to the `qt_vstart' | |
| startup code. The startup code pops all the extra arguments, then | |
| calls the appropriate functions. */ | |
| /* What to do to start a thread running. */ | |
| extern void qt_start (void); | |
| extern void qt_vstart (void); | |
| /* Initial call frame for non-varargs and varargs cases. */ | |
| #define QUICKTHREADS_STKBASE (10 * 4) | |
| #define QUICKTHREADS_VSTKBASE (9 * 4) | |
| /* Stack "must be" 4-byte aligned. (Actually, no, but it's | |
| easiest and probably fastest to do so.) */ | |
| #define QUICKTHREADS_STKALIGN (4) | |
| /* Where to place various arguments. */ | |
| #define QUICKTHREADS_ONLY_INDEX (5) | |
| #define QUICKTHREADS_USER_INDEX (8) | |
| #define QUICKTHREADS_ARGT_INDEX (7) | |
| #define QUICKTHREADS_ARGU_INDEX (6) | |
| #define QUICKTHREADS_VSTARTUP_INDEX (6) | |
| #define QUICKTHREADS_VUSERF_INDEX (7) | |
| #define QUICKTHREADS_VCLEANUP_INDEX (8) | |
| #define QUICKTHREADS_VARGT_INDEX (5) | |
| /* Stack grows down. The top of the stack is the first thing to | |
| pop off (predecrement, postincrement). */ | |
| #define QUICKTHREADS_GROW_DOWN | |
| extern void qt_error (void); | |
| #define QUICKTHREADS_VAX_GMASK_NOREGS (0) | |
| /* Push on the error return address, null termination to call chains, | |
| number of arguments to `only', register save mask (save no | |
| registers). */ | |
| #define QUICKTHREADS_ARGS_MD(sto) \ | |
| (QUICKTHREADS_SPUT (sto, 0, 0), \ | |
| QUICKTHREADS_SPUT (sto, 1, QUICKTHREADS_VAX_GMASK_NOREGS), \ | |
| QUICKTHREADS_SPUT (sto, 2, 0), \ | |
| QUICKTHREADS_SPUT (sto, 3, 0), \ | |
| QUICKTHREADS_SPUT (sto, 4, qt_start)) | |
| #define QUICKTHREADS_VARGS_MD0(sto, nbytes) \ | |
| (QUICKTHREADS_SPUT (sto, (-(nbytes)/4)-1, (nbytes)/4), \ | |
| ((char *)(((sto)-4) - QUICKTHREADS_STKROUNDUP(nbytes)))) | |
| #define QUICKTHREADS_VARGS_ADJUST(sp) ((char *)sp + 4) | |
| #define QUICKTHREADS_VARGS_MD1(sto) \ | |
| (QUICKTHREADS_SPUT (sto, 0, 0), \ | |
| QUICKTHREADS_SPUT (sto, 1, QUICKTHREADS_VAX_GMASK_NOREGS), \ | |
| QUICKTHREADS_SPUT (sto, 2, 0), \ | |
| QUICKTHREADS_SPUT (sto, 3, 0), \ | |
| QUICKTHREADS_SPUT (sto, 4, qt_vstart)) | |
| #define QUICKTHREADS_VARGS_DEFAULT | |
| #endif /* QUICKTHREADS_VAX_H */ |