unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* Trouble joining with threads from C
@ 2011-03-07  5:56 Mark H Weaver
  2011-03-09  6:48 ` Mark H Weaver
  0 siblings, 1 reply; 12+ messages in thread
From: Mark H Weaver @ 2011-03-07  5:56 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 444 bytes --]

Apologies in advance if I'm making a mistake here, but can someone
explain to me why the minimal attached example code fails to join with
its trivial spawned thread?

I might guess that it's because spawn_thread() in threads.c calls
scm_i_pthread_detach.  So does launch_thread().  Yet the documentation
of scm_join_thread seems to indicate that you ought to be able to join
with a thread created by scm_spawn_thread.

    Thanks,
      Mark



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Minimal example code --]
[-- Type: text/x-csrc, Size: 481 bytes --]

#include <libguile.h>

static SCM
thread_main (void *data)
{
  return SCM_BOOL_F;
}

static SCM
thread_handler (void *data, SCM key, SCM args)
{
  return SCM_BOOL_F;
}

static void *
inner_main (void *data)
{
  SCM thread = scm_spawn_thread (thread_main, 0, thread_handler, 0);
  SCM timeout = scm_from_unsigned_integer (time (NULL) + 20);
  scm_join_thread_timed (thread, timeout, SCM_BOOL_T);
}

int
main (int argc, char **argv)
{
  scm_with_guile (inner_main, 0);
  return 0;
}

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Trouble joining with threads from C
  2011-03-07  5:56 Trouble joining with threads from C Mark H Weaver
@ 2011-03-09  6:48 ` Mark H Weaver
  2011-03-18 12:23   ` Andy Wingo
  0 siblings, 1 reply; 12+ messages in thread
From: Mark H Weaver @ 2011-03-09  6:48 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 961 bytes --]

Having further investigated, I'm convinced that this is a bug.

Attached are two minimal C programs.  Both create threads that do
nothing but sleep for 2 seconds and then exit.  The parent tries to join
with the child thread, with a timeout of 10 seconds.

The only difference is that test1 uses scm_spawn_thread, and test2 uses
scm_call_with_new_thread.  test1 always times out, and test2 works
properly.

Having looked at the code in threads.c, I'm surprised that either of
them work.  Both scm_spawn_thread and scm_call_with_new_thread arrange
for pthread_detach to be called in the child (in spawn_thread and
launch_thread, respectively).  This is supposed to make the child
un-joinable.

I've attached not only test1.c and test2.c, but also the diff
between them.  I compiled them as follows:

  gcc -o test1 test1.c $(pkg-config --cflags --libs guile-2.0)
  gcc -o test2 test2.c $(pkg-config --cflags --libs guile-2.0)

Any ideas?

   Thanks,
     Mark



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: test1.c, which uses scm_spawn_thread --]
[-- Type: text/x-csrc, Size: 920 bytes --]

#include <libguile.h>

static SCM
thread_main (void *data)
{
  /* scm_sleep (scm_from_signed_integer (20));  /* This should cause a timeout */
  /* scm_sleep (SCM_BOOL_T);                    /* This should throw an exception */
  scm_sleep (scm_from_signed_integer (2));      /* This should finish */
  return scm_from_latin1_string ("finished");
}

static SCM
thread_handler (void *data, SCM key, SCM args)
{
  return scm_from_latin1_string ("exception thrown");
}

static void *
inner_main (void *data)
{
  SCM thread = scm_spawn_thread (thread_main, 0, thread_handler, 0);
  SCM timeout = scm_sum (scm_current_time(), scm_from_signed_integer (10));
  SCM result = scm_join_thread_timed (thread, timeout, scm_from_latin1_string ("timed out"));
  scm_simple_format (SCM_BOOL_T, scm_from_latin1_string ("~A\n"), scm_list_1 (result));
}

int
main (int argc, char **argv)
{
  scm_with_guile (inner_main, 0);
  return 0;
}

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: test2.c, which uses scm_call_with_new_thread --]
[-- Type: text/x-csrc, Size: 1098 bytes --]

#include <libguile.h>

static SCM
thread_main (void)
{
  /* scm_sleep (scm_from_signed_integer (20));  /* This should cause a timeout */
  /* scm_sleep (SCM_BOOL_T);                    /* This should throw an exception */
  scm_sleep (scm_from_signed_integer (2));      /* This should finish */
  return scm_from_latin1_string ("finished");
}

static SCM
thread_handler (SCM handler, SCM key, SCM args)
{
  return scm_from_latin1_string ("exception thrown");
}

static void *
inner_main (void *data)
{
  SCM thread_main_proc = scm_c_make_gsubr ("thread-main", 0, 0, 0, thread_main);
  SCM thread_handler_proc = scm_c_make_gsubr ("thread-handler", 2, 0, 1, thread_handler);
  SCM thread = scm_call_with_new_thread (thread_main_proc, thread_handler_proc);
  SCM timeout = scm_sum (scm_current_time(), scm_from_signed_integer (10));
  SCM result = scm_join_thread_timed (thread, timeout, scm_from_latin1_string ("timed out"));
  scm_simple_format (SCM_BOOL_T, scm_from_latin1_string ("~A\n"), scm_list_1 (result));
}

int
main (int argc, char **argv)
{
  scm_with_guile (inner_main, 0);
  return 0;
}

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: Diff between test1.c and test2.c --]
[-- Type: text/x-diff, Size: 1207 bytes --]

--- test1.c	2011-03-09 01:33:36.000000000 -0500
+++ test2.c	2011-03-09 01:34:18.000000000 -0500
@@ -1,7 +1,7 @@
 #include <libguile.h>
 
 static SCM
-thread_main (void *data)
+thread_main (void)
 {
   /* scm_sleep (scm_from_signed_integer (20));  /* This should cause a timeout */
   /* scm_sleep (SCM_BOOL_T);                    /* This should throw an exception */
@@ -10,7 +10,7 @@
 }
 
 static SCM
-thread_handler (void *data, SCM key, SCM args)
+thread_handler (SCM handler, SCM key, SCM args)
 {
   return scm_from_latin1_string ("exception thrown");
 }
@@ -18,7 +18,9 @@
 static void *
 inner_main (void *data)
 {
+  SCM thread_main_proc = scm_c_make_gsubr ("thread-main", 0, 0, 0, thread_main);
+  SCM thread_handler_proc = scm_c_make_gsubr ("thread-handler", 2, 0, 1, thread_handler);
-  SCM thread = scm_spawn_thread (thread_main, 0, thread_handler, 0);
+  SCM thread = scm_call_with_new_thread (thread_main_proc, thread_handler_proc);
   SCM timeout = scm_sum (scm_current_time(), scm_from_signed_integer (10));
   SCM result = scm_join_thread_timed (thread, timeout, scm_from_latin1_string ("timed out"));
   scm_simple_format (SCM_BOOL_T, scm_from_latin1_string ("~A\n"), scm_list_1 (result));

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Trouble joining with threads from C
  2011-03-09  6:48 ` Mark H Weaver
