diff --git a/libguile/ChangeLog b/libguile/ChangeLog index 6c254432a..dec6dcd73 100644 --- a/libguile/ChangeLog +++ b/libguile/ChangeLog @@ -1,3 +1,38 @@ +2008-05-08 Neil Jerram + + * throw.c (scm_ithrow): For IA64 add a return statement, to + appease GCC. + + * threads.h (scm_i_thread): New IA64 fields: + register_backing_store_base and pending_rbs_continuation. + + * threads.c (guilify_self_1): For IA64: cap RBS base address at + the current value of scm_ia64_ar_bsp, and store the capped value + in thread state. + (SCM_MARK_BACKING_STORE): Use thread->register_backing_store_base + instead of scm_ia64_register_backing_store_base(). + (scm_threads_mark_stacks): Add "&" in "&t->regs", so that the code + works both for jmp_buf defined as an array, and jmp_buf defined as + a struct. + + * continuations.h (scm_t_contregs): Remove `fresh' and `ctx' + fields; these are now inside the IA64 definition of `jmp_buf'. + + * continuations.c (scm_make_continuation): Simplify, by moving + some of the IA64 code inside the definition of "setjmp", and by + some obvious commonizations. For IA64 register backing store + (RBS) stack base, use thread->register_backing_store_base instead + of scm_ia64_register_backing_store_base(). + (copy_stack): For IA64, store pointer to continuation being + invoked in thread state, so we can restore the continuation's RBS + stack just before the next setcontext call. + (copy_stack_and_call): Don't restore RBS stack explicitly here. + It will be restored, if appropriate, inside the longjmp call. + (scm_ia64_longjmp): New function. + + * __scm.h (setjmp, longjmp, jmp_buf): For IA64, implement using + getcontext and setcontext. + 2008-05-07 Ludovic Courtès * numbers.c (scm_from_complex_double): Mark as `SCM_UNUSED'. diff --git a/libguile/__scm.h b/libguile/__scm.h index 3d6d9a7f3..b198f9d6a 100644 --- a/libguile/__scm.h +++ b/libguile/__scm.h @@ -402,7 +402,23 @@ # define setjmp setjump # define longjmp longjump # else /* ndef _CRAY1 */ -# include +# if defined (__ia64__) +/* For IA64, emulate the setjmp API using getcontext. */ +# include +# include + typedef struct { + ucontext_t ctx; + int fresh; + } jmp_buf; +# define setjmp(JB) \ + ( (JB).fresh = 1, \ + getcontext (&((JB).ctx)), \ + ((JB).fresh ? ((JB).fresh = 0, 0) : 1) ) +# define longjmp(JB,VAL) scm_ia64_longjmp (&(JB), VAL) + void scm_ia64_longjmp (jmp_buf *, int); +# else /* ndef __ia64__ */ +# include +# endif /* ndef __ia64__ */ # endif /* ndef _CRAY1 */ #endif /* ndef vms */ diff --git a/libguile/continuations.c b/libguile/continuations.c index 39785a528..80a2790b8 100644 --- a/libguile/continuations.c +++ b/libguile/continuations.c @@ -124,47 +124,30 @@ scm_make_continuation (int *first) continuation->offset = continuation->stack - src; memcpy (continuation->stack, src, sizeof (SCM_STACKITEM) * stack_size); -#ifdef __ia64__ - continuation->fresh = 1; - getcontext (&continuation->ctx); - if (continuation->fresh) + *first = !setjmp (continuation->jmpbuf); + if (*first) { +#ifdef __ia64__ continuation->backing_store_size = - (char *) scm_ia64_ar_bsp(&continuation->ctx) + (char *) scm_ia64_ar_bsp(&continuation->jmpbuf.ctx) - - (char *) scm_ia64_register_backing_store_base (); + (char *) thread->register_backing_store_base; continuation->backing_store = NULL; continuation->backing_store = scm_gc_malloc (continuation->backing_store_size, "continuation backing store"); memcpy (continuation->backing_store, - (void *) scm_ia64_register_backing_store_base (), + (void *) thread->register_backing_store_base, continuation->backing_store_size); - *first = 1; - continuation->fresh = 0; +#endif /* __ia64__ */ return cont; } else { SCM ret = continuation->throw_value; - *first = 0; continuation->throw_value = SCM_BOOL_F; return ret; } -#else /* !__ia64__ */ - if (setjmp (continuation->jmpbuf)) - { - SCM ret = continuation->throw_value; - *first = 0; - continuation->throw_value = SCM_BOOL_F; - return ret; - } - else - { - *first = 1; - return cont; - } -#endif /* !__ia64__ */ } #undef FUNC_NAME @@ -218,6 +201,9 @@ copy_stack (void *data) copy_stack_data *d = (copy_stack_data *)data; memcpy (d->dst, d->continuation->stack, sizeof (SCM_STACKITEM) * d->continuation->num_stack_items); +#ifdef __ia64__ + SCM_I_CURRENT_THREAD->pending_rbs_continuation = d->continuation; +#endif } static void @@ -235,16 +221,26 @@ copy_stack_and_call (scm_t_contregs *continuation, SCM val, scm_i_set_last_debug_frame (continuation->dframe); continuation->throw_value = val; -#ifdef __ia64__ - memcpy (scm_ia64_register_backing_store_base (), - continuation->backing_store, - continuation->backing_store_size); - setcontext (&continuation->ctx); -#else longjmp (continuation->jmpbuf, 1); -#endif } +#ifdef __ia64__ +void +scm_ia64_longjmp (jmp_buf *JB, int VAL) +{ + scm_i_thread *t = SCM_I_CURRENT_THREAD; + + if (t->pending_rbs_continuation) + { + memcpy (t->register_backing_store_base, + t->pending_rbs_continuation->backing_store, + t->pending_rbs_continuation->backing_store_size); + t->pending_rbs_continuation = NULL; + } + setcontext (&JB->ctx); +} +#endif + /* Call grow_stack until the stack space is large enough, then, as the current * stack frame might get overwritten, let copy_stack_and_call perform the * actual copying and continuation calling. diff --git a/libguile/continuations.h b/libguile/continuations.h index 0274c1b2d..f6fb96aa2 100644 --- a/libguile/continuations.h +++ b/libguile/continuations.h @@ -46,8 +46,6 @@ typedef struct jmp_buf jmpbuf; SCM dynenv; #ifdef __ia64__ - ucontext_t ctx; - int fresh; void *backing_store; unsigned long backing_store_size; #endif /* __ia64__ */ diff --git a/libguile/threads.c b/libguile/threads.c index 858a1eb3d..609fc9912 100644 --- a/libguile/threads.c +++ b/libguile/threads.c @@ -423,6 +423,22 @@ guilify_self_1 (SCM_STACKITEM *base) t->pending_asyncs = 1; t->last_debug_frame = NULL; t->base = base; +#ifdef __ia64__ + /* Calculate and store off the base of this thread's register + backing store (RBS). Unfortunately our implementation(s) of + scm_ia64_register_backing_store_base are only reliable for the + main thread. For other threads, therefore, find out the current + top of the RBS, and use that as a maximum. */ + t->register_backing_store_base = scm_ia64_register_backing_store_base (); + { + ucontext_t ctx; + void *bsp; + getcontext (&ctx); + bsp = scm_ia64_ar_bsp (&ctx); + if (t->register_backing_store_base > bsp) + t->register_backing_store_base = bsp; + } +#endif t->continuation_root = SCM_EOL; t->continuation_base = base; scm_i_pthread_cond_init (&t->sleep_cond, NULL); @@ -1350,7 +1366,7 @@ SCM_DEFINE (scm_broadcast_condition_variable, "broadcast-condition-variable", 1, scm_mark_locations ((SCM_STACKITEM *) &ctx.uc_mcontext, \ ((size_t) (sizeof (SCM_STACKITEM) - 1 + sizeof ctx.uc_mcontext) \ / sizeof (SCM_STACKITEM))); \ - bot = (SCM_STACKITEM *) scm_ia64_register_backing_store_base (); \ + bot = (SCM_STACKITEM *) SCM_I_CURRENT_THREAD->register_backing_store_base; \ top = (SCM_STACKITEM *) scm_ia64_ar_bsp (&ctx); \ scm_mark_locations (bot, top - bot); } while (0) #else @@ -1374,7 +1390,7 @@ scm_threads_mark_stacks (void) #else scm_mark_locations (t->top, t->base - t->top); #endif - scm_mark_locations ((SCM_STACKITEM *) t->regs, + scm_mark_locations ((SCM_STACKITEM *) &t->regs, ((size_t) sizeof(t->regs) / sizeof (SCM_STACKITEM))); } diff --git a/libguile/threads.h b/libguile/threads.h index 09939b0a4..d58a0fbee 100644 --- a/libguile/threads.h +++ b/libguile/threads.h @@ -28,6 +28,7 @@ #include "libguile/root.h" #include "libguile/iselect.h" #include "libguile/dynwind.h" +#include "libguile/continuations.h" #if SCM_USE_PTHREAD_THREADS #include "libguile/pthread-threads.h" @@ -107,6 +108,10 @@ typedef struct scm_i_thread { SCM_STACKITEM *base; SCM_STACKITEM *top; jmp_buf regs; +#ifdef __ia64__ + void *register_backing_store_base; + scm_t_contregs *pending_rbs_continuation; +#endif } scm_i_thread; diff --git a/libguile/throw.c b/libguile/throw.c index 1c254631c..119d0bd44 100644 --- a/libguile/throw.c +++ b/libguile/throw.c @@ -824,6 +824,12 @@ scm_ithrow (SCM key, SCM args, int noreturn SCM_UNUSED) /* Otherwise, it's some random piece of junk. */ else abort (); + +#ifdef __ia64__ + /* On IA64, we #define longjmp as setcontext, and GCC appears not to + know that that doesn't return. */ + return SCM_UNSPECIFIED; +#endif }