GNU bug report logs - #32367
2.2.4 hangs when a script uses a module that calls sigaction

Previous Next

Package: guile;

Reported by: Derek Upham <sand <at> blarg.net>

Date: Sun, 5 Aug 2018 00:48:01 UTC

Severity: normal

Found in version 2.2.4

To reply to this bug, email your comments to 32367 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-guile <at> gnu.org:
bug#32367; Package guile. (Sun, 05 Aug 2018 00:48:01 GMT) Full text and rfc822 format available.

Acknowledgement sent to Derek Upham <sand <at> blarg.net>:
New bug report received and forwarded. Copy sent to bug-guile <at> gnu.org. (Sun, 05 Aug 2018 00:48:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Derek Upham <sand <at> blarg.net>
To: bug-guile <at> gnu.org
Subject: 2.2.4 hangs when a script uses a module that calls sigaction
Date: Sat, 04 Aug 2018 17:47:09 -0700
This is with guile-2.2 (2.2.4+1-1) and guile-2.2-libs (2.2.4+1-1) on Debian unstable, for the amd64 architecture.

Create the following one-line script file:

  (use-modules (scsh))

Call it (for example) “foo”.

Create a file named “scsh.scm” in a location where the above “use-modules” form will find it.  I use “/usr/share/guile/site/scsh.scm”.  In “scsh.scm”, put:

  (define-module (scsh))

  (display "setting SIGCHILD to SIG_DFL...")
  (newline)
  (sigaction SIGCHLD SIG_DFL)
  (display "setting SIGCHILD to SIG_DFL...done")
  (newline)

Invoke guile as follows:

  /usr/bin/guile < foo

This is reading commands from stdin.  You should see the expected output:

  GNU Guile 2.2.4
  Copyright (C) 1995-2017 Free Software Foundation, Inc.

  Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
  This program is free software, and you are welcome to redistribute it
  under certain conditions; type `,show c' for details.

  Enter `,help' for help.
  setting SIGCHILD to SIG_DFL...
  setting SIGCHILD to SIG_DFL...done

and a command-line prompt.  Invoke guile as a script:

  /usr/bin/guile -s foo

I see just the following:

  setting SIGCHILD to SIG_DFL...

Guile hangs at this point.

Reverting Guile to 2.2.3 from the Debian testing distribution (guile-2.2-dev_2.2.3+1-3+b1_amd64.deb, guile-2.2-doc_2.2.3+1-3_all.deb, guile-2.2-libs_2.2.3+1-3+b1_amd64.deb, guile-2.2_2.2.3+1-3+b1_amd64.deb) fixes the problem:

  % /usr/bin/guile -s foo 
  setting SIGCHILD to SIG_DFL...
  setting SIGCHILD to SIG_DFL...done

Note that moving the sigaction call from “scsh.scm” to “foo” does not trigger the problem.  It only happens when a script uses a module that calls sigaction.




Information forwarded to bug-guile <at> gnu.org:
bug#32367; Package guile. (Mon, 06 Aug 2018 10:15:02 GMT) Full text and rfc822 format available.

Message #8 received at 32367 <at> debbugs.gnu.org (full text, mbox):

From: Göran Weinholt <goran <at> weinholt.se>
To: Derek Upham <sand <at> blarg.net>
Cc: 32367 <at> debbugs.gnu.org
Subject: Re: bug#32367: 2.2.4 hangs when a script uses a module that calls
 sigaction
Date: Mon, 06 Aug 2018 11:54:31 +0200
Derek Upham <sand <at> blarg.net> writes:

> This is with guile-2.2 (2.2.4+1-1) and guile-2.2-libs (2.2.4+1-1) on
> Debian unstable, for the amd64 architecture.
...
>
>   % /usr/bin/guile -s foo 
>   setting SIGCHILD to SIG_DFL...
>   setting SIGCHILD to SIG_DFL...done

Here's a backtrace:

GNU gdb (Debian 8.1-4) 8.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/bin/guile...Reading symbols from /usr/lib/debug/.build-id/e3/f08708458c69f9adf32d6cafd6d9ca7a8410ea.debug...done.
done.
Attaching to program: /usr/bin/guile, process 29610
[New LWP 29611]
[New LWP 29612]
[New LWP 29613]
[New LWP 29614]
[New LWP 29615]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
s0x00007fb48c8f0e6c in futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x559a855ebe60) at ../sysdeps/unix/sysv/linux/futex-internal.h:88
88	  int err = lll_futex_timed_wait (futex_word, expected, NULL, private);
(gdb) set pagination off
(gdb) thread apply all bt