@ 2011-03-18 12:23   ` Andy Wingo
  2011-03-20 23:11     ` Ludovic Courtès
  0 siblings, 1 reply; 12+ messages in thread
From: Andy Wingo @ 2011-03-18 12:23 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: guile-devel

[-- Attachment #1: Type: text/plain, Size: 1291 bytes --]

Hi Mark,

On Wed 09 Mar 2011 07:48, Mark H Weaver <mhw@netris.org> writes:

> Attached are two minimal C programs.  Both create threads that do
> nothing but sleep for 2 seconds and then exit.  The parent tries to join
> with the child thread, with a timeout of 10 seconds.
>
> The only difference is that test1 uses scm_spawn_thread, and test2 uses
> scm_call_with_new_thread.  test1 always times out, and test2 works
> properly.

Indeed, a bug.

> Having looked at the code in threads.c, I'm surprised that either of
> them work.  Both scm_spawn_thread and scm_call_with_new_thread arrange
> for pthread_detach to be called in the child (in spawn_thread and
> launch_thread, respectively).  This is supposed to make the child
> un-joinable.

scm_join_thread_timed doesn't use pthread_join.  I don't recall exactly
why, but its implementation does look OK, at least at first glance.

No, the issue is elsewhere, that the thread-exit handlers were not being
called, which makes me trust our pthreads support much less than before,
if this bug could exist for so long.  I have fixed this in Git with the
attached patch, which fixes your test as well.

Would you mind submitting (and committing :) a test case?  Adding it to
test-suite/standalone is probably the thing to do.

Regards,

Andy


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-fix-thread-cleanup.patch --]
[-- Type: text/x-patch, Size: 6719 bytes --]

From 4732679c36305b886cbb6bd3473154731535cb0b Mon Sep 17 00:00:00 2001
From: Andy Wingo <wingo@pobox.com>
Date: Fri, 18 Mar 2011 13:18:47 +0100
Subject: [PATCH] fix thread cleanup

* libguile/threads.h: Always declare a scm_i_thread_key, for cleanup
  purposes, in the BUILDING_LIBGUILE case.

* libguile/threads.c (scm_i_thread_key): Init with a cleanup handler, so
  any guile-specific info for a thread can be cleaned up reliably.
  (guilify_self_1): Always set the thread key.
  (do_thread_exit_trampoline, on_thread_exit): Enter guile-mode for the
  guile-mode cleanup handler, and trampoline through a
  gc_call_with_stack_base for reasons explained in the code.
  (init_thread_key, scm_i_init_thread_for_guile): Always init the key.
  (scm_i_with_guile_and_parent): No need for pthread_cancel cleanup
  handlers, as the pthread key destructor will take care of that for
  us.
  (really_launch): Remove needless pthread_exit call with incorrect
  comment.
---
 libguile/threads.c |   71 ++++++++++++++++++++++++++++-----------------------
 libguile/threads.h |    5 +++-
 2 files changed, 43 insertions(+), 33 deletions(-)

diff --git a/libguile/threads.c b/libguile/threads.c
index e7347ad..e2e17ac 100644
--- a/libguile/threads.c
+++ b/libguile/threads.c
@@ -343,6 +343,12 @@ unblock_from_queue (SCM queue)
 /* Getting into and out of guile mode.
  */
 
+/* Key used to attach a cleanup handler to a given thread.  Also, if
+   thread-local storage is unavailable, this key is used to retrieve the
+   current thread with `pthread_getspecific ()'.  */
+scm_i_pthread_key_t scm_i_thread_key;
+
+
 #ifdef SCM_HAVE_THREAD_STORAGE_CLASS
 
 /* When thread-local storage (TLS) is available, a pointer to the
@@ -352,17 +358,7 @@ unblock_from_queue (SCM queue)
    represent.  */
 SCM_THREAD_LOCAL scm_i_thread *scm_i_current_thread = NULL;
 
-# define SET_CURRENT_THREAD(_t)  scm_i_current_thread = (_t)
-
-#else /* !SCM_HAVE_THREAD_STORAGE_CLASS */
-
-/* Key used to retrieve the current thread with `pthread_getspecific ()'.  */
-scm_i_pthread_key_t scm_i_thread_key;
-
-# define SET_CURRENT_THREAD(_t)				\
-  scm_i_pthread_setspecific (scm_i_thread_key, (_t))
-
-#endif /* !SCM_HAVE_THREAD_STORAGE_CLASS */
+#endif /* SCM_HAVE_THREAD_STORAGE_CLASS */
 
 
 static scm_i_pthread_mutex_t thread_admin_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
@@ -428,7 +424,12 @@ guilify_self_1 (SCM_STACKITEM *base)
   t->exited = 0;
   t->guile_mode = 0;
 
-  SET_CURRENT_THREAD (t);
+  scm_i_pthread_setspecific (scm_i_thread_key, t);
+
+#ifdef SCM_HAVE_THREAD_STORAGE_CLASS
+  /* Cache the current thread in TLS for faster lookup.  */
+  scm_i_current_thread = t;
+#endif
 
   scm_i_pthread_mutex_lock (&thread_admin_mutex);
   t->next_thread = all_threads;
@@ -537,6 +538,22 @@ do_thread_exit (void *v)
   return NULL;
 }
 
