Commit | Line | Data |
---|---|---|
44986d67 MD |
1 | #ifndef QT_H |
2 | #define QT_H | |
3 | ||
8f99e3f3 SJ |
4 | #if defined (QT_IMPORT) |
5 | # define QT_API __declspec (dllimport) extern | |
6 | #elif defined (QT_EXPORT) || defined (DLL_EXPORT) | |
7 | # define QT_API __declspec (dllexport) extern | |
8 | #else | |
9 | # define QT_API extern | |
10 | #endif | |
11 | ||
44986d67 MD |
12 | #ifdef __cplusplus |
13 | extern "C" { | |
14 | #endif | |
15 | ||
0e850825 | 16 | #include <qt/@qtmd_h@> |
44986d67 MD |
17 | |
18 | ||
19 | /* A QuickThreads thread is represented by it's current stack pointer. | |
20 | To restart a thread, you merely need pass the current sp (qt_t*) to | |
21 | a QuickThreads primitive. `qt_t*' is a location on the stack. To | |
22 | improve type checking, represent it by a particular struct. */ | |
23 | ||
24 | typedef struct qt_t { | |
25 | char dummy; | |
26 | } qt_t; | |
27 | ||
28 | ||
29 | /* Alignment is guaranteed to be a power of two. */ | |
30 | #ifndef QT_STKALIGN | |
31 | #error "Need to know the machine-dependent stack alignment." | |
32 | #endif | |
33 | ||
34 | #define QT_STKROUNDUP(bytes) \ | |
35 | (((bytes)+QT_STKALIGN) & ~(QT_STKALIGN-1)) | |
36 | ||
37 | ||
38 | /* Find ``top'' of the stack, space on the stack. */ | |
39 | #ifndef QT_SP | |
40 | #ifdef QT_GROW_DOWN | |
41 | #define QT_SP(sto, size) ((qt_t *)(&((char *)(sto))[(size)])) | |
42 | #endif | |
43 | #ifdef QT_GROW_UP | |
44 | #define QT_SP(sto, size) ((void *)(sto)) | |
45 | #endif | |
46 | #if !defined(QT_SP) | |
47 | #error "QT_H: Stack must grow up or down!" | |
48 | #endif | |
49 | #endif | |
50 | ||
51 | ||
52 | /* The type of the user function: | |
53 | For non-varargs, takes one void* function. | |
54 | For varargs, takes some number of arguments. */ | |
55 | typedef void *(qt_userf_t)(void *pu); | |
56 | typedef void *(qt_vuserf_t)(int arg0, ...); | |
57 | ||
58 | /* For non-varargs, just call a client-supplied function, | |
59 | it does all startup and cleanup, and also calls the user's | |
60 | function. */ | |
61 | typedef void (qt_only_t)(void *pu, void *pt, qt_userf_t *userf); | |
62 | ||
63 | /* For varargs, call `startup', then call the user's function, | |
64 | then call `cleanup'. */ | |
65 | typedef void (qt_startup_t)(void *pt); | |
66 | typedef void (qt_cleanup_t)(void *pt, void *vuserf_return); | |
67 | ||
68 | ||
69 | /* Internal helper for putting stuff on stack. */ | |
70 | #ifndef QT_SPUT | |
71 | #define QT_SPUT(top, at, val) \ | |
72 | (((qt_word_t *)(top))[(at)] = (qt_word_t)(val)) | |
73 | #endif | |
74 | ||
75 | ||
76 | /* Push arguments for the non-varargs case. */ | |
77 | #ifndef QT_ARGS | |
78 | ||
79 | #ifndef QT_ARGS_MD | |
80 | #define QT_ARGS_MD (0) | |
81 | #endif | |
82 | ||
83 | #ifndef QT_STKBASE | |
84 | #error "Need to know the machine-dependent stack allocation." | |
85 | #endif | |
86 | ||
87 | /* All things are put on the stack relative to the final value of | |
88 | the stack pointer. */ | |
89 | #ifdef QT_GROW_DOWN | |
90 | #define QT_ADJ(sp) (((char *)sp) - QT_STKBASE) | |
91 | #else | |
92 | #define QT_ADJ(sp) (((char *)sp) + QT_STKBASE) | |
93 | #endif | |
94 | ||
95 | #define QT_ARGS(sp, pu, pt, userf, only) \ | |
96 | (QT_ARGS_MD (QT_ADJ(sp)), \ | |
97 | QT_SPUT (QT_ADJ(sp), QT_ONLY_INDEX, only), \ | |
98 | QT_SPUT (QT_ADJ(sp), QT_USER_INDEX, userf), \ | |
99 | QT_SPUT (QT_ADJ(sp), QT_ARGT_INDEX, pt), \ | |
100 | QT_SPUT (QT_ADJ(sp), QT_ARGU_INDEX, pu), \ | |
101 | ((qt_t *)QT_ADJ(sp))) | |
102 | ||
103 | #endif | |
104 | ||
105 | ||
106 | /* Push arguments for the varargs case. | |
107 | Has to be a function call because initialization is an expression | |
108 | and we need to loop to copy nbytes of stuff on to the stack. | |
109 | But that's probably OK, it's not terribly cheap, anyway. */ | |
110 | ||
111 | #ifdef QT_VARGS_DEFAULT | |
112 | #ifndef QT_VARGS_MD0 | |
113 | #define QT_VARGS_MD0(sp, vasize) (sp) | |
114 | #endif | |
115 | #ifndef QT_VARGS_MD1 | |
116 | #define QT_VARGS_MD1(sp) do { ; } while (0) | |
117 | #endif | |
118 | ||
119 | #ifndef QT_VSTKBASE | |
120 | #error "Need base stack size for varargs functions." | |
121 | #endif | |
122 | ||
123 | /* Sometimes the stack pointer needs to munged a bit when storing | |
124 | the list of arguments. */ | |
125 | #ifndef QT_VARGS_ADJUST | |
126 | #define QT_VARGS_ADJUST(sp) (sp) | |
127 | #endif | |
128 | ||
129 | /* All things are put on the stack relative to the final value of | |
130 | the stack pointer. */ | |
131 | #ifdef QT_GROW_DOWN | |
132 | #define QT_VADJ(sp) (((char *)sp) - QT_VSTKBASE) | |
133 | #else | |
134 | #define QT_VADJ(sp) (((char *)sp) + QT_VSTKBASE) | |
135 | #endif | |
136 | ||
8f99e3f3 | 137 | QT_API qt_t *qt_vargs (qt_t *sp, int nbytes, void *vargs, |
44986d67 MD |
138 | void *pt, qt_startup_t *startup, |
139 | qt_vuserf_t *vuserf, qt_cleanup_t *cleanup); | |
140 | ||
141 | #ifndef QT_VARGS | |
142 | #define QT_VARGS(sp, nbytes, vargs, pt, startup, vuserf, cleanup) \ | |
143 | (qt_vargs (sp, nbytes, vargs, pt, startup, vuserf, cleanup)) | |
144 | #endif | |
145 | ||
146 | #endif | |
147 | ||
8f99e3f3 SJ |
148 | QT_API void qt_null (void); |
149 | QT_API void qt_error (void); | |
44986d67 MD |
150 | |
151 | /* Save the state of the thread and call the helper function | |
152 | using the stack of the new thread. */ | |
153 | typedef void *(qt_helper_t)(qt_t *old, void *a0, void *a1); | |
154 | typedef void *(qt_block_t)(qt_helper_t *helper, void *a0, void *a1, | |
155 | qt_t *newthread); | |
156 | ||
157 | /* Rearrange the parameters so that things passed to the helper | |
158 | function are already in the right argument registers. */ | |
159 | #ifndef QT_ABORT | |
8f99e3f3 | 160 | QT_API void qt_abort (qt_helper_t *h, void *a0, void *a1, qt_t *newthread); |
44986d67 MD |
161 | /* The following does, technically, `return' a value, but the |
162 | user had better not rely on it, since the function never | |
163 | returns. */ | |
164 | #define QT_ABORT(h, a0, a1, newthread) \ | |
165 | do { qt_abort (h, a0, a1, newthread); } while (0) | |
166 | #endif | |
167 | ||
168 | #ifndef QT_BLOCK | |
8f99e3f3 | 169 | QT_API void *qt_block (qt_helper_t *h, void *a0, void *a1, |
44986d67 MD |
170 | qt_t *newthread); |
171 | #define QT_BLOCK(h, a0, a1, newthread) \ | |
172 | (qt_block (h, a0, a1, newthread)) | |
173 | #endif | |
174 | ||
175 | #ifndef QT_BLOCKI | |
8f99e3f3 | 176 | QT_API void *qt_blocki (qt_helper_t *h, void *a0, void *a1, |
44986d67 MD |
177 | qt_t *newthread); |
178 | #define QT_BLOCKI(h, a0, a1, newthread) \ | |
179 | (qt_blocki (h, a0, a1, newthread)) | |
180 | #endif | |
181 | ||
182 | #ifdef __cplusplus | |
183 | } /* Match `extern "C" {' at top. */ | |
184 | #endif | |
185 | ||
186 | #endif /* ndef QT_H */ |