| /* |
| * QuickThreads -- Threads-building toolkit. |
| * Copyright (c) 1993 by David Keppel |
| * |
| * Permission to use, copy, modify and distribute this software and |
| * its documentation for any purpose and without fee is hereby |
| * granted, provided that the above copyright notice and this notice |
| * appear in all copies. This software is provided as a |
| * proof-of-concept and for demonstration purposes; there is no |
| * representation about the suitability of this software for any |
| * purpose. |
| */ |
| |
| #include <stdarg.h> |
| #include "qt.h" |
| |
| |
| /* Varargs is harder on the AXP. Parameters are saved on the stack as |
| something like (stack grows down to low memory; low at bottom of |
| picture): |
| |
| | : |
| | arg6 |
| +--- |
| | iarg5 |
| | : |
| | iarg3 <-- va_list._a0 + va_list._offset |
| | : |
| | iarg0 <-- va_list._a0 |
| +--- |
| | farg5 |
| | : |
| | farg0 |
| +--- |
| |
| When some of the arguments have known type, there is no need to |
| save all of them in the struct. So, for example, if the routine is |
| called |
| |
| zork (int a0, float a1, int a2, ...) |
| { |
| va_list ap; |
| va_start (ap, a2); |
| qt_vargs (... &ap ...); |
| } |
| |
| then offset is set to 3 * 8 (8 === sizeof machine word) = 24. |
| |
| What this means for us is that the user's routine needs to be |
| called with an arg list where some of the words in the `any type' |
| parameter list have to be split and moved up in to the int/fp |
| region. |
| |
| Ways in which this can fail: |
| - The user might not know the size of the pushed arguments anyway. |
| - Structures have funny promotion rules. |
| - Probably lots of other things. |
| |
| All in all, we never promised varargs would work reliably. */ |
| |
| |
| |
| #define QUICKTHREADS_VADJ(sp) (((char *)sp) - QUICKTHREADS_VSTKBASE) |
| |
| #define QUICKTHREADS_VARGS_MD0(sp, vabytes) \ |
| ((qt_t *)(((char *)(sp)) - 6*2*8 - QUICKTHREADS_STKROUNDUP(vabytes))) |
| |
| extern void qt_vstart(void); |
| #define QUICKTHREADS_VARGS_MD1(sp) (QUICKTHREADS_SPUT (sp, QUICKTHREADS_R26, qt_vstart)) |
| |
| |
| /* Different machines use different implementations for varargs. |
| Unfortunately, the code below ``looks in to'' the varargs |
| structure, `va_list', and thus depends on the conventions. |
| The following #defines try to deal with it but don't catch |
| everything. */ |
| |
| #ifdef __GNUC__ |
| #define _a0 __base |
| #define _offset __offset |
| #else |
| #ifdef __OSF1__ |
| #define _a0 a0 |
| #define _offset offset |
| #endif |
| #endif /* def __GNUC__ */ |
| |
| |
| struct qt_t * |
| qt_vargs (struct qt_t *qsp, int nbytes, struct va_list *vargs, |
| void *pt, qt_function_t *startup, |
| qt_function_t *vuserf, qt_function_t *cleanup) |
| { |
| va_list ap; |
| int i; |
| int max; /* Maximum *words* of args to copy. */ |
| int tmove; /* *Words* of args moved typed->typed. */ |
| qt_word_t *sp; |
| |
| ap = *(va_list *)vargs; |
| qsp = QUICKTHREADS_VARGS_MD0 (qsp, nbytes); |
| sp = (qt_word_t *)qsp; |
| |
| tmove = 6 - ap._offset/sizeof(qt_word_t); |
| |
| /* Copy from one typed area to the other. */ |
| for (i=0; i<tmove; ++i) { |
| /* Integer args: */ |
| sp[i+6] = ((qt_word_t *)(ap._a0 + ap._offset))[i]; |
| /* Fp args: */ |
| sp[i] = ((qt_word_t *)(ap._a0 + ap._offset))[i-6]; |
| } |
| |
| max = nbytes/sizeof(qt_word_t); |
| |
| /* Copy from the untyped area to the typed area. Split each arg. |
| in to integer and floating-point save areas. */ |
| for (; i<6 && i<max; ++i) { |
| sp[i] = sp[i+6] = ((qt_word_t *)(ap._a0 + ap._offset))[i]; |
| } |
| |
| /* Copy from the untyped area to the other untyped area. */ |
| for (; i<max; ++i) { |
| sp[i+6] = ((qt_word_t *)(ap._a0 + ap._offset))[i]; |
| } |
| |
| QUICKTHREADS_VARGS_MD1 (QUICKTHREADS_VADJ(sp)); |
| QUICKTHREADS_SPUT (QUICKTHREADS_VADJ(sp), QUICKTHREADS_VARGT_INDEX, pt); |
| QUICKTHREADS_SPUT (QUICKTHREADS_VADJ(sp), QUICKTHREADS_VSTARTUP_INDEX, startup); |
| QUICKTHREADS_SPUT (QUICKTHREADS_VADJ(sp), QUICKTHREADS_VUSERF_INDEX, vuserf); |
| QUICKTHREADS_SPUT (QUICKTHREADS_VADJ(sp), QUICKTHREADS_VCLEANUP_INDEX, cleanup); |
| return ((qt_t *)QUICKTHREADS_VADJ(sp)); |
| } |