+static void *
+do_thread_exit_trampoline (struct GC_stack_base *sb, void *v)
+{
+  void *ret;
+  int registered;
+
+  registered = GC_register_my_thread (sb);
+
+  ret = scm_with_guile (do_thread_exit, v);
+
+  if (registered == GC_SUCCESS)
+    GC_unregister_my_thread ();
+
+  return ret;
+}
+
 static void
 on_thread_exit (void *v)
 {
@@ -551,19 +568,20 @@ on_thread_exit (void *v)
       t->held_mutex = NULL;
     }
 
-  SET_CURRENT_THREAD (v);
+  /* Reinstate the current thread for purposes of scm_with_guile
+     guile-mode cleanup handlers.  Only really needed in the non-TLS
+     case but it doesn't hurt to be consistent.  */
+  scm_i_pthread_setspecific (scm_i_thread_key, t);
 
   /* Ensure the signal handling thread has been launched, because we might be
      shutting it down.  */
   scm_i_ensure_signal_delivery_thread ();
 
   /* Unblocking the joining threads needs to happen in guile mode
-     since the queue is a SCM data structure.  */
-
-  /* Note: Since `do_thread_exit ()' uses allocates memory via `libgc', we
-     assume the GC is usable at this point, and notably that thread-local
-     storage (TLS) hasn't been deallocated yet.  */
-  do_thread_exit (v);
+     since the queue is a SCM data structure.   Trampoline through
+     GC_call_with_stack_base so that the GC works even if it already
+     cleaned up for this thread.  */
+  GC_call_with_stack_base (do_thread_exit_trampoline, v);
 
   /* Removing ourself from the list of all threads needs to happen in
      non-guile mode since all SCM values on our stack become
@@ -590,21 +608,17 @@ on_thread_exit (void *v)
 
   scm_i_pthread_mutex_unlock (&thread_admin_mutex);
 
-  SET_CURRENT_THREAD (NULL);
+  scm_i_pthread_setspecific (scm_i_thread_key, NULL);
 }
 
-#ifndef SCM_HAVE_THREAD_STORAGE_CLASS
-
 static scm_i_pthread_once_t init_thread_key_once = SCM_I_PTHREAD_ONCE_INIT;
 
 static void
 init_thread_key (void)
 {
-  scm_i_pthread_key_create (&scm_i_thread_key, NULL);
+  scm_i_pthread_key_create (&scm_i_thread_key, on_thread_exit);
 }
 
-#endif
-
 /* Perform any initializations necessary to make the current thread
    known to Guile (via SCM_I_CURRENT_THREAD), initializing Guile itself,
    if necessary.
@@ -625,9 +639,7 @@ init_thread_key (void)
 static int
 scm_i_init_thread_for_guile (SCM_STACKITEM *base, SCM parent)
 {
-#ifndef SCM_HAVE_THREAD_STORAGE_CLASS
   scm_i_pthread_once (&init_thread_key_once, init_thread_key);
-#endif
 
   if (SCM_I_CURRENT_THREAD)
     {
@@ -790,9 +802,7 @@ scm_i_with_guile_and_parent (void *(*func)(void *), void *data, SCM parent)
       /* We are in Guile mode.  */
       assert (t->guile_mode);
 
-      scm_i_pthread_cleanup_push (scm_leave_guile_cleanup, NULL);
       res = scm_c_with_continuation_barrier (func, data);
-      scm_i_pthread_cleanup_pop (0);
 
       /* Leave Guile mode.  */
       t->guile_mode = 0;
@@ -880,9 +890,6 @@ really_launch (void *d)
   else
     t->result = scm_catch (SCM_BOOL_T, thunk, handler);
 
-  /* Trigger a call to `on_thread_exit ()'.  */
-  pthread_exit (NULL);
-
   return 0;
 }
 
diff --git a/libguile/threads.h b/libguile/threads.h
index b5e3c21..475af32 100644
--- a/libguile/threads.h
+++ b/libguile/threads.h
@@ -192,6 +192,10 @@ SCM_API void scm_dynwind_critical_section (SCM mutex);
 
 #ifdef BUILDING_LIBGUILE
 
+/* Though we don't need the key for SCM_I_CURRENT_THREAD if we have TLS,
+   we do use it for cleanup purposes.  */
+SCM_INTERNAL scm_i_pthread_key_t scm_i_thread_key;
+
 # ifdef SCM_HAVE_THREAD_STORAGE_CLASS
 
 SCM_INTERNAL SCM_THREAD_LOCAL scm_i_thread *scm_i_current_thread;
@@ -199,7 +203,6 @@ SCM_INTERNAL SCM_THREAD_LOCAL scm_i_thread *scm_i_current_thread;
 
 # else /* !SCM_HAVE_THREAD_STORAGE_CLASS */
 
-SCM_INTERNAL scm_i_pthread_key_t scm_i_thread_key;
 #  define SCM_I_CURRENT_THREAD						\
     ((scm_i_thread *) scm_i_pthread_getspecific (scm_i_thread_key))
 
-- 
1.7.3.4


[-- Attachment #3: Type: text/plain, Size: 25 bytes --]

-- 
http://wingolog.org/

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: Trouble joining with threads from C
  2011-03-18 12:23   ` Andy Wingo
@ 2011-03-20 23:11     ` Ludovic Courtès
  2011-04-13 21:25       ` Ludovic Courtès
  0 siblings, 1 reply; 12+ messages in thread
From: Ludovic Courtès @ 2011-03-20 23:11 UTC (permalink / raw)
  To: guile-devel

Hi!

Thanks for the brave threading debugging.  :-)

Andy Wingo <wingo@pobox.com> writes:

> No, the issue is elsewhere, that the thread-exit handlers were not being
> called

I just tried with 60582b7c2a495957012f9a20cd8691dc6307a850 and
‘on_thread_exit’ /is/ called after something like
‘(call-with-new-thread (lambda () #t))’.

Am I missing something?

> Would you mind submitting (and committing :) a test case?  Adding it to
> test-suite/standalone is probably the thing to do.

Yes, that’d be nice (even better in a single commit so we see the fix
and test are related.)

Thanks,
Ludo’.




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Trouble joining with threads from C
  2011-03-20 23:11     ` Ludovic Courtès
@ 2011-04-13 21:25       ` Ludovic Courtès
  2011-04-13 21:34         ` Ludovic Courtès
  0 siblings, 1 reply; 12+ messages in thread
From: Ludovic Courtès @ 2011-04-13 21:25 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 574 bytes --]

