00001 /* 00002 * QuickThreads -- Threads-building toolkit. 00003 * Copyright (c) 1993 by David Keppel 00004 * 00005 * Permission to use, copy, modify and distribute this software and 00006 * its documentation for any purpose and without fee is hereby 00007 * granted, provided that the above copyright notice and this notice 00008 * appear in all copies. This software is provided as a 00009 * proof-of-concept and for demonstration purposes; there is no 00010 * representation about the suitability of this software for any 00011 * purpose. 00012 */ 00013 00014 #ifndef QUICKTHREADS_KSR1_H 00015 #define QUICKTHREADS_KSR1_H 00016 00017 /* 00018 Stack layout: 00019 00020 Registers are saved in strictly low to high order, FPU regs first 00021 (only if qt_block is called), CEU regs second, IPU regs next, with no 00022 padding between the groups. 00023 00024 Callee-save: f16..f63; c15..c30; i12..i30. 00025 Args passed in i2..i5. 00026 00027 Note: c31 is a private data pointer. It is not changed on thread 00028 swaps with the assumption that it represents per-processor rather 00029 than per-thread state. 00030 00031 Note: i31 is an instruction count register that is updated by the 00032 context switch routines. Like c31, it is not changed on context 00033 switches. 00034 00035 This is what we want on startup: 00036 00037 00038 +------ <-- BOS: Bottom of stack (grows down) 00039 | 80 (128 - 48) bytes of padding to a 128-byte boundary 00040 +--- 00041 | only 00042 | userf 00043 | t 00044 | u 00045 | qt_start$TXT 00046 | (empty) <-- qt.sp 00047 +------ <-- (BOS - 128) 00048 00049 This is why we want this on startup: 00050 00051 A thread begins running when the restore procedure switches thread stacks 00052 and pops a return address off of the top of the new stack (see below 00053 for the reason why we explicitly store qt_start$TXT). The 00054 block procedure pushes two jump addresses on a thread's stack before 00055 it switches stacks. The first is the return address for the block 00056 procedure, and the second is a restore address. The return address 00057 is used to jump back to the thread that has been switched to; the 00058 restore address is a jump within the block code to restore the registers. 00059 Normally, this is just a jump to the next address. However, on thread 00060 startup, this is a jump to qt_start$TXT. (The block procedure stores 00061 the restore address at an offset of 8 bytes from the top of the stack, 00062 which is also the offset at which qt_start$TXT is stored on the stacks 00063 of new threads. Hence, when the block procedure switches to a new 00064 thread stack, it will initially jump to qt_start$TXT; thereafter, 00065 it jumps to the restore code.) 00066 00067 qt_start$TXT, after it has read the initial data on the new thread's 00068 stack and placed it in registers, pops the initial stack frame 00069 and gives the thread the entire stack to use for execution. 00070 00071 The KSR runtime system has an unusual treatment of pointers to 00072 functions. From C, taking the `name' of a function yields a 00073 pointer to a _constant block_ and *not* the address of the 00074 function. The zero'th entry in the constant block is a pointer to 00075 the function. 00076 00077 We have to be careful: the restore procedure expects a return 00078 address on the top of the stack (pointed to by qt.sp). This is not 00079 a problem when restoring a thread that has run before, since the 00080 block routine would have stored the return address on top of the 00081 stack. However, when ``faking up'' a thread start (bootstrapping a 00082 thread stack frame), the top of the stack needs to contain a 00083 pointer to the code that will start the thread running. 00084 00085 The pointer to the startup code is *not* `qt_start'. It is the 00086 word *pointed to* by `qt_start'. Thus, we dereference `qt_start', 00087 see QUICKTHREADS_ARGS_MD below. 00088 00089 On varargs startup (still unimplemented): 00090 00091 | padding to 128 byte boundary 00092 | varargs <-- padded to a 128-byte-boundary 00093 +--- 00094 | caller's frame, 16 bytes 00095 | 80 bytes of padding (frame padded to a 128-byte boundary) 00096 +--- 00097 | cleanup 00098 | vuserf 00099 | startup 00100 | t 00101 +--- 00102 | qt_start <-- qt.sp 00103 +--- 00104 00105 Of a suspended thread: 00106 00107 +--- 00108 | caller's frame, 16 bytes 00109 | fpu registers 47 regs * 8 bytes/reg 376 bytes 00110 | ceu registers 16 regs * 8 bytes/reg 128 bytes 00111 | ipu registers 19 regs * 8 bytes/reg 152 bytes 00112 | : 00113 | 80 bytes of padding 00114 | : 00115 | qt_restore <-- qt.sp 00116 +--- 00117 00118 */ 00119 00120 00121 #define QUICKTHREADS_STKALIGN 128 00122 #define QUICKTHREADS_GROW_DOWN 00123 typedef unsigned long qt_word_t; 00124 00125 #define QUICKTHREADS_STKBASE QUICKTHREADS_STKALIGN 00126 #define QUICKTHREADS_VSTKBASE QUICKTHREADS_STKBASE 00127 00128 extern void qt_start(void); 00129 /* 00130 * See the discussion above for what indexing into a procedure ptr 00131 * does for us (it's lovely, though, isn't it?). 00132 * 00133 * This assumes that the address of a procedure's code is the 00134 * first word in a procedure's constant block. That's how the manual 00135 * says it will be arranged. 00136 */ 00137 #define QUICKTHREADS_ARGS_MD(sp) (QUICKTHREADS_SPUT (sp, 1, ((qt_word_t *)qt_start)[0])) 00138 00139 /* 00140 * The *index* (positive offset) of where to put each value. 00141 * See the picture of the stack above that explains the offsets. 00142 */ 00143 #define QUICKTHREADS_ONLY_INDEX (5) 00144 #define QUICKTHREADS_USER_INDEX (4) 00145 #define QUICKTHREADS_ARGT_INDEX (3) 00146 #define QUICKTHREADS_ARGU_INDEX (2) 00147 00148 #define QUICKTHREADS_VARGS_DEFAULT 00149 #define QUICKTHREADS_VARGS(sp, nb, vargs, pt, startup, vuserf, cleanup) \ 00150 (qt_vargs (sp, nbytes, &vargs, pt, startup, vuserf, cleanup)) 00151 00152 00153 #define QUICKTHREADS_VARGS_MD0(sp, vabytes) \ 00154 ((qt_t *)(((char *)(sp)) - 4*8 - QUICKTHREADS_STKROUNDUP(vabytes))) 00155 00156 extern void qt_vstart(void); 00157 #define QUICKTHREADS_VARGS_MD1(sp) (QUICKTHREADS_SPUT (sp, 0, ((qt_word_t *)qt_vstart)[0])) 00158 00159 #define QUICKTHREADS_VCLEANUP_INDEX (4) 00160 #define QUICKTHREADS_VUSERF_INDEX (3) 00161 #define QUICKTHREADS_VSTARTUP_INDEX (2) 00162 #define QUICKTHREADS_VARGT_INDEX (1) 00163 00164 #endif /* def QUICKTHREADS_KSR1_H */
1.2.18