summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiroslav Lichvar <mlichvar@fedoraproject.org>2008-05-13 11:47:06 +0000
committerMiroslav Lichvar <mlichvar@fedoraproject.org>2008-05-13 11:47:06 +0000
commit21d483d14e2aea67e811cf83539a623bf5b44cc2 (patch)
tree8c9815cf754005b412d378263fd155dabab180dc
parent07c1ec826d57d5b8fd820b668377fe7f046e8992 (diff)
downloadguile-21d483d14e2aea67e811cf83539a623bf5b44cc2.tar.gz
guile-21d483d14e2aea67e811cf83539a623bf5b44cc2.tar.xz
guile-21d483d14e2aea67e811cf83539a623bf5b44cc2.zip
- fix continuations on ia64 - remove umask setting from scriptlet, rpm sets it now
-rw-r--r--.cvsignore2
-rw-r--r--guile-1.8.5-conts.patch474
-rw-r--r--guile.spec15
-rw-r--r--sources2
4 files changed, 487 insertions, 6 deletions
diff --git a/.cvsignore b/.cvsignore
index 14ac502..861fac3 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -1 +1 @@
-guile-1.8.4.tar.gz
+guile-1.8.5.tar.gz
diff --git a/guile-1.8.5-conts.patch b/guile-1.8.5-conts.patch
new file mode 100644
index 0000000..66e979c
--- /dev/null
+++ b/guile-1.8.5-conts.patch
@@ -0,0 +1,474 @@
+From 78aa4a8850396801f2e5515565d051b45b4f15b5 Mon Sep 17 00:00:00 2001
+From: Neil Jerram <neil@ossau.uklinux.net>
+Date: Thu, 8 May 2008 00:29:53 +0100
+Subject: [PATCH] Fix continuation problems on IA64.
+
+* Specific problems in IA64 make check
+
+** test-unwind
+
+Representation of the relevant dynamic context:
+
+ non-rewindable
+ catch frame make cont.
+ o----o-----a----------b-------------c
+ \
+ \ call cont.
+ o-----o-----------d
+
+A continuation is captured at (c), with a non-rewindable frame in the
+dynamic context at (b). If a rewind through that frame was attempted,
+Guile would throw to the catch at (a). Then the context unwinds back
+past (a), then winds forwards again, and the captured continuation is
+called at (d).
+
+We should end up at the catch at (a). On ia64, we get an "illegal
+instruction".
+
+The problem is that Guile does not restore the ia64 register backing
+store (RBS) stack (which is saved off when the continuation is
+captured) until all the unwinding and rewinding is done. Therefore,
+when the rewind code (scm_i_dowinds) hits the non-rewindable frame at
+(b), the RBS stack hasn't yet been restored. The throw finds the
+jmp_buf (for the catch at (a)) correctly from the dynamic context, and
+jumps back to (a), but the RBS stack is invalid, hence the illegal
+instruction.
+
+This could be fixed by restoring the RBS stack earlier, at the same
+point (copy_stack) where the normal stack is restored. But that
+causes a problem in the next test...
+
+** continuations.test
+
+The dynamic context diagram for this case is similar:
+
+ non-rewindable
+ catch frame make cont.
+ a----x-----o----------b-------------c
+ \
+ \ call cont.
+ o-------d
+
+The only significant difference is that the catch point (a) is
+upstream of where the dynamic context forks. This means that the RBS
+stack at (d) already contains the correct RBS contents for throwing
+back to (a), so it doesn't matter whether the RBS stack that was saved
+off with the continuation gets restored.
+
+This test passes with the Guile 1.8.4 code, but fails (with an
+"illegal instruction") when the code is changed to restore the RBS
+stack earlier as described above.
+
+The problem now is that the RBS stack is being restored _too_ early;
+specifically when there is still stuff to do that relies on the old
+RBS contents. When a continuation is called, the sequence of relevant
+events is:
+
+ (1) Grow the (normal) stack until it is bigger than the (normal)
+ stack saved off in the continuation. (scm_dynthrow, grow_stack)
+
+ (2) scm_i_dowinds calls itself recursively, such that
+
+ (2.1) for each rewind (from (x) to (c)) that will be needed,
+ another frame is added to the stack (both normal and RBS),
+ with local variables specifying the required rewind; the
+ rewinds don't actually happen yet, they will happen when
+ the stack unwinds again through these frames
+
+ (2.2) required unwinds - back from where the continuation was
+ called (d) to the fork point (x) - are done immediately.
+
+ (3) The normal (i.e. non-RBS) stack that was stored in the
+ continuation is restored (i.e. copied on top of the actual
+ stack).
+
+ Note that this doesn't overwrite the frames that were added in
+ (2.1), because the growth in (1) ensures that the added frames
+ are beyond the end of the restored stack.
+
+ (4) ? Restore the RBS stack here too ?
+
+ (5) Return (from copy_stack) through the (2.1) frames, which means
+ that the rewinds now happen.
+
+ (6) setcontext (or longjmp) to the context (c) where the
+ continuation was captured.
+
+The trouble is that step (1) does not create space in the RBS stack in
+the same kind of way that it does for the normal stack. Therefore, if
+the saved (in the continuation) RBS stack is big enough, it can
+overwrite the RBS of the (2.1) frames that still need to complete.
+This causes an illegal instruction when we return through those frames
+and try to perform the rewinds.
+
+* Fix
+
+The key to the fix is that the saved RBS stack only needs to be
+restored at some point before the next setcontext call, and that doing
+it as close to the setcontext call as possible will avoid bad
+interactions with the pre-setcontext stack. Therefore we do the
+restoration at the last possible point, immediately before the next
+setcontext call.
+
+The situation is complicated by there being two ways that the next
+setcontext call can happen.
+
+ - If the unwinding and rewinding is all successful, the next
+ setcontext will be the one from step (6) above. This is the
+ "normal" continuation invocation case.
+
+ - If one of the rewinds throws an error, the next setcontext will
+ come from the throw implementation code. (And the one in step (6)
+ will never happen.) This is the rewind error case.
+
+In the rewind error case, the code calling setcontext knows nothing
+about the continuation. So to cover both cases, we:
+
+ - copy (in step (4) above) the address and length of the
+ continuation's saved RBS stack to the current thread state
+ (SCM_I_CURRENT_THREAD)
+
+ - modify all setcontext callers so that they check the current
+ thread state for a saved RBS stack, and restore it if so before
+ calling setcontext.
+
+* Notes
+
+** I think rewinders cannot rely on using any stack data
+
+Unless it can be guaranteed that the data won't go into a register.
+I'm not 100% sure about this, but I think it follows from the fact
+that the RBS stack is not restored until after the rewinds have
+happened.
+
+Note that this isn't a regression caused by the current fix. In Guile
+1.8.4, the RBS stack was restored _after_ the rewinds, and this is
+still the case now.
+
+** Most setcontext calls for `throw' don't need to change the RBS stack
+
+In the absence of continuation invocation, the setcontext call in the
+throw implementation code always sets context to a place higher up the
+same stack (both normal and RBS), hence no stack restoration is
+needed.
+
+* Other changes
+
+** Using setcontext for all non-local jumps (for __ia64__)
+
+Along the way, I read a claim somewhere that setcontext was more
+reliable than longjmp, in cases where the stack has been manipulated.
+
+I don't now have any reason to believe this, but it seems reasonable
+anyway to leave the __ia64__ code using getcontext/setcontext, instead
+of setjmp/longjmp.
+
+(I think the only possible argument against this would be performance -
+if getcontext was significantly slower than setjmp. It that proves to
+be the case, we should revisit this.)
+
+** Capping RBS base for non-main threads
+
+Somewhere else along the way, I hit a problem in GC, involving the RBS
+stack of a non-main thread. The problem was, in
+SCM_MARK_BACKING_STORE, that scm_ia64_register_backing_store_base was
+returning a value that was massively greater than the value of
+scm_ia64_ar_bsp, leading to a seg fault. This is because the
+implementation of scm_ia64_register_backing_store_base is only valid
+for the main thread. I couldn't find a neat way of getting the true
+RBS base of a non-main thread, but one idea is simply to call
+scm_ia64_ar_bsp when guilifying a thread, and use the value returned
+as an upper bound for that thread's RBS base. (Note that the RBS
+stack grows upwards.)
+
+(Were it not for scm_init_guile, we could be much more definitive
+about this. We could take the value of scm_ia64_ar_bsp as a
+definitive base address for the part of the RBS stack that Guile cares
+about. We could also then discard
+scm_ia64_register_backing_store_base.)
+---
+ libguile/ChangeLog | 35 +++++++++++++++++++++++++++
+ libguile/__scm.h | 18 +++++++++++++-
+ libguile/continuations.c | 58 +++++++++++++++++++++------------------------
+ libguile/continuations.h | 2 -
+ libguile/threads.c | 20 ++++++++++++++-
+ libguile/threads.h | 5 ++++
+ libguile/throw.c | 6 ++++
+ 7 files changed, 108 insertions(+), 36 deletions(-)
+
+diff --git a/libguile/ChangeLog b/libguile/ChangeLog
+index 6c25443..dec6dcd 100644
+--- a/libguile/ChangeLog
++++ b/libguile/ChangeLog
+@@ -1,3 +1,38 @@
++2008-05-08 Neil Jerram <neil@ossau.uklinux.net>
++
++ * 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 <ludo@gnu.org>
+
+ * numbers.c (scm_from_complex_double): Mark as `SCM_UNUSED'.
+diff --git a/libguile/__scm.h b/libguile/__scm.h
+index 3d6d9a7..b198f9d 100644
+--- a/libguile/__scm.h
++++ b/libguile/__scm.h
+@@ -402,7 +402,23 @@
+ # define setjmp setjump
+ # define longjmp longjump
+ # else /* ndef _CRAY1 */
+-# include <setjmp.h>
++# if defined (__ia64__)
++/* For IA64, emulate the setjmp API using getcontext. */
++# include <signal.h>
++# include <ucontext.h>
++ 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 <setjmp.h>
++# endif /* ndef __ia64__ */
+ # endif /* ndef _CRAY1 */
+ #endif /* ndef vms */
+
+diff --git a/libguile/continuations.c b/libguile/continuations.c
+index 39785a5..80a2790 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 0274c1b..f6fb96a 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 858a1eb..609fc99 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 09939b0..d58a0fb 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 1c25463..119d0bd 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
+ }
+
+
+--
+1.5.4.1
+
diff --git a/guile.spec b/guile.spec
index fafd521..5601544 100644
--- a/guile.spec
+++ b/guile.spec
@@ -1,12 +1,13 @@
Summary: A GNU implementation of Scheme for application extensibility
Name: guile
%define mver 1.8
-Version: 1.8.4
+Version: 1.8.5
Release: 1%{?dist}
Source: ftp://ftp.gnu.org/pub/gnu/guile/guile-%{version}.tar.gz
URL: http://www.gnu.org/software/guile/
Patch1: guile-1.8.4-multilib.patch
Patch2: guile-1.8.4-testsuite.patch
+Patch3: guile-1.8.5-conts.patch
Patch4: guile-1.8.1-deplibs.patch
License: GPLv2+ and LGPLv2+
Group: Development/Languages
@@ -30,6 +31,7 @@ that you are developing.
Summary: Libraries and header files for the GUILE extensibility library
Group: Development/Libraries
Requires: guile = %{epoch}:%{version} gmp-devel
+Requires: pkgconfig
%description devel
The guile-devel package includes the libraries, header files, etc.,
@@ -44,6 +46,7 @@ install the guile package.
%setup -q
%patch1 -p1 -b .multilib
%patch2 -p1 -b .testsuite
+%patch3 -p1 -b .conts
%patch4 -p1 -b .deplibs
%build
@@ -108,7 +111,6 @@ rm -f %{_datadir}/guile/site/slib{,cat}
ln -sfT ../../slib %{_datadir}/guile/%{mver}/slib
rm -f %{_datadir}/guile/%{mver}/slibcat
export SCHEME_LIBRARY_PATH=%{_datadir}/slib/
-umask 0022
# Build SLIB catalog
for pre in \
@@ -129,8 +131,7 @@ fi
%files
%defattr(-,root,root,-)
-%doc AUTHORS COPYING* ChangeLog HACKING NEWS.bz2 README
-%doc SNAPSHOTS ANON-CVS THANKS
+%doc AUTHORS COPYING* ChangeLog HACKING NEWS.bz2 README THANKS
%{_bindir}/guile
%{_bindir}/guile-tools
%{_libdir}/libguile*.so.*
@@ -155,11 +156,17 @@ fi
%{_bindir}/guile-snarf
%{_datadir}/aclocal/*
%{_libdir}/libguile.so
+%{_libdir}/pkgconfig/*.pc
%{_includedir}/guile
%{_includedir}/libguile
%{_includedir}/libguile.h
%changelog
+* Tue May 13 2008 Miroslav Lichvar <mlichvar@redhat.com> - 5:1.8.5-1
+- update to 1.8.5
+- fix continuations on ia64
+- remove umask setting from scriptlet, rpm sets it now
+
* Thu Feb 21 2008 Miroslav Lichvar <mlichvar@redhat.com> - 5:1.8.4-1
- update to 1.8.4
- add %%check
diff --git a/sources b/sources
index 06536c8..3291d76 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-aacc6a384af88a85574717a9221f5c6e guile-1.8.4.tar.gz
+a3f8216544509a74a4441f689a0410d2 guile-1.8.5.tar.gz