ludo@gnu.org (Ludovic Courtès) writes:

> Hi!

Howdy!

> Andy Wingo <wingo@pobox.com> writes:
>
>> No, the issue is elsewhere, that the thread-exit handlers were not being
>> called
>
> I just tried with 60582b7c2a495957012f9a20cd8691dc6307a850 and
> ‘on_thread_exit’ /is/ called after something like
> ‘(call-with-new-thread (lambda () #t))’.

The thread-exit handlers were not being called *for threads launched by
scm_spawn_thread*.

The patch below (against 60582b7c2a495957012f9a20cd8691dc6307a850) fixes it.

Now to see what's happened since then...

Ludo'.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: the patch --]
[-- Type: text/x-patch, Size: 2977 bytes --]

diff --git a/libguile/threads.c b/libguile/threads.c
index e7347ad..1c90517 100644
--- a/libguile/threads.c
+++ b/libguile/threads.c
@@ -980,7 +980,11 @@ spawn_thread (void *d)
 {
   spawn_data *data = (spawn_data *)d;
   scm_i_pthread_detach (scm_i_pthread_self ());
+
+  scm_i_pthread_cleanup_push (scm_leave_guile_cleanup, NULL);
   scm_i_with_guile_and_parent (really_spawn, d, data->parent);
+  scm_i_pthread_cleanup_pop (1);
+
   return NULL;
 }
 
diff --git a/test-suite/standalone/Makefile.am b/test-suite/standalone/Makefile.am
index b21edd2..b1f16f3 100644
--- a/test-suite/standalone/Makefile.am
+++ b/test-suite/standalone/Makefile.am
@@ -198,6 +198,11 @@ test_scm_with_guile_LDADD = $(LIBGUILE_LDADD)
 check_PROGRAMS += test-scm-with-guile
 TESTS += test-scm-with-guile
 
+test_scm_spawn_thread_CFLAGS = ${test_cflags}
+test_scm_spawn_thread_LDADD = $(LIBGUILE_LDADD)
+check_PROGRAMS += test-scm-spawn-thread
+TESTS += test-scm-spawn-thread
+
 else
 
 EXTRA_DIST += test-with-guile-module.c test-scm-with-guile.c
diff --git a/test-suite/standalone/test-scm-spawn-thread.c b/test-suite/standalone/test-scm-spawn-thread.c
new file mode 100644
index 0000000..b632ab0
--- /dev/null
+++ b/test-suite/standalone/test-scm-spawn-thread.c
@@ -0,0 +1,62 @@
+/* Copyright (C) 2011 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
+ */
+
+/* Test whether a thread created with `scm_spawn_thread' can be joined.
+   See <http://thread.gmane.org/gmane.lisp.guile.devel/11804> for the
+   original report.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libguile.h>
+
+#include <time.h>
+#include <stdlib.h>
+
+static SCM
+thread_main (void *data)
+{
+  return SCM_BOOL_T;
+}
+
+static SCM
+thread_handler (void *data, SCM key, SCM args)
+{
+  return SCM_BOOL_T;
+}
+
+static void *
+inner_main (void *data)
+{
+  SCM thread, timeout;
+
+  thread = scm_spawn_thread (thread_main, 0, thread_handler, 0);
+  timeout = scm_from_unsigned_integer (time (NULL) + 10);
+  return (void *) scm_join_thread_timed (thread, timeout, SCM_BOOL_F);
+}
+
+\f
+int
+main (int argc, char **argv)
+{
+  SCM result;
+
+  result = PTR2SCM (scm_with_guile (inner_main, 0));
+  return scm_is_true (result) ? EXIT_SUCCESS : EXIT_FAILURE;
+}

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: Trouble joining with threads from C
  2011-04-13 21:25       ` Ludovic Courtès
@ 2011-04-13 21:34         ` Ludovic Courtès
  2011-04-15  8:41           ` Andy Wingo
  0 siblings, 1 reply; 12+ messages in thread
From: Ludovic Courtès @ 2011-04-13 21:34 UTC (permalink / raw)
  To: guile-devel

Hello,

ludo@gnu.org (Ludovic Courtès) writes:

> ludo@gnu.org (Ludovic Courtès) writes:
>> Andy Wingo <wingo@pobox.com> writes:
>>
>>> No, the issue is elsewhere, that the thread-exit handlers were not being
>>> called
>>
>> I just tried with 60582b7c2a495957012f9a20cd8691dc6307a850 and
>> ‘on_thread_exit’ /is/ called after something like
>> ‘(call-with-new-thread (lambda () #t))’.
>
> The thread-exit handlers were not being called *for threads launched by
> scm_spawn_thread*.
>
> The patch below (against 60582b7c2a495957012f9a20cd8691dc6307a850) fixes it.

After reviewing f60a7648d5926555c7760364a6fbb7dc0cf60720 (which
addressed the same issue), I lean towards reverting it and instead
applying the patch I just sent.

The problem I see with f60a7648d5926555c7760364a6fbb7dc0cf60720 is that
it re-introduces a pthread_key, even when using TLS, and make things a
bit complex IMO.

Thoughts?

Besides, reverting it may fix --without-threads builds.

Thanks,
Ludo’.




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Trouble joining with threads from C
  2011-04-13 21:34         ` Ludovic Courtès
@ 2011-04-15  8:41           ` Andy Wingo
  2011-04-15 21:44             ` Ludovic Courtès
  2011-04-25 13:53             ` Ludovic Courtès
  0 siblings, 2 replies; 12+ messages in thread
From: Andy Wingo @ 2011-04-15  8:41 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-devel

Hi Ludovic,

On Wed 13 Apr 2011 23:34, ludo@gnu.org (Ludovic Courtès) writes:

> After reviewing f60a7648d5926555c7760364a6fbb7dc0cf60720 (which
> addressed the same issue), I lean towards reverting it and instead
> applying the patch I just sent.
>
> The problem I see with f60a7648d5926555c7760364a6fbb7dc0cf60720 is that
> it re-introduces a pthread_key, even when using TLS, and make things a
> bit complex IMO.

The issue is that threads in Guile are not always spawned by Guile.
It's true that of the two cases in which Guile spawned a thread, one of
them wasn't getting the cleanup handlers called, and your patch fixes
that; but that ignores the case of threads that are spawned by a user's
program.

For example in the following program:

    void* thread (void*)
    {
      scm_with_guile (do_something, NULL);
      scm_with_guile (do_something_else, NULL);
      return NULL;
    }

    int main ()
    {
      pthread_t thr;
      pthread_create (&thr, NULL, thread, NULL);
      pthread_join (thr, NULL);
      return 0;
    }

When do you propose that the cleanup handlers for the thread be called?

As far as I understand things, reliably cleaning up after the thread
*requires* the use of pthread_key with a destructor.  It is the only way
to attach a cleanup callback to a thread.  It's true that the key is not
used when TLS is available, except for its destructor capabilities, but
it is not more complicated than before.

I think they context that you are missing here is bug 32436.

It does appear that I have introduced some bugs here: Mark's
after-gc-hook not being called, and a failure to build
--without-threads.  For that I apologize.  But these bugs are fixable.
Consider bug 32436 for a moment: you can't fix that with
pthread_cleanup_push.

Does this explanation help?

Let me know,

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Trouble joining with threads from C
  2011-04-15  8:41           ` Andy Wingo
@ 2011-04-15 21:44             ` Ludovic Courtès
  2011-04-16 15:55               ` Andy Wingo
  2011-04-25 13:53             ` Ludovic Courtès
  1 sibling, 1 reply; 12+ messages in thread
From: Ludovic Courtès @ 2011-04-15 21:44 UTC (permalink / raw)
  To: Andy Wingo; +Cc: guile-devel

Hi Andy!

Thanks for your explanations.

Andy Wingo <wingo@pobox.com> writes:

> On Wed 13 Apr 2011 23:34, ludo@gnu.org (Ludovic Courtès) writes:
>
>> After reviewing f60a7648d5926555c7760364a6fbb7dc0cf60720 (which
>> addressed the same issue), I lean towards reverting it and instead
>> applying the patch I just sent.
>>
>> The problem I see with f60a7648d5926555c7760364a6fbb7dc0cf60720 is that
>> it re-introduces a pthread_key, even when using TLS, and make things a
>> bit complex IMO.
>
> The issue is that threads in Guile are not always spawned by Guile.
> It's true that of the two cases in which Guile spawned a thread, one of
> them wasn't getting the cleanup handlers called, and your patch fixes
> that; but that ignores the case of threads that are spawned by a user's
> program.

Right, I was just focusing on Mark’s case, blissfully ignoring #32436.

> For example in the following program:
>
>     void* thread (void*)
>     {
>       scm_with_guile (do_something, NULL);
>       scm_with_guile (do_something_else, NULL);
>       return NULL;
>     }
>
>     int main ()
>     {
>       pthread_t thr;
>       pthread_create (&thr, NULL, thread, NULL);
>       pthread_join (thr, NULL);
>       return 0;
>     }
>
> When do you propose that the cleanup handlers for the thread be called?

I’ll followup on this later, but currently it seems impossible to call
GC_INIT from a thread other than the initial thread [0].

Thanks,
Ludo’.

[0] http://article.gmane.org/gmane.comp.programming.garbage-collection.boehmgc/4490



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Trouble joining with threads from C
  2011-04-15 21:44             ` Ludovic Courtès
@ 2011-04-16 15:55               ` Andy Wingo
  0 siblings, 0 replies; 12+ messages in thread
From: Andy Wingo @ 2011-04-16 15:55 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-devel

Heya Ludo,

On Fri 15 Apr 2011 23:44, ludo@gnu.org (Ludovic Courtès) writes:

>> For example in the following program:
>>
>>     void* thread (void*)
>>     {
>>       scm_with_guile (do_something, NULL);
>>       scm_with_guile (do_something_else, NULL);
>>       return NULL;
>>     }
>>
>>     int main ()
>>     {
>>       pthread_t thr;
>>       pthread_create (&thr, NULL, thread, NULL);
>>       pthread_join (thr, NULL);
>>       return 0;
>>     }
>>
>> When do you propose that the cleanup handlers for the thread be called?
>
> I’ll followup on this later, but currently it seems impossible to call
> GC_INIT from a thread other than the initial thread [0].

Interesting; I had it working at some point, in the context of that
other bug;  anyway, the same considerations hold if you scm_init_guile
in the main thread first.

Cheers,

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Trouble joining with threads from C
  2011-04-15  8:41           ` Andy Wingo
  2011-04-15 21:44             ` Ludovic Courtès
@ 2011-04-25 13:53             ` Ludovic Courtès
  2011-04-25 14:19               ` Andy Wingo
  1 sibling, 1 reply; 12+ messages in thread
From: Ludovic Courtès @ 2011-04-25 13:53 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 6853 bytes --]

Hello!

Andy Wingo <wingo@pobox.com> writes:

> When do you propose that the cleanup handlers for the thread be called?
>
> As far as I understand things, reliably cleaning up after the thread
> *requires* the use of pthread_key with a destructor.  It is the only way
> to attach a cleanup callback to a thread.  It's true that the key is not
> used when TLS is available, except for its destructor capabilities, but
> it is not more complicated than before.
>
> I think they context that you are missing here is bug 32436.
>
> It does appear that I have introduced some bugs here: Mark's
> after-gc-hook not being called, and a failure to build
> --without-threads.  For that I apologize.  But these bugs are fixable.
> Consider bug 32436 for a moment: you can't fix that with
> pthread_cleanup_push.

Attached are 3 tests: one for Mark’s bug, and two for #32436.

Currently they all pass, but ‘test-scm-spawn-thread’ hits a libgc
assertion failure (“Duplicate large block deallocation”) once every 5
runs or so:

--8<---------------cut here---------------start------------->8---
(gdb) thread apply all bt

Thread 3 (Thread 0x7ffff582e700 (LWP 15207)):
#0  0x00007ffff62b220b in memset () from /nix/store/vxycd107wjbhcj720hzkw2px7s7kr724-glibc-2.12.2/lib/libc.so.6
#1  0x00007ffff6e8c6d8 in GC_generic_malloc (lb=524288, k=<value optimized out>) at ../malloc.c:193
#2  0x00007ffff7b36aad in make_vm () at vm.c:501
#3  0x00007ffff7b36b8e in scm_the_vm () at vm.c:578
#4  0x00007ffff7ac3190 in scm_call_4 (proc=0x778ab0, arg1=<value optimized out>, arg2=<value optimized out>, arg3=<value optimized out>, arg4=<value optimized out>) at eval.c:476
#5  0x00007ffff7aba283 in scm_i_with_continuation_barrier (body=0x7ffff7ab9a90 <c_body>, body_data=0x7ffff582dd80, handler=0x7ffff7ab9e60 <c_handler>, handler_data=0x7ffff582dd80,
    pre_unwind_handler=<value optimized out>, pre_unwind_handler_data=<value optimized out>) at continuations.c:450
#6  0x00007ffff7aba335 in scm_c_with_continuation_barrier (func=<value optimized out>, data=<value optimized out>) at continuations.c:546
#7  0x00007ffff7b3146a in with_guile_and_parent (base=0x7ffff582dde0, data=0x7ffff582de00) at threads.c:856
#8  0x00007ffff6e916b5 in GC_call_with_stack_base (fn=<value optimized out>, arg=<value optimized out>) at ../misc.c:1505
#9  0x00007ffff7b3109c in scm_i_with_guile_and_parent (d=<value optimized out>) at threads.c:899
#10 spawn_thread (d=<value optimized out>) at threads.c:1056
#11 0x00007ffff6e96791 in GC_inner_start_routine (sb=<value optimized out>, arg=<value optimized out>) at ../pthread_start.c:61
#12 0x00007ffff6e916b5 in GC_call_with_stack_base (fn=<value optimized out>, arg=<value optimized out>) at ../misc.c:1505
#13 0x00007ffff6c61cec in start_thread () from /nix/store/vxycd107wjbhcj720hzkw2px7s7kr724-glibc-2.12.2/lib/libpthread.so.0
#14 0x00007ffff63041ed in clone () from /nix/store/vxycd107wjbhcj720hzkw2px7s7kr724-glibc-2.12.2/lib/libc.so.6

Thread 2 (Thread 0x7ffff602f700 (LWP 15206)):
#0  0x00007ffff626585e in raise () from /nix/store/vxycd107wjbhcj720hzkw2px7s7kr724-glibc-2.12.2/lib/libc.so.6
#1  0x00007ffff6266d16 in abort () from /nix/store/vxycd107wjbhcj720hzkw2px7s7kr724-glibc-2.12.2/lib/libc.so.6
#2  0x00007ffff6e90d9f in GC_abort (msg=0x7ffff6e98b50 "Duplicate large block deallocation") at ../misc.c:1409
#3  0x00007ffff6e85b3c in GC_freehblk (hbp=0x980000) at ../allchblk.c:852
#4  0x00007ffff6e977cb in GC_pthread_create (new_thread=0x7ffff602ee38, attr=0x0, start_routine=0x7ffff7b31060 <spawn_thread>, arg=0x7ffff602edb0) at ../pthread_support.c:1552
#5  0x00007ffff7b31cbc in scm_spawn_thread (body=<value optimized out>, body_data=<value optimized out>, handler=0x7ffff7b33f20 <scm_handle_by_message>, handler_data=0x7ffff7b72868) at threads.c:1078
#6  0x00007ffff7b0e1cc in start_signal_delivery_thread () at scmsigs.c:193
#7  0x00007ffff6c67c83 in pthread_once () from /nix/store/vxycd107wjbhcj720hzkw2px7s7kr724-glibc-2.12.2/lib/libpthread.so.0
#8  0x00007ffff7b3115d in on_thread_exit (v=0x96a600) at threads.c:692
#9  0x00007ffff6c61b29 in __nptl_deallocate_tsd () from /nix/store/vxycd107wjbhcj720hzkw2px7s7kr724-glibc-2.12.2/lib/libpthread.so.0
#10 0x00007ffff6c61cfa in start_thread () from /nix/store/vxycd107wjbhcj720hzkw2px7s7kr724-glibc-2.12.2/lib/libpthread.so.0
#11 0x00007ffff63041ed in clone () from /nix/store/vxycd107wjbhcj720hzkw2px7s7kr724-glibc-2.12.2/lib/libc.so.6

Thread 1 (Thread 0x7ffff7ff3700 (LWP 15205)):
#0  0x00007ffff6c6692b in pthread_cond_timedwait@@GLIBC_2.3.2 () from /nix/store/vxycd107wjbhcj720hzkw2px7s7kr724-glibc-2.12.2/lib/libpthread.so.0
#1  0x00007ffff7b31e76 in scm_pthread_cond_timedwait (cond=0x662e88, mutex=0x96a628, wt=0x7fffffffcca0) at threads.c:1916
#2  0x00007ffff7b31fca in block_self (queue=0x981fc0, sleep_object=<value optimized out>, mutex=0x96a628, waittime=0x7fffffffcca0) at threads.c:431
#3  0x00007ffff7b321f9 in scm_join_thread_timed (thread=0x981ff0, timeout=<value optimized out>, timeoutval=<value optimized out>) at threads.c:1205
#4  0x00007ffff7ab9a9a in c_body (d=0x7fffffffcf30) at continuations.c:512
#5  0x00007ffff7b497b0 in vm_regular_engine (vm=0x6f38c0, program=0x7ffff7b72f72, argv=0x6f70a8, nargs=1) at vm-i-system.c:956
#6  0x00007ffff7ac31a3 in scm_call_4 (proc=0x778ab0, arg1=<value optimized out>, arg2=<value optimized out>, arg3=<value optimized out>, arg4=<value optimized out>) at eval.c:476
#7  0x00007ffff7aba283 in scm_i_with_continuation_barrier (body=0x7ffff7ab9a90 <c_body>, body_data=0x7fffffffcf30, handler=0x7ffff7ab9e60 <c_handler>, handler_data=0x7fffffffcf30,
    pre_unwind_handler=<value optimized out>, pre_unwind_handler_data=<value optimized out>) at continuations.c:450
#8  0x00007ffff7aba335 in scm_c_with_continuation_barrier (func=<value optimized out>, data=<value optimized out>) at continuations.c:546
#9  0x00007ffff7b3146a in with_guile_and_parent (base=0x7fffffffcf90, data=0x7fffffffcfb0) at threads.c:856
#10 0x00007ffff6e916b5 in GC_call_with_stack_base (fn=<value optimized out>, arg=<value optimized out>) at ../misc.c:1505
#11 0x00007ffff7b31598 in scm_i_with_guile_and_parent (func=<value optimized out>, data=<value optimized out>) at threads.c:899
#12 scm_with_guile (func=<value optimized out>, data=<value optimized out>) at threads.c:905
#13 0x00000000004008c0 in main (argc=<value optimized out>, argv=<value optimized out>) at test-scm-spawn-thread.c:60
--8<---------------cut here---------------end--------------->8---

This happens when calling ‘GC_pthread_create’ from a pthread key
destructor, which appears to be problematic [0].

I haven’t been able to fix it or otherwise work around it though, so
help welcome!  :-)

I think this is not a showstopper for 2.0.1.

Thanks,
Ludo’.

[0] http://thread.gmane.org/gmane.comp.programming.garbage-collection.boehmgc/4502


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: the tests --]
[-- Type: text/x-patch, Size: 8887 bytes --]

From 257ee9f4449c82c4cf9d3cd9951e48df549667fb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= <ludo@gnu.org>
Date: Fri, 22 Apr 2011 12:29:50 +0200
Subject: [PATCH] Add pthread-related tests.

* test-suite/standalone/Makefile.am (test_scm_spawn_thread_CFLAGS,
  test_scm_spawn_thread_LDADD, test_pthread_create_CFLAGS,
  test_pthread_create_LDADD, test_pthread_create_secondary_CFLAGS,
  test_pthread_create_secondary_LDADD): New variables.
  (check_PROGRAMS)[BUILD_PTHREAD_SUPPORT]: Add `test-scm-spawn-thread',
  `test-pthread_create', `test-pthread_create-secondary'.
  (TESTS)[BUILD_PTHREAD_SUPPORT]: Likewise.

* test-suite/standalone/test-scm-spawn-thread.c,
  test-suite/standalone/test-pthread-create.c,
  test-suite/standalone/test-pthread-create-secondary.c: New files.
---
 .gitignore                                         |    3 +
 test-suite/standalone/Makefile.am                  |   15 ++++
 .../standalone/test-pthread-create-secondary.c     |   85 ++++++++++++++++++++
 test-suite/standalone/test-pthread-create.c        |   63 +++++++++++++++
 test-suite/standalone/test-scm-spawn-thread.c      |   62 ++++++++++++++
 5 files changed, 228 insertions(+), 0 deletions(-)
 create mode 100644 test-suite/standalone/test-pthread-create-secondary.c
 create mode 100644 test-suite/standalone/test-pthread-create.c
 create mode 100644 test-suite/standalone/test-scm-spawn-thread.c

diff --git a/.gitignore b/.gitignore
index f24e589..a0eeeca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -139,3 +139,6 @@ INSTALL
 /.sc-start-*
 /lib/math.h
 /lib/sys/time.h
+/test-suite/standalone/test-scm-spawn-thread
+/test-suite/standalone/test-pthread-create
+/test-suite/standalone/test-pthread-create-secondary
diff --git a/test-suite/standalone/Makefile.am b/test-suite/standalone/Makefile.am
index b21edd2..cf1fc4f 100644
--- a/test-suite/standalone/Makefile.am
+++ b/test-suite/standalone/Makefile.am
@@ -198,6 +198,21 @@ test_scm_with_guile_LDADD = $(LIBGUILE_LDADD)
 check_PROGRAMS += test-scm-with-guile
 TESTS += test-scm-with-guile
 
+test_scm_spawn_thread_CFLAGS = ${test_cflags}
+test_scm_spawn_thread_LDADD = $(LIBGUILE_LDADD)
+check_PROGRAMS += test-scm-spawn-thread
+TESTS += test-scm-spawn-thread
+
+test_pthread_create_CFLAGS = ${test_cflags}
+test_pthread_create_LDADD = $(LIBGUILE_LDADD)
+check_PROGRAMS += test-pthread-create
+TESTS += test-pthread-create
+
+test_pthread_create_secondary_CFLAGS = ${test_cflags} $(BDW_GC_CFLAGS)
+test_pthread_create_secondary_LDADD = $(LIBGUILE_LDADD)
+check_PROGRAMS += test-pthread-create-secondary
+TESTS += test-pthread-create-secondary
+
 else
 
 EXTRA_DIST += test-with-guile-module.c test-scm-with-guile.c
diff --git a/test-suite/standalone/test-pthread-create-secondary.c b/test-suite/standalone/test-pthread-create-secondary.c
new file mode 100644
index 0000000..fe39c2a
--- /dev/null
+++ b/test-suite/standalone/test-pthread-create-secondary.c
@@ -0,0 +1,85 @@
+/* Copyright (C) 2011 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
+ */
+
+/* Test whether threads created with `pthread_create' work, and whether
+   a secondary thread can call `scm_with_guile'. (bug #32436).  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <libguile.h>
+
+#include <gc/gc_version.h>
+
+
+/* Up to GC 7.2alpha5, calling `GC_INIT' from a secondary thread would
+   lead to a segfault.  This was fixed in BDW-GC on 2011-04-16 by Ivan
+   Maidanski.  See <http://thread.gmane.org/gmane.lisp.guile.bugs/5340>
+   for details.  */
+
+#if (GC_VERSION_MAJOR > 7)					\
+  || ((GC_VERSION_MAJOR == 7) && (GC_VERSION_MINOR > 2))	\
+  || ((GC_VERSION_MAJOR == 7) && (GC_VERSION_MINOR == 2)	\
+      && (GC_ALPHA_VERSION > 5))
+
+static void *
+do_something (void *arg)
+{
+  scm_list_copy (scm_make_list (scm_from_int (1234), SCM_BOOL_T));
+  scm_gc ();
+  return NULL;
+}
+
+static void *
+thread (void *arg)
+{
+  scm_with_guile (do_something, NULL);
+  return NULL;
+}
+
+\f
+int
+main (int argc, char *argv[])
+{
+  int i;
+
+  for (i = 0; i < 77; i++)
+    {
+      pthread_t thr;
+
+      pthread_create (&thr, NULL, thread, NULL);
+      pthread_join (thr, NULL);
+    }
+
+  return EXIT_SUCCESS;
+}
+
+\f
+#else /* GC < 7.2 */
+
+int
+main (int argc, char *argv[])
+{
+  /* Skip.  */
+  return 77;
+}
+
+#endif /* GC < 7.2 */
diff --git a/test-suite/standalone/test-pthread-create.c b/test-suite/standalone/test-pthread-create.c
new file mode 100644
index 0000000..8d9617b
--- /dev/null
+++ b/test-suite/standalone/test-pthread-create.c
@@ -0,0 +1,63 @@
+/* Copyright (C) 2011 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
+ */
+
+/* Test whether threads created with `pthread_create' work (bug #32436)
+   when then main thread is the one that initializes Guile.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <libguile.h>
+
+static void *
+do_something (void *arg)
+{
+  scm_list_copy (scm_make_list (scm_from_int (1234), SCM_BOOL_T));
+  scm_gc ();
+  return NULL;
+}
+
+static void *
+thread (void *arg)
+{
+  scm_with_guile (do_something, NULL);
+  return NULL;
+}
+
+\f
+int
+main (int argc, char *argv[])
+{
+  int i;
+  pthread_t thr;
+
+  scm_init_guile ();
+
+  do_something (NULL);
+
+  for (i = 0; i < 77; i++)
+    {
+      pthread_create (&thr, NULL, thread, NULL);
+      pthread_join (thr, NULL);
+    }
+
+  return EXIT_SUCCESS;
+}
diff --git a/test-suite/standalone/test-scm-spawn-thread.c b/test-suite/standalone/test-scm-spawn-thread.c
new file mode 100644
index 0000000..b632ab0
--- /dev/null
+++ b/test-suite/standalone/test-scm-spawn-thread.c
@@ -0,0 +1,62 @@
+/* Copyright (C) 2011 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
+ */
+
+/* Test whether a thread created with `scm_spawn_thread' can be joined.
+   See <http://thread.gmane.org/gmane.lisp.guile.devel/11804> for the
+   original report.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libguile.h>
+
+#include <time.h>
+#include <stdlib.h>
+
+static SCM
+thread_main (void *data)
+{
+  return SCM_BOOL_T;
+}
+
+static SCM
+thread_handler (void *data, SCM key, SCM args)
+{
+  return SCM_BOOL_T;
+}
+
+static void *
+inner_main (void *data)
+{
+  SCM thread, timeout;
+
+  thread = scm_spawn_thread (thread_main, 0, thread_handler, 0);
+  timeout = scm_from_unsigned_integer (time (NULL) + 10);
+  return (void *) scm_join_thread_timed (thread, timeout, SCM_BOOL_F);
+}
+
+\f
+int
+main (int argc, char **argv)
+{
+  SCM result;
+
+  result = PTR2SCM (scm_with_guile (inner_main, 0));
+  return scm_is_true (result) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: Trouble joining with threads from C
  2011-04-25 13:53             ` Ludovic Courtès
@ 2011-04-25 14:19               ` Andy Wingo
  2011-04-25 14:49                 ` Ludovic Courtès
  0 siblings, 1 reply; 12+ messages in thread
From: Andy Wingo @ 2011-04-25 14:19 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-devel

On Mon 25 Apr 2011 15:53, ludo@gnu.org (Ludovic Courtès) writes:

> Attached are 3 tests: one for Mark’s bug, and two for #32436.

o/~ did you ever know that you're my heeee-roooo o/~

> Currently they all pass, but ‘test-scm-spawn-thread’ hits a libgc
> assertion failure (“Duplicate large block deallocation”) once every 5
> runs or so:

I guess we disable this one then?

That code always seemed a little fishy to me:

  /* Ensure the signal handling thread has been launched, because we might be
     shutting it down.  */
  scm_i_ensure_signal_delivery_thread ();

Perhaps we can avoid spawning a thread in the key destructor.

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Trouble joining with threads from C
  2011-04-25 14:19               ` Andy Wingo
@ 2011-04-25 14:49                 ` Ludovic Courtès
  0 siblings, 0 replies; 12+ messages in thread
From: Ludovic Courtès @ 2011-04-25 14:49 UTC (permalink / raw)
  To: Andy Wingo; +Cc: guile-devel

Hello!

Andy Wingo <wingo@pobox.com> writes:

> On Mon 25 Apr 2011 15:53, ludo@gnu.org (Ludovic Courtès) writes:

[...]

>> Currently they all pass, but ‘test-scm-spawn-thread’ hits a libgc
>> assertion failure (“Duplicate large block deallocation”) once every 5
>> runs or so:
>
> I guess we disable this one then?
>
> That code always seemed a little fishy to me:
>
>   /* Ensure the signal handling thread has been launched, because we might be
>      shutting it down.  */
>   scm_i_ensure_signal_delivery_thread ();
>
> Perhaps we can avoid spawning a thread in the key destructor.

I apparently found a fix: calling ‘scm_i_ensure_signal_delivery_thread’
in Guile mode.

I *think* the stack of ‘GC_pthread_create’ wasn’t scanned, so the area
pointed to by its variable ‘si’ would be reclaimed before the function
completes, leading to the “duplicate deallocation” error.

Pfffeww.

Thanks,
Ludo’.



^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2011-04-25 14:49 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-03-07  5:56 Trouble joining with threads from C Mark H Weaver
2011-03-09  6:48 ` Mark H Weaver
2011-03-18 12:23   ` Andy Wingo
2011-03-20 23:11     ` Ludovic Courtès
2011-04-13 21:25       ` Ludovic Courtès
2011-04-13 21:34         ` Ludovic Courtès
2011-04-15  8:41           ` Andy Wingo
2011-04-15 21:44             ` Ludovic Courtès
2011-04-16 15:55               ` Andy Wingo
2011-04-25 13:53             ` Ludovic Courtès
2011-04-25 14:19               ` Andy Wingo
2011-04-25 14:49                 ` Ludovic Courtès

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).