Thread 6 (Thread 0x7fb48891c700 (LWP 29615)):
#0  0x00007fb48c8f0e6c in futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x559a855ebae0) at ../sysdeps/unix/sysv/linux/futex-internal.h:88
#1  __pthread_cond_wait_common (abstime=0x0, mutex=0x559a8571ff80, cond=0x559a855ebab8) at pthread_cond_wait.c:502
#2  __pthread_cond_wait (cond=cond <at> entry=0x559a855ebab8, mutex=mutex <at> entry=0x559a8571ff80) at pthread_cond_wait.c:655
#3  0x00007fb48cb86bf5 in scm_pthread_cond_wait (cond=cond <at> entry=0x559a855ebab8, mutex=mutex <at> entry=0x559a8571ff80) at threads.c:1621
#4  0x00007fb48cb86dbb in block_self (queue=0x559a8571c2c0, mutex=mutex <at> entry=0x559a8571ff80, waittime=waittime <at> entry=0x0) at threads.c:316
#5  0x00007fb48cb86f6f in lock_mutex (current_thread=0x559a855eba80, waittime=0x0, m=0x559a8571ff80, kind=SCM_MUTEX_RECURSIVE) at threads.c:1037
#6  scm_timed_lock_mutex (mutex=0x559a8571c2b0, timeout=<optimized out>) at threads.c:1101
#7  0x00007fb48cb9353f in vm_regular_engine () at vm-engine.c:786
#8  0x00007fb48cb98d8f in scm_call_n () at vm.c:1257
#9  0x00007fb48cb1ab0f in scm_call_3 (proc=<optimized out>, arg1=arg1 <at> entry=0x7fb489ee9050, arg2=arg2 <at> entry=0x559a856abf40, arg3=arg3 <at> entry=0x4) at eval.c:501
#10 0x00007fb48cb3d950 in scm_private_variable (module_name=0x7fb489ee9050, name=0x559a8565eb20) at modules.c:674
#11 0x00007fb48cb3da51 in scm_private_lookup (module_name=0x7fb489ee9050, name=0x559a8565eb20) at modules.c:717
#12 0x00007fb48cb97fd1 in vm_regular_engine () at vm-engine.c:2066
#13 0x00007fb48cb98d8f in scm_call_n () at vm.c:1257
#14 0x00007fb48cb86076 in really_launch (d=0x559a8592c6e0) at threads.c:794
#15 0x00007fb48cb14dfa in c_body (d=0x7fb48891be40) at continuations.c:422
#16 0x00007fb48cb9353f in vm_regular_engine () at vm-engine.c:786
#17 0x00007fb48cb98d8f in scm_call_n () at vm.c:1257
#18 0x00007fb48cb87784 in catch (tag=tag <at> entry=0x404, thunk=0x559a85937720, handler=0x559a859376e0, pre_unwind_handler=0x559a859376a0) at throw.c:137
#19 0x00007fb48cb87aa5 in scm_catch_with_pre_unwind_handler (key=key <at> entry=0x404, thunk=<optimized out>, handler=<optimized out>, pre_unwind_handler=<optimized out>) at throw.c:254
#20 0x00007fb48cb87c6f in scm_c_catch (tag=tag <at> entry=0x404, body=body <at> entry=0x7fb48cb14df0 <c_body>, body_data=body_data <at> entry=0x7fb48891be40, handler=handler <at> entry=0x7fb48cb15080 <c_handler>, handler_data=handler_data <at> entry=0x7fb48891be40, pre_unwind_handler=pre_unwind_handler <at> entry=0x7fb48cb14ed0 <pre_unwind_handler>, pre_unwind_handler_data=0x559a85689a20) at throw.c:377
#21 0x00007fb48cb153e0 in scm_i_with_continuation_barrier (body=body <at> entry=0x7fb48cb14df0 <c_body>, body_data=body_data <at> entry=0x7fb48891be40, handler=handler <at> entry=0x7fb48cb15080 <c_handler>, handler_data=handler_data <at> entry=0x7fb48891be40, pre_unwind_handler=pre_unwind_handler <at> entry=0x7fb48cb14ed0 <pre_unwind_handler>, pre_unwind_handler_data=0x559a85689a20) at continuations.c:360
#22 0x00007fb48cb15475 in scm_c_with_continuation_barrier (func=<optimized out>, data=<optimized out>) at continuations.c:456
#23 0x00007fb48cb86396 in with_guile (base=0x7fb48891bea8, data=0x7fb48891bed0) at threads.c:661
#24 0x00007fb48c4d04e8 in GC_call_with_stack_base () from /usr/lib/x86_64-linux-gnu/libgc.so.1
#25 0x00007fb48cb8589d in scm_i_with_guile (dynamic_state=<optimized out>, data=0x559a8592c6e0, func=0x7fb48cb86000 <really_launch>) at threads.c:704
#26 launch_thread (d=0x559a8592c6e0) at threads.c:803
#27 0x00007fb48c8eaf2a in start_thread (arg=0x7fb48891c700) at pthread_create.c:463
#28 0x00007fb48c81dedf in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Thread 5 (Thread 0x7fb48999b700 (LWP 29614)):
#0  0x00007fb48c8f4394 in __libc_read (fd=5, buf=buf <at> entry=0x7fb48999aa40, nbytes=nbytes <at> entry=1) at ../sysdeps/unix/sysv/linux/read.c:27
#1  0x00007fb48cb240d7 in read (__nbytes=1, __buf=0x7fb48999aa40, __fd=<optimized out>) at /usr/include/x86_64-linux-gnu/bits/unistd.h:44
#2  read_finalization_pipe_data (data=0x7fb48999aa40) at finalizers.c:199
#3  0x00007fb48c4d60c3 in GC_do_blocking_inner () from /usr/lib/x86_64-linux-gnu/libgc.so.1
#4  0x00007fb48c4ca9ce in GC_with_callee_saves_pushed () from /usr/lib/x86_64-linux-gnu/libgc.so.1
#5  0x00007fb48c4d051c in GC_do_blocking () from /usr/lib/x86_64-linux-gnu/libgc.so.1
#6  0x00007fb48cb8677a in scm_without_guile (func=0x7fb48cb240c0 <read_finalization_pipe_data>, data=0x7fb48999aa40) at threads.c:722
#7  0x00007fb48cb2448b in finalization_thread_proc (unused=<optimized out>) at finalizers.c:212
#8  0x00007fb48cb14dfa in c_body (d=0x7fb48999ae40) at continuations.c:422
#9  0x00007fb48cb9353f in vm_regular_engine () at vm-engine.c:786
#10 0x00007fb48cb98d8f in scm_call_n () at vm.c:1257
#11 0x00007fb48cb87784 in catch (tag=tag <at> entry=0x404, thunk=0x559a85619860, handler=0x559a85619840, pre_unwind_handler=0x559a856197c0) at throw.c:137
#12 0x00007fb48cb87aa5 in scm_catch_with_pre_unwind_handler (key=key <at> entry=0x404, thunk=<optimized out>, handler=<optimized out>, pre_unwind_handler=<optimized out>) at throw.c:254
#13 0x00007fb48cb87c6f in scm_c_catch (tag=tag <at> entry=0x404, body=body <at> entry=0x7fb48cb14df0 <c_body>, body_data=body_data <at> entry=0x7fb48999ae40, handler=handler <at> entry=0x7fb48cb15080 <c_handler>, handler_data=handler_data <at> entry=0x7fb48999ae40, pre_unwind_handler=pre_unwind_handler <at> entry=0x7fb48cb14ed0 <pre_unwind_handler>, pre_unwind_handler_data=0x559a85689a20) at throw.c:377
#14 0x00007fb48cb153e0 in scm_i_with_continuation_barrier (body=body <at> entry=0x7fb48cb14df0 <c_body>, body_data=body_data <at> entry=0x7fb48999ae40, handler=handler <at> entry=0x7fb48cb15080 <c_handler>, handler_data=handler_data <at> entry=0x7fb48999ae40, pre_unwind_handler=pre_unwind_handler <at> entry=0x7fb48cb14ed0 <pre_unwind_handler>, pre_unwind_handler_data=0x559a85689a20) at continuations.c:360
#15 0x00007fb48cb15475 in scm_c_with_continuation_barrier (func=<optimized out>, data=<optimized out>) at continuations.c:456
#16 0x00007fb48cb86396 in with_guile (base=0x7fb48999aea8, data=0x7fb48999aed0) at threads.c:661
#17 0x00007fb48c4d04e8 in GC_call_with_stack_base () from /usr/lib/x86_64-linux-gnu/libgc.so.1
#18 0x00007fb48cb86728 in scm_i_with_guile (dynamic_state=<optimized out>, data=<optimized out>, func=<optimized out>) at threads.c:704
#19 scm_with_guile (func=<optimized out>, data=<optimized out>) at threads.c:710
#20 0x00007fb48c8eaf2a in start_thread (arg=0x7fb48999b700) at pthread_create.c:463
#21 0x00007fb48c81dedf in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Thread 4 (Thread 0x7fb48a83d700 (LWP 29613)):
#0  0x00007fb48c8f0e6c in futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x7fb48c6f4208) at ../sysdeps/unix/sysv/linux/futex-internal.h:88
#1  __pthread_cond_wait_common (abstime=0x0, mutex=0x7fb48c6f4260, cond=0x7fb48c6f41e0) at pthread_cond_wait.c:502
#2  __pthread_cond_wait (cond=0x7fb48c6f41e0, mutex=0x7fb48c6f4260) at pthread_cond_wait.c:655
#3  0x00007fb48c4d6de7 in GC_wait_marker () from /usr/lib/x86_64-linux-gnu/libgc.so.1
#4  0x00007fb48c4cd6da in GC_help_marker () from /usr/lib/x86_64-linux-gnu/libgc.so.1
#5  0x00007fb48c4d54bc in GC_mark_thread () from /usr/lib/x86_64-linux-gnu/libgc.so.1
#6  0x00007fb48c8eaf2a in start_thread (arg=0x7fb48a83d700) at pthread_create.c:463
#7  0x00007fb48c81dedf in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Thread 3 (Thread 0x7fb48b03e700 (LWP 29612)):
#0  0x00007fb48c8f0e6c in futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x7fb48c6f4208) at ../sysdeps/unix/sysv/linux/futex-internal.h:88
#1  __pthread_cond_wait_common (abstime=0x0, mutex=0x7fb48c6f4260, cond=0x7fb48c6f41e0) at pthread_cond_wait.c:502
#2  __pthread_cond_wait (cond=0x7fb48c6f41e0, mutex=0x7fb48c6f4260) at pthread_cond_wait.c:655
#3  0x00007fb48c4d6de7 in GC_wait_marker () from /usr/lib/x86_64-linux-gnu/libgc.so.1
#4  0x00007fb48c4cd6da in GC_help_marker () from /usr/lib/x86_64-linux-gnu/libgc.so.1
#5  0x00007fb48c4d54bc in GC_mark_thread () from /usr/lib/x86_64-linux-gnu/libgc.so.1
#6  0x00007fb48c8eaf2a in start_thread (arg=0x7fb48b03e700) at pthread_create.c:463
#7  0x00007fb48c81dedf in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Thread 2 (Thread 0x7fb48b83f700 (LWP 29611)):
#0  0x00007fb48c8f0e6c in futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x7fb48c6f4208) at ../sysdeps/unix/sysv/linux/futex-internal.h:88
#1  __pthread_cond_wait_common (abstime=0x0, mutex=0x7fb48c6f4260, cond=0x7fb48c6f41e0) at pthread_cond_wait.c:502
#2  __pthread_cond_wait (cond=0x7fb48c6f41e0, mutex=0x7fb48c6f4260) at pthread_cond_wait.c:655
#3  0x00007fb48c4d6de7 in GC_wait_marker () from /usr/lib/x86_64-linux-gnu/libgc.so.1
#4  0x00007fb48c4cd6da in GC_help_marker () from /usr/lib/x86_64-linux-gnu/libgc.so.1
#5  0x00007fb48c4d54bc in GC_mark_thread () from /usr/lib/x86_64-linux-gnu/libgc.so.1
#6  0x00007fb48c8eaf2a in start_thread (arg=0x7fb48b83f700) at pthread_create.c:463
#7  0x00007fb48c81dedf in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Thread 1 (Thread 0x7fb48bc8e740 (LWP 29610)):
#0  0x00007fb48c8f0e6c in futex_wait_cancelable (private=<optimized out>, expected=0, futex_word=0x559a855ebe60) at ../sysdeps/unix/sysv/linux/futex-internal.h:88
#1  __pthread_cond_wait_common (abstime=0x0, mutex=0x559a856e7f00, cond=0x559a855ebe38) at pthread_cond_wait.c:502
#2  __pthread_cond_wait (cond=cond <at> entry=0x559a855ebe38, mutex=mutex <at> entry=0x559a856e7f00) at pthread_cond_wait.c:655
#3  0x00007fb48cb86bf5 in scm_pthread_cond_wait (cond=cond <at> entry=0x559a855ebe38, mutex=mutex <at> entry=0x559a856e7f00) at threads.c:1621
#4  0x00007fb48cb86dbb in block_self (queue=0x559a8578f980, mutex=mutex <at> entry=0x559a856e7f00, waittime=waittime <at> entry=0x0) at threads.c:316
#5  0x00007fb48cb872cd in timed_wait (c=0x559a85757630, current_thread=0x559a855ebe00, current_thread=0x559a855ebe00, waittime=0x0, m=0x559a856e7f00, kind=SCM_MUTEX_STANDARD) at threads.c:1347
#6  scm_timed_wait_condition_variable (cond=0x559a8578f990, mutex=0x559a8578f960, timeout=0x904) at threads.c:1440
#7  0x00007fb48cb9353f in vm_regular_engine () at vm-engine.c:786
#8  0x00007fb48cb98d8f in scm_call_n () at vm.c:1257
#9  0x00007fb48cb1aaea in scm_call_2 (proc=<optimized out>, arg1=<optimized out>, arg2=<optimized out>) at eval.c:494
#10 0x00007fb48cb867c5 in scm_call_with_new_thread (thunk=<optimized out>, handler=<optimized out>) at threads.c:746
#11 0x00007fb48cb86816 in scm_spawn_thread (body=body <at> entry=0x7fb48cb66380 <signal_delivery_thread>, body_data=body_data <at> entry=0x0, handler=<optimized out>, handler_data=handler_data <at> entry=0x7fb48cbb63c5) at threads.c:844
#12 0x00007fb48cb66351 in start_signal_delivery_thread () at scmsigs.c:207
#13 0x00007fb48c8f2827 in __pthread_once_slow (once_control=0x7fb48cbf5ac8 <once>, init_routine=0x7fb48cb66310 <start_signal_delivery_thread>) at pthread_once.c:116
#14 0x00007fb48c8f28e5 in __GI___pthread_once (once_control=once_control <at> entry=0x7fb48cbf5ac8 <once>, init_routine=init_routine <at> entry=0x7fb48cb66310 <start_signal_delivery_thread>) at pthread_once.c:143
#15 0x00007fb48cb6668f in scm_i_ensure_signal_delivery_thread () at scmsigs.c:332
#16 scm_sigaction_for_thread (signum=<optimized out>, handler=0x2, flags=<optimized out>, thread=0x559a85622e90) at scmsigs.c:332
#17 0x00007fb48cb9353f in vm_regular_engine () at vm-engine.c:786
#18 0x00007fb48cb98d8f in scm_call_n () at vm.c:1257
#19 0x00007fb48cb38968 in scm_primitive_load_path (args=<optimized out>) at load.c:1248
#20 0x00007fb48cb9353f in vm_regular_engine () at vm-engine.c:786
#21 0x00007fb48cb98d8f in scm_call_n () at vm.c:1257
#22 0x00007fb48cb1bc07 in scm_primitive_eval (exp=<optimized out>, exp <at> entry=0x559a85735280) at eval.c:662
#23 0x00007fb48cb1bc63 in scm_eval (exp=0x559a85735280, module_or_state=module_or_state <at> entry=0x559a8571b140) at eval.c:696
#24 0x00007fb48cb67750 in scm_shell (argc=3, argv=0x7fff44ec9708) at script.c:454
#25 0x00007fb48cb3250d in invoke_main_func (body_data=0x7fff44ec95b0) at init.c:340
#26 0x00007fb48cb14dfa in c_body (d=0x7fff44ec94f0) at continuations.c:422
#27 0x00007fb48cb9353f in vm_regular_engine () at vm-engine.c:786
#28 0x00007fb48cb98d8f in scm_call_n () at vm.c:1257
#29 0x00007fb48cb87784 in catch (tag=tag <at> entry=0x404, thunk=0x559a85687140, handler=0x559a856870e0, pre_unwind_handler=0x559a856870c0) at throw.c:137
#30 0x00007fb48cb87aa5 in scm_catch_with_pre_unwind_handler (key=key <at> entry=0x404, thunk=<optimized out>, handler=<optimized out>, pre_unwind_handler=<optimized out>) at throw.c:254
#31 0x00007fb48cb87c6f in scm_c_catch (tag=tag <at> entry=0x404, body=body <at> entry=0x7fb48cb14df0 <c_body>, body_data=body_data <at> entry=0x7fff44ec94f0, handler=handler <at> entry=0x7fb48cb15080 <c_handler>, handler_data=handler_data <at> entry=0x7fff44ec94f0, pre_unwind_handler=pre_unwind_handler <at> entry=0x7fb48cb14ed0 <pre_unwind_handler>, pre_unwind_handler_data=0x559a85689a20) at throw.c:377
#32 0x00007fb48cb153e0 in scm_i_with_continuation_barrier (body=body <at> entry=0x7fb48cb14df0 <c_body>, body_data=body_data <at> entry=0x7fff44ec94f0, handler=handler <at> entry=0x7fb48cb15080 <c_handler>, handler_data=handler_data <at> entry=0x7fff44ec94f0, pre_unwind_handler=pre_unwind_handler <at> entry=0x7fb48cb14ed0 <pre_unwind_handler>, pre_unwind_handler_data=0x559a85689a20) at continuations.c:360
#33 0x00007fb48cb15475 in scm_c_with_continuation_barrier (func=<optimized out>, data=<optimized out>) at continuations.c:456
#34 0x00007fb48cb86396 in with_guile (base=0x7fff44ec9558, data=0x7fff44ec9580) at threads.c:661
#35 0x00007fb48c4d04e8 in GC_call_with_stack_base () from /usr/lib/x86_64-linux-gnu/libgc.so.1
#36 0x00007fb48cb86728 in scm_i_with_guile (dynamic_state=<optimized out>, data=data <at> entry=0x7fff44ec9580, func=func <at> entry=0x7fb48cb324f0 <invoke_main_func>) at threads.c:704
#37 scm_with_guile (func=func <at> entry=0x7fb48cb324f0 <invoke_main_func>, data=data <at> entry=0x7fff44ec95b0) at threads.c:710
#38 0x00007fb48cb326a2 in scm_boot_guile (argc=3, argv=0x7fff44ec9708, main_func=0x559a83f6e270 <inner_main>, closure=0x0) at init.c:323
#39 0x0000559a83f6e114 in main (argc=3, argv=0x7fff44ec9708) at guile.c:101


