guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] GNU Guile branch, master, updated. v2.1.0-64-geaf9998


From: Andy Wingo
Subject: [Guile-commits] GNU Guile branch, master, updated. v2.1.0-64-geaf9998
Date: Fri, 24 Feb 2012 12:33:51 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Guile".

http://git.savannah.gnu.org/cgit/guile.git/commit/?id=eaf99988aecdcacd9204f61ba1d307584300f751

The branch, master has been updated
       via  eaf99988aecdcacd9204f61ba1d307584300f751 (commit)
       via  415e00fc57e6d734d90b3a7e2324437ccdf406a7 (commit)
      from  508e4a55df353ec50f005307eb98557c7da79c82 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit eaf99988aecdcacd9204f61ba1d307584300f751
Author: Andy Wingo <address@hidden>
Date:   Fri Feb 24 13:18:48 2012 +0100

    run finalizers asynchronously (in asyncs and/or pthreads)
    
    * libguile/finalizers.c: New excitement!  We'll be running finalizers in
      threads, if that's available.  If it's not available, during early
      boot, we can run finalizers in asyncs.  This will make it safer to
      allocate while holding a mutex.
    
    * libguile/posix.c (scm_fork): Shut down the finalizer thread before
      forking.
    
    * libguile/init.c (scm_i_init_guile): Init the async finalizer mechanism
      during boot and, if available, initialialize the finalizer thread at
      the very end.
    
    * libguile/gc.c (scm_storage_prehistory): Tell libgc we'll be finalizing
      on demand.
      (scm_gc): Explicitly run finalizers here.  If you're calling this
      function, you probably want synchronous GC.

