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
|
#ifndef QT_H
#define QT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <@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
extern 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
extern void qt_null (void);
extern 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
extern 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
extern 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
extern 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 */
|