Commit | Line | Data |
---|---|---|
24a647d7 MD |
1 | /* |
2 | * QuickThreads -- Threads-building toolkit. | |
3 | * Copyright (c) 1993 by David Keppel | |
4 | * | |
5 | * Permission to use, copy, modify and distribute this software and | |
6 | * its documentation for any purpose and without fee is hereby | |
7 | * granted, provided that the above copyright notice and this notice | |
8 | * appear in all copies. This software is provided as a | |
9 | * proof-of-concept and for demonstration purposes; there is no | |
10 | * representation about the suitability of this software for any | |
11 | * purpose. | |
12 | */ | |
13 | ||
14 | #include <stdarg.h> | |
15 | #include "qt.h" | |
16 | ||
17 | /* Varargs is harder on the m88k. Parameters are saved on the stack as | |
18 | something like (stack grows down to low memory; low at bottom of | |
19 | picture): | |
20 | ||
21 | | : | |
22 | | arg8 <-- va_list.__va_stk | |
23 | +--- | |
24 | | : | |
25 | +--- | |
26 | | arg7 | |
27 | | : | |
28 | | iarg0 <-- va_list.__va_reg | |
29 | +--- | |
30 | | : | |
31 | | va_list { __va_arg, __va_stk, __va_reg } | |
32 | | : | |
33 | +--- | |
34 | ||
35 | Here, `va_list.__va_arg' is the number of word-size arguments | |
36 | that have already been skipped. Doubles must be double-arligned. | |
37 | ||
38 | What this means for us is that the user's routine needs to be | |
39 | called with an arg list where some of the words in the `__va_stk' | |
40 | part of the parameter list have to be promoted to registers. | |
41 | ||
42 | BUG: doubleword register arguments must be double-aligned. If | |
43 | something is passed as an even # arg and used as an odd # arg or | |
44 | vice-versa, the code in the called routine (in the new thread) that | |
45 | decides how to adjust the index will get it wrong, because it will | |
46 | be expect it to be, say, doubleword aligned and it will really be | |
47 | singleword aligned. | |
48 | ||
49 | I'm not sure you can solve this without knowing the types of all | |
50 | the arguments. All in all, we never promised varargs would work | |
51 | reliably. */ | |
52 | ||
53 | ||
54 | ||
55 | #define QT_VADJ(sp) (((char *)sp) - QT_VSTKBASE) | |
56 | ||
57 | /* Always allocate at least enough space for 8 args; waste some space | |
58 | at the base of the stack to ensure the startup routine doesn't read | |
59 | off the end of the stack. */ | |
60 | ||
61 | #define QT_VARGS_MD0(sp, vabytes) \ | |
62 | ((qt_t *)(((char *)(sp)) - 8*4 - QT_STKROUNDUP(vabytes))) | |
63 | ||
64 | extern void qt_vstart(void); | |
65 | #define QT_VARGS_MD1(sp) (QT_SPUT (sp, QT_1, qt_vstart)) | |
66 | ||
67 | ||
68 | struct qt_t * | |
69 | qt_vargs (struct qt_t *qsp, int nbytes, void *vargs, | |
70 | void *pt, qt_function_t *startup, | |
71 | qt_function_t *vuserf, qt_function_t *cleanup) | |
72 | { | |
73 | va_list ap; | |
74 | int i; | |
75 | int n; /* Number of words into original arg list. */ | |
76 | qt_word_t *sp; | |
77 | int *reg; /* Where to read passed-in-reg args. */ | |
78 | int *stk; /* Where to read passed-on-stk args. */ | |
79 | ||
80 | ap = *(va_list *)vargs; | |
81 | qsp = QT_VARGS_MD0 (qsp, nbytes); | |
82 | sp = (qt_word_t *)qsp; | |
83 | ||
84 | reg = (ap.__va_arg < 8) | |
85 | ? &ap.__va_reg[ap.__va_arg] | |
86 | : 0; | |
87 | stk = &ap.__va_stk[8]; | |
88 | n = ap.__va_arg; | |
89 | for (i=0; i<nbytes/sizeof(qt_word_t) && n<8; ++i,++n) { | |
90 | sp[i] = *reg++; | |
91 | } | |
92 | for (; i<nbytes/sizeof(qt_word_t); ++i) { | |
93 | sp[i] = *stk++; | |
94 | } | |
95 | ||
96 | #ifdef QT_NDEF | |
97 | for (i=0; i<nbytes/sizeof(qt_word_t); ++i) { | |
98 | sp[i] = (n < 8) | |
99 | ? *reg++ | |
100 | : *stk++; | |
101 | ++n; | |
102 | } | |
103 | #endif | |
104 | ||
105 | QT_VARGS_MD1 (QT_VADJ(sp)); | |
106 | QT_SPUT (QT_VADJ(sp), QT_VARGT_INDEX, pt); | |
107 | QT_SPUT (QT_VADJ(sp), QT_VSTARTUP_INDEX, startup); | |
108 | QT_SPUT (QT_VADJ(sp), QT_VUSERF_INDEX, vuserf); | |
109 | QT_SPUT (QT_VADJ(sp), QT_VCLEANUP_INDEX, cleanup); | |
110 | return ((qt_t *)QT_VADJ(sp)); | |
111 | } |