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