-- 
Göran Weinholt
Debian developer
73 de SA6CJK




Information forwarded to bug-guile <at> gnu.org:
bug#32367; Package guile. (Tue, 21 Aug 2018 21:33:01 GMT) Full text and rfc822 format available.

Message #11 received at 32367 <at> debbugs.gnu.org (full text, mbox):

From: Mark H Weaver <mhw <at> netris.org>
To: Göran Weinholt <goran <at> weinholt.se>
Cc: 32367 <at> debbugs.gnu.org, Ludovic Courtès <ludo <at> gnu.org>,
 Derek Upham <sand <at> blarg.net>
Subject: Re: bug#32367: 2.2.4 hangs when a script uses a module that calls
 sigaction
Date: Tue, 21 Aug 2018 17:30:41 -0400
I don't have time now for a proper investigation, but this might be
related to commit 761cf0fb8c364e885e4c6fced34563f8157c3b84 (Make module
autoloading thread-safe).

      Mark




Information forwarded to bug-guile <at> gnu.org:
bug#32367; Package guile. (Wed, 22 Aug 2018 13:48:01 GMT) Full text and rfc822 format available.

Message #14 received at 32367 <at> debbugs.gnu.org (full text, mbox):

From: Derek Upham <sand <at> blarg.net>
To: Mark H Weaver <mhw <at> netris.org>
Cc: 32367 <at> debbugs.gnu.org, Ludovic Courtès <ludo <at> gnu.org>,
 Göran Weinholt <goran <at> weinholt.se>
