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