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