Subject: Re: bug#32367: 2.2.4 hangs when a script uses a module that calls
 sigaction
Date: Wed, 22 Aug 2018 06:47:49 -0700
Thanks.  I built from 4c91de3e4 and was able to reproduce the problem.  Then I reverted 761cf0fb8c364e885e4c6fced34563f8157c3b84 and I was not able to reproduce it.

So it’s probably the signal delivery thread starting in that module, and trying to load another module immediately.  This isn’t the first time the signal delivery thread has exposed an issue: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=26858

Derek

Mark H Weaver <mhw <at> netris.org> writes:

> I don't have time now for a proper investigation, but this might be
> related to commit 761cf0fb8c364e885e4c6fced34563f8157c3b84 (Make module
> autoloading thread-safe).
>
>       Mark




Information forwarded to bug-guile <at> gnu.org:
bug#32367; Package guile. (Thu, 23 Aug 2018 02:23:01 GMT) Full text and rfc822 format available.

Message #17 received at 32367 <at> debbugs.gnu.org (full text, mbox):

From: Mark H Weaver <mhw <at> netris.org>
To: Derek Upham <sand <at> blarg.net>
Cc: 32367 <at> debbugs.gnu.org, Ludovic Courtès <ludo <at> gnu.org>,
 Göran Weinholt <goran <at> weinholt.se>
Subject: Re: bug#32367: 2.2.4 hangs when a script uses a module that calls
 sigaction
Date: Wed, 22 Aug 2018 22:20:21 -0400
Hi Derek,

Derek Upham <sand <at> blarg.net> writes:

> Thanks.  I built from 4c91de3e4 and was able to reproduce the problem.
> Then I reverted 761cf0fb8c364e885e4c6fced34563f8157c3b84 and I was not
> able to reproduce it.

Thanks for checking.  I've reopened <https://bugs.gnu.org/31878> which
led to the faulty commit, and sent some messages there proposing a rough
outline for a more proper fix.

      Mark




Information forwarded to bug-guile <at> gnu.org:
bug#32367; Package guile. (Sun, 21 Oct 2018 18:49:02 GMT) Full text and rfc822 format available.

Message #20 received at 32367 <at> debbugs.gnu.org (full text, mbox):

From: Mark H Weaver <mhw <at> netris.org>
To: Göran Weinholt <goran <at> weinholt.se>
Cc: 32367 <at> debbugs.gnu.org, Derek Upham <sand <at> blarg.net>
Subject: Re: bug#32367: 2.2.4 hangs when a script uses a module that calls
 sigaction
Date: Sun, 21 Oct 2018 14:47:29 -0400
[Message part 1 (text/plain, inline)]
I've attached a preliminary patch to fix this bug.

      Mark

[0001-DRAFT-Fix-thread-safe-module-loading.patch (text/x-patch, inline)]
From 897a6f76280612e83f48d63430bf962520c0e7b3 Mon Sep 17 00:00:00 2001
From: Mark H Weaver <mhw <at> netris.org>
Date: Sun, 21 Oct 2018 09:56:16 -0400
Subject: [PATCH] DRAFT: Fix thread-safe module loading.

* module/ice-9/boot-9.scm (%modules-being-loaded)
(%local-modules-being-loaded, %modules-waiting-for): New variables.
(%force-lazy-module-cell!, %module-waiting-for?)
(%module-waiting-for!): New procedures.
(resolve-module): If the requested module is not in the regular global
module table, look in '%local-modules-being-loaded' and
'%modules-being-loaded', and handle these cases appropriately.  Support
looping without recursively locking the autoload lock.  When
autoloading, unlock the mutex before calling 'try-load-module'.
(try-module-autoload): Add entries to '%modules-being-loaded' and
'%local-modules-being-loaded' before loading the module.  Also, load the
module with the autoload mutex unlocked.  When the load attempt
finishes (or fails), add the module to the regular global module table
if it was ever created, signal the threads waiting for this module, and
remove it from the '*-begin-loaded' and '%modules-waiting-for' tables.
(call-with-module-autoload-lock): Accept a unary procedure instead of a
thunk.
(module-name): Adapt to the new 'call-with-module-autoload-lock'.
(nested-define-module!): If we're asked to define a submodule of a
module that's currently being loaded, install the parent module being
loaded into the global module table.
* module/ice-9/threads.scm (call-with-module-autoload-lock):
Pass the mutex as an argument to the procedure.
* test-suite/tests/threads.test: Add tests.
* test-suite/tests/delayed-test.scm,
test-suite/tests/mutual-delayed-a.scm,
test-suite/tests/mutual-delayed-b.scm,
test-suite/tests/mutual-delayed-c.scm: New files.
* test-suite/Makefile.am (EXTRA_DIST): Add them.
---
 module/ice-9/boot-9.scm               | 292 ++++++++++++++++++++++----
 module/ice-9/threads.scm              |   4 +-
 test-suite/Makefile.am                |   7 +-
 test-suite/tests/delayed-test.scm     |  28 +++
 test-suite/tests/mutual-delayed-a.scm |  29 +++
 test-suite/tests/mutual-delayed-b.scm |  29 +++
 test-suite/tests/mutual-delayed-c.scm |  29 +++
 test-suite/tests/threads.test         |  66 +++++-
 8 files changed, 435 insertions(+), 49 deletions(-)
 create mode 100644 test-suite/tests/delayed-test.scm
 create mode 100644 test-suite/tests/mutual-delayed-a.scm
 create mode 100644 test-suite/tests/mutual-delayed-b.scm
 create mode 100644 test-suite/tests/mutual-delayed-c.scm

diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm
index d8801dada..404a19d49 100644
--- a/module/ice-9/boot-9.scm
+++ b/module/ice-9/boot-9.scm
@@ -2502,13 +2502,32 @@ interfaces are added to the inports list."
                  (tail (cdr names)))
         (if (null? tail)
             (module-define-submodule! cur head module)
-            (let ((cur (or (module-ref-submodule cur head)
-                           (let ((m (make-module 31)))
-                             (set-module-kind! m 'directory)
-                             (set-module-name! m (append (module-name cur)
-                                                         (list head)))
-                             (module-define-submodule! cur head m)
-                             m))))
+            (let ((cur
+                   (or (module-ref-submodule cur head)
+                       (let ((dir-name (append (module-name cur)
+                                               (list head))))
+                         (cond ((assoc dir-name %modules-being-loaded)
+                                => (lambda (entry)
+                                     ;; The module we're being asked to define
+                                     ;; is a submodule of a module that's
+                                     ;; currently being loaded.  In this case,
+                                     ;; we must install the parent module
+                                     ;; being loaded into the global module
+                                     ;; table.  This is unfortunate, but it's
+                                     ;; not clear how to avoid this without
+                                     ;; changing the structure of the global
+                                     ;; module table.
+                                     (let ((m (%force-lazy-module-cell!
+                                               (cddr entry)
+                                               dir-name)))
+                                       (module-define-submodule! cur head m)
+                                       m)))
+                               (else
+                                (let ((m (make-module 31)))
+                                  (set-module-kind! m 'directory)
+                                  (set-module-name! m dir-name)
+                                  (module-define-submodule! cur head m)
+                                  m)))))))
               (loop cur (car tail) (cdr tail)))))))
 
 
@@ -2607,13 +2626,13 @@ interfaces are added to the inports list."
 
 
 