commit 415e00fc57e6d734d90b3a7e2324437ccdf406a7
Author: Andy Wingo <address@hidden>
Date:   Fri Feb 24 11:20:21 2012 +0100

    signal an error on multithreaded fork
    
    * libguile/posix.c (scm_fork): Signal an error if a `fork' is attempted
      after threads have been spawned.
    
    * test-suite/tests/00-socket.test: Moved here, from socket.test, so as
      to run before any threads are created.
    * test-suite/Makefile.am: Adapt.

-----------------------------------------------------------------------

Summary of changes:
 libguile/finalizers.c                            |  178 ++++++++++++++++++++++
 libguile/finalizers.h                            |    3 +
 libguile/gc.c                                    |    4 +-
 libguile/init.c                                  |    5 +
 libguile/posix.c                                 |   15 ++-
 test-suite/Makefile.am                           |    4 +-
 test-suite/tests/{socket.test => 00-socket.test} |    7 +-
 7 files changed, 210 insertions(+), 6 deletions(-)
 rename test-suite/tests/{socket.test => 00-socket.test} (98%)

diff --git a/libguile/finalizers.c b/libguile/finalizers.c
index 8b4178f..cabfa2c 100644
--- a/libguile/finalizers.c
+++ b/libguile/finalizers.c
@@ -23,6 +23,13 @@
 # include <config.h>
 #endif
 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+
+#include <full-write.h>
+
 #include "libguile/bdw-gc.h"
 #include "libguile/_scm.h"
 #include "libguile/finalizers.h"
@@ -31,6 +38,11 @@
 
 
 
+static size_t finalization_count;
+
+
+
+
 void
 scm_i_set_finalizer (void *obj, scm_t_finalizer_proc proc, void *data)
 {
@@ -117,10 +129,176 @@ scm_i_add_finalizer (void *obj, scm_t_finalizer_proc 
proc, void *data)
   shuffle_resuscitators_to_front (chained_data);
 }
 
+
 
 
+static SCM finalizer_async_cell;
+
+static SCM
+run_finalizers_async_thunk (void)
+{
+  finalization_count += GC_invoke_finalizers ();
+  return SCM_UNSPECIFIED;
+}
+
+
+/* The function queue_after_gc_hook is run by the scm_before_gc_c_hook
+ * at the end of the garbage collection.  The only purpose of this
+ * function is to mark the after_gc_async (which will eventually lead to
+ * the execution of the after_gc_async_thunk).
+ */
+static void
+queue_finalizer_async (void)
+{
+  scm_i_thread *t = SCM_I_CURRENT_THREAD;
+  static scm_i_pthread_mutex_t lock = SCM_I_PTHREAD_MUTEX_INITIALIZER;
+
+  scm_i_pthread_mutex_lock (&lock);
+  if (scm_is_false (SCM_CDR (finalizer_async_cell)))
+    {
+      SCM_SETCDR (finalizer_async_cell, t->active_asyncs);
+      t->active_asyncs = finalizer_async_cell;
+      t->pending_asyncs = 1;
+    }
+  scm_i_pthread_mutex_unlock (&lock);
+}
+
+
+
+
+#if SCM_USE_PTHREAD_THREADS
+
+static int finalization_pipe[2];
+static scm_i_pthread_mutex_t finalization_thread_lock =
+  SCM_I_PTHREAD_MUTEX_INITIALIZER;
+static SCM finalization_thread = SCM_BOOL_F;
+
+static void
+notify_finalizers_to_run (void)
+{
+  char byte = 0;
+  full_write (finalization_pipe[1], &byte, 1);
+}
+
+static void
+notify_about_to_fork (void)
+{
+  char byte = 1;
+  full_write (finalization_pipe[1], &byte, 1);
+}
+
+struct finalization_pipe_data
+{
+  char byte;
+  ssize_t n;
+  int err;
+};
+
+static void*
+read_finalization_pipe_data (void *data)
+{
+  struct finalization_pipe_data *fdata = data;
+  
+  fdata->n = read (finalization_pipe[0], &fdata->byte, 1);
+  fdata->err = errno;
+
+  return NULL;
+}
+  
+static SCM
+finalization_thread_proc (void *unused)
+{
+  while (1)
+    {
+      struct finalization_pipe_data data;
+
+      scm_without_guile (read_finalization_pipe_data, &data);
+      
+      if (data.n <= 0 && data.err != EINTR) 
+        {
+          perror ("error in finalization delivery thread");
+          return SCM_UNSPECIFIED;
+        }
+
+      switch (data.byte)
+        {
+        case 0:
+          finalization_count += GC_invoke_finalizers ();
+          break;
+        case 1:
+          return SCM_UNSPECIFIED;
+        default:
+          abort ();
+        }
+    }
+}
+
+static void
+start_finalization_thread (void)
+{
+  scm_i_pthread_mutex_lock (&finalization_thread_lock);
+  if (scm_is_false (finalization_thread))
+    finalization_thread = scm_spawn_thread (finalization_thread_proc, NULL,
+                                            scm_handle_by_message,
+                                            "finalization thread");
+  scm_i_pthread_mutex_unlock (&finalization_thread_lock);
+}
+
+static void
+stop_finalization_thread (void)
+{
+  scm_i_pthread_mutex_lock (&finalization_thread_lock);
+  if (scm_is_true (finalization_thread))
+    {
+      notify_about_to_fork ();
+      scm_join_thread (finalization_thread);
+      finalization_thread = SCM_BOOL_F;
+    }
+  scm_i_pthread_mutex_unlock (&finalization_thread_lock);
+}
+
+static void
+spawn_finalizer_thread (void)
+{
+  GC_set_finalizer_notifier (notify_finalizers_to_run);
+  start_finalization_thread ();
+}
+
+#endif /* SCM_USE_PTHREAD_THREADS */
+
+
+
+
+void
+scm_i_finalizer_pre_fork (void)
+{
+#if SCM_USE_PTHREAD_THREADS
+  stop_finalization_thread ();
+  GC_set_finalizer_notifier (spawn_finalizer_thread);
+#endif
+}
+
+
+
 
 void
 scm_init_finalizers (void)
 {
+  /* When the async is to run, the cdr of the pair gets set to the
+     asyncs queue of the current thread.  */
+  finalizer_async_cell =
+    scm_cons (scm_c_make_gsubr ("%run-finalizers", 0, 0, 0,
+                                run_finalizers_async_thunk),
+              SCM_BOOL_F);
+  GC_set_finalizer_notifier (queue_finalizer_async);
+}
+
+void
+scm_init_finalizer_thread (void)
+{
+#if SCM_USE_PTHREAD_THREADS
+  if (pipe2 (finalization_pipe, O_CLOEXEC) != 0)
+    scm_syserror (NULL);
+  GC_set_finalizer_notifier (spawn_finalizer_thread);
+#endif
 }
diff --git a/libguile/finalizers.h b/libguile/finalizers.h
index bad96e1..ad14d94 100644
--- a/libguile/finalizers.h
+++ b/libguile/finalizers.h
@@ -34,6 +34,9 @@ SCM_INTERNAL void scm_i_add_finalizer (void *obj, 
scm_t_finalizer_proc,
 SCM_INTERNAL void scm_i_add_resuscitator (void *obj, scm_t_finalizer_proc,
                                           void *data);
 
+SCM_INTERNAL void scm_i_finalizer_pre_fork (void);
+
 SCM_INTERNAL void scm_init_finalizers (void);
+SCM_INTERNAL void scm_init_finalizer_thread (void);
 
 #endif  /* SCM_FINALIZERS_H */
diff --git a/libguile/gc.c b/libguile/gc.c
index 6d44f5e..b33fb0c 100644
--- a/libguile/gc.c
+++ b/libguile/gc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2006, 2008, 
2009, 2010, 2011 Free Software Foundation, Inc.
+/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2006, 2008, 
2009, 2010, 2011, 2012 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
@@ -384,6 +384,7 @@ SCM_DEFINE (scm_gc, "gc", 0, 0, 0,
 #define FUNC_NAME s_scm_gc
 {
   scm_i_gc ("call");
+  GC_invoke_finalizers ();
   return SCM_UNSPECIFIED;
 }
 #undef FUNC_NAME
@@ -616,6 +617,7 @@ scm_storage_prehistory ()
   minimum_free_space_divisor = free_space_divisor;
   target_free_space_divisor = free_space_divisor;
   GC_set_free_space_divisor (free_space_divisor);
+  GC_set_finalize_on_demand (1);
 
   GC_INIT ();
 
diff --git a/libguile/init.c b/libguile/init.c
index dc3f5ec..90b01ee 100644
--- a/libguile/init.c
+++ b/libguile/init.c
@@ -59,6 +59,7 @@
 #include "libguile/expand.h"
 #include "libguile/feature.h"
 #include "libguile/filesys.h"
+#include "libguile/finalizers.h"
 #include "libguile/fluids.h"
 #include "libguile/fports.h"
 #include "libguile/frames.h"
@@ -421,6 +422,7 @@ scm_i_init_guile (void *base)
   scm_init_dynwind ();            /* requires smob_prehistory */
   scm_init_eq ();
   scm_init_error ();
+  scm_init_finalizers ();
   scm_init_fluids ();
   scm_init_control ();            /* requires fluids */
   scm_init_feature ();
@@ -529,6 +531,9 @@ scm_i_init_guile (void *base)
   /* Capture the dynamic state after loading boot-9, so that new threads end up
      in the guile-user module. */
   scm_init_threads_default_dynamic_state ();
+
+  /* Finally, cause finalizers to run in a separate thread.  */
+  scm_init_finalizer_thread ();
 }
 
 /*
diff --git a/libguile/posix.c b/libguile/posix.c
index 4f8b8ac..25476e5 100644
--- a/libguile/posix.c
+++ b/libguile/posix.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2004, 2005, 
2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2004, 2005, 
2006, 2007, 2008, 2009, 2010, 2011, 2012 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
@@ -1248,6 +1248,19 @@ SCM_DEFINE (scm_fork, "primitive-fork", 0, 0, 0,
 #define FUNC_NAME s_scm_fork
 {
   int pid;
+  scm_i_finalizer_pre_fork ();
+  if (scm_ilength (scm_all_threads ()) != 1)
+    /* Other threads may be holding on to resources that Guile needs --
+       it is not safe to permit one thread to fork while others are
+       running.
+
+       In addition, POSIX clearly specifies that if a multi-threaded
+       program forks, the child must only call functions that are
+       async-signal-safe.  We can't guarantee that in general.  The best
+       we can do is to allow forking only very early, before any call to
+       sigaction spawns the signal-handling thread.  */
+    SCM_MISC_ERROR ("attempt to fork while multiple threads are running",
+                    SCM_EOL);
   pid = fork ();
   if (pid == -1)
     SCM_SYSERROR;
diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am
index a2f6def..8daa2e0 100644
--- a/test-suite/Makefile.am
+++ b/test-suite/Makefile.am
@@ -1,7 +1,7 @@
 ## Process this file with automake to produce Makefile.in.
 ##
 ## Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-##   2010, 2011 Software Foundation, Inc.
+##   2010, 2011, 2012 Software Foundation, Inc.
 ##
 ## This file is part of GUILE.
 ##
@@ -23,6 +23,7 @@
 SUBDIRS = standalone vm
 
 SCM_TESTS = tests/00-initial-env.test          \
+           tests/00-socket.test                \
             tests/alist.test                   \
            tests/and-let-star.test             \
            tests/arbiters.test                 \
@@ -111,7 +112,6 @@ SCM_TESTS = tests/00-initial-env.test               \
            tests/regexp.test                   \
            tests/session.test                  \
            tests/signals.test                  \
-           tests/socket.test                   \
            tests/srcprop.test                  \
            tests/srfi-1.test                   \
            tests/srfi-6.test                   \
diff --git a/test-suite/tests/socket.test b/test-suite/tests/00-socket.test
similarity index 98%
rename from test-suite/tests/socket.test
rename to test-suite/tests/00-socket.test
index 6deb285..e74d376 100644
--- a/test-suite/tests/socket.test
+++ b/test-suite/tests/00-socket.test
@@ -1,7 +1,7 @@
-;;;; socket.test --- test socket functions     -*- scheme -*-
+;;;; 00-socket.test --- test socket functions     -*- scheme -*-
 ;;;;
 ;;;; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-;;;;   2011 Free Software Foundation, Inc.
+;;;;   2011, 2012 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,6 +17,9 @@
 ;;;; License along with this library; if not, write to the Free Software
 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
USA
 
+;; This test runs early, so that we can fork before any threads are
+;; created in other tests.
+
 (define-module (test-suite test-socket)
   #:use-module (rnrs bytevectors)
   #:use-module (srfi srfi-26)


hooks/post-receive
-- 
GNU Guile



reply via email to

[Prev in Thread] Current Thread [Next in Thread]