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