-(define (call-with-module-autoload-lock thunk)
-  ;; This binding is overridden when (ice-9 threads) is available to
-  ;; implement a critical section around the call to THUNK.  It must be
-  ;; used anytime 'autoloads-done' and related variables are accessed
-  ;; and whenever submodules are accessed (via the 'nested-'
-  ;; procedures.)
-  (thunk))
+(define (call-with-module-autoload-lock proc)
+  ;; Apply PROC to the autoload lock or #f, while holding the lock.
+  ;; This must be used anytime 'autoloads-done' and related variables
+  ;; are accessed and whenever submodules are accessed (e.g. via the
+  ;; 'nested-' procedures.)  This is initially a stub, but it will be
+  ;; overwritten when (ice-9 threads) is loaded.
+  (proc #f))
 
 ;; Now that modules are booted, give module-name its final definition.
 ;;
@@ -2627,7 +2646,7 @@ interfaces are added to the inports list."
             ;; names and relies on being able to `resolve-module' them.
             (set-module-name! mod name)
             (call-with-module-autoload-lock
-             (lambda ()
+             (lambda (mutex)
                (nested-define-module! (resolve-module '() #f) name mod)))
             (accessor mod))))))
 
@@ -2701,36 +2720,175 @@ deterministic."
     (beautify-user-module! m)
     m))
 
+;; '%modules-being-loaded' is a global table of modules currently
+;; being loaded.  Its entries are of the form:
+;;
+;;   (NAME COND-VAR . LAZY-MODULE-CELL)
+;;
+;; where COND-VAR is a condition variable that will signaled when the
+;; current module load attempt succeeds (or fails), and LAZY-MODULE-CELL
+;; is a singleton list whose element is either a module or #f.  It
+;; should only be accessed from within 'call-with-module-autoload-lock'.
+;;
+;; The modules in '%modules-being-loaded' are normally not added to the
+;; regular global module table until they have finished loading.  The
+;; idea is that other threads should not be able to see the partially
+;; loaded module.  If another thread tries to load the partially loaded
+;; module, it will normally wait on COND-VAR until the module has
+;; finished loading (or the load attempt fails).  However, there are two
+;; cases when a thread is given access to a partially loaded module: (1)
+;; when the partially loaded module is in its
+;; '%local-modules-being-loaded' list, and (2) when a non-trivial cycle
+;; would be introduced in the reflexive and transitive closure of the
+;; global %modules-waiting-for relation.
+(define %modules-being-loaded
+  '())
+
+;; The entries in (fluid-ref %local-modules-being-loaded) are of
+;; the form:
+;;
+;;   (NAME . LAZY-MODULE-CELL)
+;;
+;; where LAZY-MODULE-CELL is a singleton list whose element is
+;; either a module or #f.  It should only be accessed from within
+;; 'call-with-module-autoload-lock'.
+;;
+;; Modules listed in (fluid-ref %local-modules-being-loaded) are visible
+;; to the local thread, even if they are not present in the regular
+;; global module table.
+(define %local-modules-being-loaded
+  (make-fluid '()))
+
+(define (%force-lazy-module-cell! cell name)
+  (or (car cell) ; the module already exists; return it
+      ;; otherwise, create a fresh new module, store it in the
+      ;; lazy-module-cell, and return it.
+      (let ((m (make-module 31)))
+        (set-module-name! m name)
+        (set-car! cell m)
+        m)))
+
+;; The '%modules-waiting-for' relation is a partial order on
+;; the modules present in the '%modules-being-loaded' table.
+;; Its entries are of the form:
+;;
+;;   (NAME-1 . NAME-2)
+;;
+;; '%modules-waiting-for' is used to prevent deadlocks that would
+;; otherwise occur when mutually dependent modules are loaded
+;; concurrently.  It should only be accessed from within
+;; 'call-with-module-autoload-lock'.
+(define %modules-waiting-for
+  '())
+
+;; Return #t if (NAME-1 NAME-2) is in the reflexive and transitive
+;; closure of '%modules-waiting-for'.  This procedure should only be
+;; called from within 'call-with-module-autoload-lock'.
+(define (%module-waiting-for? name-1 name-2)
+  (or (equal? name-1 name-2)
+      (cond ((assoc name-1 %modules-waiting-for)
+             => (lambda (entry)
+                  (%module-waiting-for? (cdr entry) name-2)))
+            (else #f))))
+
+;; Add (NAME-1 NAME-2) to the '%modules-waiting-for' relation if it's
+;; not already in the reflexive and transitive closure.  Raise an error
+;; if adding it would introduce a cycle.  This procedure should only be
+;; called from within 'call-with-module-autoload-lock'.
+(define (%module-waiting-for! name-1 name-2)
+  (unless (%module-waiting-for? name-1 name-2)
+    (when (%module-waiting-for? name-2 name-1)
+      (error "%module-waiting-for!: would introduce a cycle"
+             (list name-1 name-2 %modules-waiting-for)))
+    (set! %modules-waiting-for
+          (cons (cons name-1 name-2)
+                %modules-waiting-for))))
+
 ;; NOTE: This binding is used in libguile/modules.c.
 ;;
 (define resolve-module
-  (let ((root (make-module)))
+  (let ((root (make-module))
+        (ice-9-threads
+         (lambda (sym)
+           (module-ref (resolve-module '(ice-9 threads)) sym))))
+
     (set-module-name! root '())
     ;; Define the-root-module as '(guile).
     (module-define-submodule! root 'guile the-root-module)
 
     (lambda* (name #:optional (autoload #t) (version #f) #:key (ensure #t))
       (call-with-module-autoload-lock
-       (lambda ()
-         (let ((already (nested-ref-module root name)))
-           (cond
-            ((and already
-                  (or (not autoload) (module-public-interface already)))
-             ;; A hit, a palpable hit.
-             (if (and version
-                      (not (version-matches? version (module-version already))))
+       (lambda (mutex)
+         (let loop ((autoload autoload))
+           ;; First check the global module table.
+           (let ((already (nested-ref-module root name)))
+             (cond
+              ((and already
+                    (or (not autoload) (module-public-interface already)))
+               ;; A hit, a palpable hit.
+               (when (and version
+                          (not (version-matches? version (module-version already))))
                  (error "incompatible module version already loaded" name))
-             already)
-            (autoload
-             ;; Try to autoload the module, and recurse.
-             (try-load-module name version)
-             (resolve-module name #f #:ensure ensure))
-            (else
-             ;; No module found (or if one was, it had no public interface), and
-             ;; we're not autoloading. Make an empty module if #:ensure is true.
-             (or already
-                 (and ensure
-                      (make-modules-in root name)))))))))))
+               already)
+
+              ;; The module is not in the global module table.
+              ;; Check %local-modules-being-loaded.  If there's a
+              ;; matching entry, return the associated module,
+              ;; forcing the lazy module cell if needed.
+              ((assoc name (fluid-ref %local-modules-being-loaded))
+               => (lambda (entry)
+                    (%force-lazy-module-cell! (cdr entry) name)))
+
+              ;; Check the global '%modules-being-loaded' table.  If
+              ;; there's a matching entry, add an entry to the
+              ;; '%modules-waiting-for' relation (checking to
+              ;; make sure we don't introduce a cycle), wait on the
+              ;; associated condition variable for the module to be
+              ;; loaded, and try again.
+              ((assoc name %modules-being-loaded)
+               => (lambda (entry)
+                    (let ((cond-var (cadr entry))
+                          (lazy-module-cell (cddr entry))
+                          (local-modules (fluid-ref %local-modules-being-loaded)))
+                      (if (or (not mutex)
+                              (and (pair? local-modules)
+                                   ;; check for circular dependency below
+                                   (%module-waiting-for? name (caar local-modules))))
+                          ;; If (ice-9 threads) is not yet loaded, or
+                          ;; if adding the new entry to
+                          ;; '%module-waiting-for' would add a
+                          ;; circular dependency, then punt and
+                          ;; immediately return the partially-loaded
+                          ;; module.
+                          (%force-lazy-module-cell! lazy-module-cell name)
+                          ;; Otherwise, add an entry to the
+                          ;; '%modules-waiting-for' relation, wait on
+                          ;; the associated condition variable for the
+                          ;; module to be loaded, and try again.
+                          (begin
+                            (when (pair? local-modules)
+                              (%module-waiting-for! (caar local-modules) name))
+                            ;; wait for the pending module load to finish.
+                            ((ice-9-threads 'wait-condition-variable) cond-var mutex)
+                            (loop #f))))))   ; and try again
+
+              (autoload
+               ;; Here we try to autoload the module.  Unlock the mutex
+               ;; while we call 'try-load-module'.
+               (dynamic-wind
+                 (lambda () (when mutex
+                              ((ice-9-threads 'unlock-mutex) mutex)))
+                 (lambda () (try-load-module name version))
+                 (lambda () (when mutex
+                              ((ice-9-threads 'lock-mutex) mutex))))
+               ;; Now try again with autoload set to #f.
+               (loop #f))
+              (else
+               ;; No module found (or if one was, it had no public interface), and
+               ;; we're not autoloading. Make an empty module if #:ensure is true.
+               (or already
+                   (and ensure
+                        (make-modules-in root name))))))))))))
 
 
 (define (try-load-module name version)
@@ -2973,6 +3131,8 @@ module '(ice-9 q) '(make-q q-length))}."
   "Try to load a module of the given name.  If it is not found, return
 #f.  Otherwise return #t.  May raise an exception if a file is found,
 but it fails to load."
+  (define (ice-9-threads sym)
+    (module-ref (resolve-module '(ice-9 threads)) sym))
   (let* ((reverse-name (reverse module-name))
          (name (symbol->string (car reverse-name)))
          (dir-hint-module-name (reverse (cdr reverse-name)))
@@ -2980,17 +3140,34 @@ but it fails to load."
                           (map (lambda (elt)
                                  (string-append (symbol->string elt)
                                                 file-name-separator-string))
-                               dir-hint-module-name))))
-    (resolve-module dir-hint-module-name #f)
+                               dir-hint-module-name)))
+         (parent-module (resolve-module dir-hint-module-name #f)))
 
     (call-with-module-autoload-lock
-     (lambda ()
+     (lambda (mutex)
        (and (not (autoload-done-or-in-progress? dir-hint name))
-            (let ((didit #f))
+            (let ((lazy-module-cell (list #f))
+                  (cond-var (and mutex
+                                 ((ice-9-threads 'make-condition-variable))))
+                  (didit #f))
+
+              ;; Add an entry to the '%modules-being-loaded' table,
+              ;; with an associated condition variable to be signaled
+              ;; when the module is finished loading.
+              (set! %modules-being-loaded
+                    (cons (cons* module-name cond-var lazy-module-cell)
+                          %modules-being-loaded))
+
               (dynamic-wind
-                (lambda () (autoload-in-progress! dir-hint name))
                 (lambda ()
-                  (with-fluids ((current-reader #f))
+                  (autoload-in-progress! dir-hint name)
+                  (when mutex
+                    ((ice-9-threads 'unlock-mutex) mutex)))
+                (lambda ()
+                  (with-fluids ((%local-modules-being-loaded
+                                 (cons (cons module-name lazy-module-cell)
+                                       (fluid-ref %local-modules-being-loaded)))
+                                (current-reader #f))
                     (save-module-excursion
                      (lambda ()
                        (define (call/ec proc)
@@ -3014,7 +3191,38 @@ but it fails to load."
                           (primitive-load-path (in-vicinity dir-hint name)
                                                abort)
                           (set! didit #t)))))))
-                (lambda () (set-autoloaded! dir-hint name didit)))
+                (lambda ()
+                  (when mutex
+                    ((ice-9-threads 'lock-mutex) mutex))
+                  (set-autoloaded! dir-hint name didit)))
+
+              ;; If the local module was actually created, then we
+              ;; now add it to the global module table.
+              (let ((module (car lazy-module-cell)))
+                (when module
+                  (module-define-submodule! parent-module
+                                            (car reverse-name)
+                                            module)))
+
+              ;; Signal all threads waiting on the condition variable
+              ;; for this module to be loaded.
+              (when cond-var
+                ((ice-9-threads 'broadcast-condition-variable) cond-var))
+
+              ;; Remove the module from '%modules-being-loaded'.
+              (set! %modules-being-loaded
+                    (assoc-remove! %modules-being-loaded
+                                   module-name))
+
+              ;; Remove all '%modules-waiting-for' entries that are
+              ;; directly related to the module that we just loaded
+              ;; (or attempted to load).
+              (set! %modules-waiting-for
+                    (filter! (lambda (entry)
+                               (not (or (equal? module-name (car entry))
+                                        (equal? module-name (cdr entry)))))
+                             %modules-waiting-for))
+              
               didit))))))
 
 
diff --git a/module/ice-9/threads.scm b/module/ice-9/threads.scm
index c42bd266f..81fa22063 100644
--- a/module/ice-9/threads.scm
+++ b/module/ice-9/threads.scm
@@ -385,8 +385,8 @@ of applying P-PROC on ARGLISTS."
 ;; thread-safe.
 (set! (@ (guile) call-with-module-autoload-lock)
   (let ((mutex (make-mutex 'recursive)))
-    (lambda (thunk)
+    (lambda (proc)
       (with-mutex mutex
-        (thunk)))))
+        (proc mutex)))))
 
 ;;; threads.scm ends here
diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am
index 0934dbb34..354c33152 100644
--- a/test-suite/Makefile.am
+++ b/test-suite/Makefile.am
@@ -1,7 +1,6 @@
 ## Process this file with automake to produce Makefile.in.
 ##
-## Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-##   2010, 2011, 2012, 2013, 2014 Software Foundation, Inc.
+## Copyright 2001-2018 Software Foundation, Inc.
 ##
 ## This file is part of GUILE.
 ##
@@ -204,6 +203,10 @@ EXTRA_DIST = \
 	$(SCM_TESTS) \
 	tests/rnrs-test-a.scm \
 	tests/srfi-64-test.scm \
+	tests/mutual-delayed-a.scm \
+	tests/mutual-delayed-b.scm \
+	tests/mutual-delayed-c.scm \
+	tests/delayed-test.scm \
 	ChangeLog-2008
 
 
diff --git a/test-suite/tests/delayed-test.scm b/test-suite/tests/delayed-test.scm
new file mode 100644
index 000000000..cc584d61d
--- /dev/null
+++ b/test-suite/tests/delayed-test.scm
@@ -0,0 +1,28 @@
+;;;; delayed-test.scm --- A test helper.       -*- scheme -*-
+;;;;
+;;;; Copyright 2018 Free Software Foundation, Inc.
+;;;;
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;; 
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;; 
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+(define-module (tests delayed-test)
+  #:use-module (tests threads)
+  #:export (delayed-proc))
+
+(increment-delayed-test-count!)
+(define delayed-proc #f)
+(thread-safe-format "delayed-test: starting sleep\n")
+(sleep 2)
+(define (delayed-proc) 'done)
+(thread-safe-format "delayed-test: done\n")
diff --git a/test-suite/tests/mutual-delayed-a.scm b/test-suite/tests/mutual-delayed-a.scm
new file mode 100644
index 000000000..6a8c4f116
--- /dev/null
+++ b/test-suite/tests/mutual-delayed-a.scm
@@ -0,0 +1,29 @@
+;;;; mutual-delayed-a.scm --- A test helper.       -*- scheme -*-
+;;;;
+;;;; Copyright 2018 Free Software Foundation, Inc.
+;;;;
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;; 
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;; 
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+(define-module (tests mutual-delayed-a)
+  #:use-module (tests threads)
+  #:export (delayed-a))
+
+(define delayed-a #f)
+(thread-safe-format "mutual-delayed-a: starting sleep\n")
+(sleep 2)
+(thread-safe-format "mutual-delayed-a: loading mutual-delayed-b\n")
+(resolve-module '(tests mutual-delayed-b))
+(define (delayed-a) 'a)
+(thread-safe-format "mutual-delayed-a: done\n")
diff --git a/test-suite/tests/mutual-delayed-b.scm b/test-suite/tests/mutual-delayed-b.scm
new file mode 100644
index 000000000..81aad5b52
--- /dev/null
+++ b/test-suite/tests/mutual-delayed-b.scm
@@ -0,0 +1,29 @@
+;;;; mutual-delayed-b.scm --- A test helper.       -*- scheme -*-
+;;;;
+;;;; Copyright 2018 Free Software Foundation, Inc.
+;;;;
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;; 
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;; 
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+(define-module (tests mutual-delayed-b)
+  #:use-module (tests threads)
+  #:export (delayed-b))
+
+(define delayed-b #f)
+(thread-safe-format "mutual-delayed-b: starting sleep\n")
+(sleep 2)
+(thread-safe-format "mutual-delayed-b: loading mutual-delayed-c\n")
+(resolve-module '(tests mutual-delayed-c))
+(define (delayed-b) 'b)
+(thread-safe-format "mutual-delayed-b: done\n")
diff --git a/test-suite/tests/mutual-delayed-c.scm b/test-suite/tests/mutual-delayed-c.scm
new file mode 100644
index 000000000..90e84a52f
--- /dev/null
+++ b/test-suite/tests/mutual-delayed-c.scm
@@ -0,0 +1,29 @@
+;;;; mutual-delayed-c.scm --- A test helper.       -*- scheme -*-
+;;;;
+;;;; Copyright 2018 Free Software Foundation, Inc.
+;;;;
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;; 
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;; 
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+(define-module (tests mutual-delayed-c)
+  #:use-module (tests threads)
+  #:export (delayed-c))
+
+(define delayed-c #f)
+(thread-safe-format "mutual-delayed-c: starting sleep\n")
+(sleep 2)
+(thread-safe-format "mutual-delayed-c: loading mutual-delayed-a\n")
+(resolve-module '(tests mutual-delayed-a))
+(define (delayed-c) 'c)
+(thread-safe-format "mutual-delayed-c: done\n")
diff --git a/test-suite/tests/threads.test b/test-suite/tests/threads.test
index efdf36db2..434a1f4e8 100644
--- a/test-suite/tests/threads.test
+++ b/test-suite/tests/threads.test
@@ -1,7 +1,7 @@
 ;;;; threads.test --- Tests for Guile threading.    -*- scheme -*-
 ;;;;
 ;;;; Copyright 2003, 2006, 2007, 2009, 2010, 2011, 2012, 2013,
-;;;;   2014 Free Software Foundation, Inc.
+;;;;   2014, 2018 Free Software Foundation, Inc.
 ;;;;
 ;;;; This library is free software; you can redistribute it and/or
 ;;;; modify it under the terms of the GNU Lesser General Public
@@ -17,10 +17,12 @@
 ;;;; License along with this library; if not, write to the Free Software
 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
-(define-module (test-threads)
+(define-module (tests threads)
   #:use-module (ice-9 threads)
   #:use-module (system base compile)
-  #:use-module (test-suite lib))
+  #:use-module (test-suite lib)
+  #:export (increment-delayed-test-count!
+            thread-safe-format))
 
 (define (asyncs-still-working?)
   (let ((a #f))
@@ -448,3 +450,61 @@
   (pass-if "current-processor-count"
     (and (>= (current-processor-count) 1)
          (>= (total-processor-count) (current-processor-count)))))
+
+;;
+;; thread safe module loading
+;;
+
+(define thread-safe-format
+  (let ((mutex (make-mutex)))
+    (lambda args
+      (with-mutex mutex
+        (apply format (current-error-port) args)))))
+(define delayed-test-count-mutex (make-mutex))
+(define delayed-test-count 0)
+(define (increment-delayed-test-count!)
+  (with-mutex delayed-test-count-mutex
+    (set! delayed-test-count
+          (+ delayed-test-count 1))))
+
+(with-test-prefix "thread safe module loading"
+  ;; We deliberately avoid using 'par-map' below, because the
+  ;; effectiveness of these tests depend on them running roughly in
+  ;; parallel.  When 'par-map' is used on a machine with only 1 or 2
+  ;; cores, the tests below are unable to reliably detect the problems
+  ;; that exist before guile-2.2.5.
+  (define (spawn-test-thread module-name sym)
+    (call-with-new-thread
+     (lambda ()
+       (cond ((module-variable (resolve-module module-name) sym)
+              => (lambda (v)
+                   (and (variable? v)
+                        (procedure? (variable-ref v))
+                        ((variable-ref v)))))
+             (else
+              #f)))))
+  (define (join-thread-with-timeout deadline)
+    (lambda (thread)
+      (join-thread thread deadline 'timeout)))
+  (pass-if-equal "concurrent loading of the same module by multiple threads"
+      '(1 done done done done done done)
+    (let ((results
+           (map (join-thread-with-timeout (+ (current-time) 20))
+                (map (lambda (i)
+                       (spawn-test-thread '(tests delayed-test)
+                                          'delayed-proc))
+                     (iota 6)))))
+      (cons delayed-test-count results)))
+  (pass-if-equal "mutually dependent modules loaded concurrently"
+      '(a b c a b c a b c)
+    (map (join-thread-with-timeout (+ (current-time) 20))
+         (map (lambda (i)
+                (case (modulo i 3)
+                  ((0) (spawn-test-thread '(tests mutual-delayed-a)
+                                          'delayed-a))
+                  ((1) (spawn-test-thread '(tests mutual-delayed-b)
+                                          'delayed-b))
+                  ((2) (spawn-test-thread '(tests mutual-delayed-c)
+                                          'delayed-c))
+                  (else #f)))
+              (iota 9)))))
-- 
2.19.1


Information forwarded to bug-guile <at> gnu.org:
bug#32367; Package guile. (Sat, 27 Oct 2018 14:17:02 GMT) Full text and rfc822 format available.

Message #23 received at 32367 <at> debbugs.gnu.org (full text, mbox):

From: Derek Upham <sand <at> blarg.net>
To: Mark H Weaver <mhw <at> netris.org>
Cc: 32367 <at> debbugs.gnu.org, Göran Weinholt <goran <at> weinholt.se>
Subject: Re: bug#32367: 2.2.4 hangs when a script uses a module that calls
 sigaction
Date: Sat, 27 Oct 2018 07:16:44 -0700
I’m not having luck with the patch.  Current commit is bbe6daa76 (stable-2.2).  Running

  ./autogen.sh && ./configure --prefix=$HOME/guile-2.2 PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/lib64/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig && make clean all install

builds clean and I can repro the problem with

  $HOME/guile-2.2/bin/guile -s ../signal-test

The patch applies cleanly, but then the same build commands fail:

    GUILEC sxml/apply-templates.go
  Backtrace:
  In ice-9/boot-9.scm:
     222:17 19 (map1 (((sxml ssax)) ((sxml xpath) #:hide (filter))))
    2958:17 18 (resolve-interface (sxml ssax) #:select _ #:hide _ #:prefix _ #:renamer _ #:version _)
  In ice-9/threads.scm:
      390:8 17 (_ _)
  In ice-9/boot-9.scm:
    2881:28 16 (_ #<mutex 559a33ee4f80>)
  In ice-9/threads.scm:
      390:8 15 (_ _)
  In ice-9/boot-9.scm:
    3171:20 14 (_ #<mutex 559a33ee4f80>)
     2312:4 13 (save-module-excursion #<procedure 559a3417a360 at ice-9/boot-9.scm:3172:21 ()>)
    3191:26 12 (_)
  In unknown file:
            11 (primitive-load-path "sxml/ssax" #<procedure 559a33dc3c60 at ice-9/boot-9.scm:3178:37 ()>)
  In ice-9/eval.scm:
     721:20 10 (primitive-eval (define-module (sxml ssax) #:use-module (sxml ssax input-parse) #:use-module (srfi srfi-1) #:use-module (srfi srfi-13) #:export (# # # # # # ?)))
  In ice-9/psyntax.scm:
    1235:36  9 (expand-top-sequence ((define-module (sxml ssax) #:use-module (sxml ssax input-parse) #:use-module (srfi srfi-1) #:use-module (srfi srfi-13) #:export (# # ?))) _ ?)
    1182:24  8 (parse _ (("placeholder" placeholder)) ((top) #(ribcage () () ())) _ e (eval) (hygiene #{ g95}#))
     285:10  7 (parse _ (("placeholder" placeholder)) (()) _ c&e (eval) (hygiene #{ g95}#))
  In ice-9/eval.scm:
     293:34  6 (_ #<module (#{ g95}#) 559a34125000>)
  In ice-9/boot-9.scm:
     3032:4  5 (define-module* _ #:filename _ #:pure _ #:version _ #:imports _ #:exports _ #:replacements _ #:re-exports _ #:autoloads _ #:duplicates _ #:transformer _)
    3045:24  4 (_)
     222:17  3 (map1 (((sxml ssax input-parse)) ((srfi srfi-1)) ((srfi srfi-13))))
     2961:6  2 (resolve-interface _ #:select _ #:hide _ #:prefix _ #:renamer _ #:version _)
  In unknown file:
             1 (scm-error misc-error #f "~A ~S" ("no code for module" (sxml ssax input-parse)) #f)
  In ice-9/boot-9.scm:
     752:25  0 (dispatch-exception _ _ _)

  ice-9/boot-9.scm:752:25: In procedure dispatch-exception:
  no code for module (sxml ssax input-parse)


Mark H Weaver <mhw <at> netris.org> writes:

> I've attached a preliminary patch to fix this bug.
>
>       Mark


-- 
Derek Upham
sand <at> blarg.net




Information forwarded to bug-guile <at> gnu.org:
bug#32367; Package guile. (Sat, 15 Dec 2018 16:47:01 GMT) Full text and rfc822 format available.

Message #26 received at 32367 <at> debbugs.gnu.org (full text, mbox):

From: Matt Wette <matt.wette <at> gmail.com>
To: 32367 <at> debbugs.gnu.org
Subject: sigaction hangs
Date: Sat, 15 Dec 2018 08:46:18 -0800
-s seems to end up using load-in-vicinity: I can re-create this way:

mwette$ guile -L `pwd` -c '(load-in-vicinity (getcwd) "foo.scm")'
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;;       or pass the --no-auto-compile argument to disable.
;;; compiling /home/mwette/proj/guile/bugs-guile/32367/foo.scm
setting SIGCHILD to SIG_DFL...
^C





Information forwarded to bug-guile <at> gnu.org:
bug#32367; Package guile. (Sat, 15 Dec 2018 16:59:02 GMT) Full text and rfc822 format available.

Message #29 received at 32367 <at> debbugs.gnu.org (full text, mbox):

From: Matt Wette <matt.wette <at> gmail.com>
To: 32367 <at> debbugs.gnu.org
Subject: Re: sigaction hangs
Date: Sat, 15 Dec 2018 08:58:51 -0800
On 12/15/18 8:46 AM, Matt Wette wrote:
> -s seems to end up using load-in-vicinity: I can re-create this way:
>
> mwette$ guile -L `pwd` -c '(load-in-vicinity (getcwd) "foo.scm")'
> ;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
> ;;;       or pass the --no-auto-compile argument to disable.
> ;;; compiling /home/mwette/proj/guile/bugs-guile/32367/foo.scm
> setting SIGCHILD to SIG_DFL...
> ^C
>

And using `-l' to load scsh.scm fixes the problem:

mwette$ guile -L `pwd` -l scsh.scm -c '(load-in-vicinity (getcwd) 
"foo.scm")'setting SIGCHILD to SIG_DFL...
setting SIGCHILD to SIG_DFL...done
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;;       or pass the --no-auto-compile argument to disable.
;;; compiling /home/mwette/proj/guile/bugs-guile/32367/foo.scm
;;; compiled 
/home/mwette/.cache/guile/ccache/2.2-LE-8-3.A/home/mwette/proj/guile/bugs-guile/32367/foo.scm.go
mwette $

An update from 2.2.3 to 2.2.4 adds call-with-module-autoload-lock which 
places a
mutex around autoload.  This looks like one place to start digging. See 
ice-9/threads.scm:

(set! (@ (guile) call-with-module-autoload-lock)
  (let ((mutex (make-mutex 'recursive)))
    (lambda (thunk)
      (with-mutex mutex
        (thunk)))))






Information forwarded to bug-guile <at> gnu.org:
bug#32367; Package guile. (Sat, 15 Dec 2018 17:52:02 GMT) Full text and rfc822 format available.

Message #32 received at 32367 <at> debbugs.gnu.org (full text, mbox):

From: Mark H Weaver <mhw <at> netris.org>
To: Matt Wette <matt.wette <at> gmail.com>
Cc: 32367 <at> debbugs.gnu.org
Subject: Re: bug#32367: sigaction hangs
Date: Sat, 15 Dec 2018 12:50:37 -0500
Hi Matt,

Matt Wette <matt.wette <at> gmail.com> writes:

> On 12/15/18 8:46 AM, Matt Wette wrote:
>> -s seems to end up using load-in-vicinity: I can re-create this way:
>>
>> mwette$ guile -L `pwd` -c '(load-in-vicinity (getcwd) "foo.scm")'
>> ;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
>> ;;;       or pass the --no-auto-compile argument to disable.
>> ;;; compiling /home/mwette/proj/guile/bugs-guile/32367/foo.scm
>> setting SIGCHILD to SIG_DFL...
>> ^C
>>
>
> And using `-l' to load scsh.scm fixes the problem:
>
> mwette$ guile -L `pwd` -l scsh.scm -c '(load-in-vicinity (getcwd)
> "foo.scm")'setting SIGCHILD to SIG_DFL...
> setting SIGCHILD to SIG_DFL...done
> ;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
> ;;;       or pass the --no-auto-compile argument to disable.
> ;;; compiling /home/mwette/proj/guile/bugs-guile/32367/foo.scm
> ;;; compiled
> /home/mwette/.cache/guile/ccache/2.2-LE-8-3.A/home/mwette/proj/guile/bugs-guile/32367/foo.scm.go
> mwette $
>
> An update from 2.2.3 to 2.2.4 adds call-with-module-autoload-lock
> which places a
> mutex around autoload.  This looks like one place to start
> digging. See ice-9/threads.scm:
>
> (set! (@ (guile) call-with-module-autoload-lock)
>   (let ((mutex (make-mutex 'recursive)))
>     (lambda (thunk)
>       (with-mutex mutex
>         (thunk)))))

It looks like you might have missed some of the messages in this bug
report.  See <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32367#11>
and later comments.

     Regards,
       Mark




This bug report was last modified 5 years and 132 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.