"Julian Graham" <[EMAIL PROTECTED]> writes: >> > Let me know if I've missed anything. >> >> I don't think so, and I plan to apply this very soon. I've found a >> reliable recipe for reproducing the critical section problem: if a >> scm_i_gc call is added to make_jmpbuf (), like this: > > > Excellent -- I'll let you know if I can think of a deterministic way > to reproduce that from user code.
Thanks. I've decided to give up on this for now, and just check in the fix. I was playing with code like the attached patch - which I think is already more effort than it's worth spending to be able to regressibly test this :-) - and then I found that even this doesn't work reliably. To be precise, it hangs every time when run under GDB, but not when run outside GDB. So I think the wise course is to accept that there are some things we can't write tests for.
Index: libguile/debug.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/debug.c,v retrieving revision 1.120.2.1 diff -u -r1.120.2.1 debug.c --- libguile/debug.c 12 Feb 2006 13:42:51 -0000 1.120.2.1 +++ libguile/debug.c 6 Feb 2008 23:52:02 -0000 @@ -523,6 +523,30 @@ +unsigned scm_forced_internals[1] = { 0 }; + +SCM_GLOBAL_SYMBOL (scm_sym_gc_in_make_jmpbuf, "gc-in-make_jmpbuf"); + +SCM_DEFINE (scm_force_internal, "force-internal", 1, 0, 0, + (SCM op), + "Force the next internal Guile operation @var{op} to occur (for test purposes only).") +#define FUNC_NAME s_scm_force_internal +{ + int op_index; + + if (scm_is_eq (op, scm_sym_gc_in_make_jmpbuf)) + op_index = SCM_FI_GC_IN_MAKE_JMPBUF; + else + SCM_WRONG_TYPE_ARG(1, op); + + scm_forced_internals[op_index] = 2; + + return SCM_UNSPECIFIED; +} +#undef FUNC_NAME + + + void scm_init_debug () { Index: libguile/debug.h =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/debug.h,v retrieving revision 1.58 diff -u -r1.58 debug.h --- libguile/debug.h 4 Nov 2005 21:20:24 -0000 1.58 +++ libguile/debug.h 6 Feb 2008 23:52:02 -0000 @@ -173,6 +173,12 @@ SCM_API SCM scm_debug_hang (SCM obj); #endif /*GUILE_DEBUG*/ +#define SCM_FI_GC_IN_MAKE_JMPBUF 0 +extern unsigned scm_forced_internals[]; +#define SCM_FORCE_INTERNAL(OP) ((scm_forced_internals[OP]) && !(--scm_forced_internals[OP])) + +SCM_API SCM scm_force_internal (SCM op); + #if SCM_ENABLE_DEPRECATED == 1 #define CHECK_ENTRY scm_check_entry_p Index: libguile/throw.c =================================================================== RCS file: /cvsroot/guile/guile/guile-core/libguile/throw.c,v retrieving revision 1.108.2.3 diff -u -r1.108.2.3 throw.c --- libguile/throw.c 2 Jun 2006 23:39:12 -0000 1.108.2.3 +++ libguile/throw.c 6 Feb 2008 23:52:02 -0000 @@ -73,6 +73,8 @@ SCM answer; SCM_CRITICAL_SECTION_START; { + if (SCM_FORCE_INTERNAL (SCM_FI_GC_IN_MAKE_JMPBUF)) + scm_i_gc ("test"); SCM_NEWSMOB2 (answer, tc16_jmpbuffer, 0, 0); SETJBJMPBUF(answer, (jmp_buf *)0); DEACTIVATEJB(answer); Index: test-suite/standalone/Makefile.am =================================================================== RCS file: /cvsroot/guile/guile/guile-core/test-suite/standalone/Makefile.am,v retrieving revision 1.13.2.7 diff -u -r1.13.2.7 Makefile.am --- test-suite/standalone/Makefile.am 1 Feb 2008 22:47:51 -0000 1.13.2.7 +++ test-suite/standalone/Makefile.am 6 Feb 2008 23:52:03 -0000 @@ -55,6 +55,9 @@ check_SCRIPTS += test-bad-identifiers TESTS += test-bad-identifiers +check_SCRIPTS += test-gc-in-make-jmpbuf +TESTS += test-gc-in-make-jmpbuf + # test-num2integral test_num2integral_SOURCES = test-num2integral.c test_num2integral_CFLAGS = ${test_cflags} Index: test-suite/standalone/test-gc-in-make-jmpbuf =================================================================== RCS file: test-suite/standalone/test-gc-in-make-jmpbuf diff -N test-suite/standalone/test-gc-in-make-jmpbuf --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ test-suite/standalone/test-gc-in-make-jmpbuf 6 Feb 2008 23:52:03 -0000 @@ -0,0 +1,10 @@ +#!/bin/sh +exec guile -s "$0" "$@" +!# + +(force-internal 'gc-in-make_jmpbuf) +(system* "sleep" "1") + +;; Local Variables: +;; mode: scheme +;; End:
> At any rate, let me pop a few frames off the stack. The two remaining > changes for the core features patch were providing a join_thread that > could indicate a timeout without throwing an SRFI-18 exception; and > providing a well-defined fat_mutex_lock that doesn't rely on the > SRFI-18 notion of mutex state. Two questions: > > * What would be an appropriate way for join_thread to indicate a > timeout? Given that it's a primitive that can be called from Guile, I > take it that the standard C approach of passing a pointer to a flag is > out of the question. Would it be good enough to have it return #f on > timeout (even if that leaves some amiguity about whether there was a > timeout or just a lack of a thread return value)? Is there a core > exception it could throw? How about if the core join-thread takes an optional timeout-val parameter, like SRFI-18 thread-join! ? If no timeout-val was supplied, and the join timed out, the core join-thread would return #f. The #f would indeed be ambiguous, but any given caller can eliminate the ambiguity if they choose to by specifying a timeout-val. Note that thread-join! can map onto this, in the case where _it_ gets no timeout-val, by constructing a unique object such as (list 'timeout) and passing this as the timeout-val to the core join-thread. > * What should be the behavior of fat_mutex_lock when attempting to > lock an abandoned mutex -- in your earlier email, you seemed amenable > to the parts of SRFI-18 that shore up some of the poorly-defined > threading behavior in core threads. So should locking an abandoned > mutex be an error? If so, what kind? Or should locking an abandoned > mutex not be an error at all unless you do it using the SRFI-18 API? I'll get back to you on this one tomorrow! Regards, Neil