#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 /* 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 */