mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-07-04 16:50:25 +02:00
add atfork interface
* libguile/posix.h: * libguile/posix.c (scm_c_atfork): New interface. (scm_fork): Wrap fork calls in atfork pre/post invocations, and finally a GC_call_with_alloc_lock. It's an attempt to grab the interesting mutexes in Guile. * libguile/weak-set.c (make_weak_set): * libguile/weak-table.c (make_weak_table): Use atfork mechanism to lock and unlock weak sets and weak tables during a fork(), in such a way that does not prevent those tables from being gc'd.
This commit is contained in:
parent
981bace7e4
commit
9f6ac5d71d
6 changed files with 253 additions and 31 deletions
|
@ -383,6 +383,7 @@ scm_i_init_guile (void *base)
|
|||
|
||||
scm_storage_prehistory ();
|
||||
scm_threads_prehistory (base); /* requires storage_prehistory */
|
||||
scm_weak_set_prehistory (); /* requires storage_prehistory */
|
||||
scm_weak_table_prehistory (); /* requires storage_prehistory */
|
||||
#ifdef GUILE_DEBUG_MALLOC
|
||||
scm_debug_malloc_prehistory ();
|
||||
|
|
|
@ -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
|
||||
|
@ -1238,6 +1238,65 @@ SCM_DEFINE (scm_execle, "execle", 2, 0, 1,
|
|||
#undef FUNC_NAME
|
||||
|
||||
#ifdef HAVE_FORK
|
||||
struct scm_t_atfork_entry {
|
||||
struct scm_t_atfork_entry *next;
|
||||
struct scm_t_atfork_entry *prev;
|
||||
scm_t_atfork_callback pre;
|
||||
scm_t_atfork_callback post;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static scm_i_pthread_mutex_t atfork_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER;
|
||||
static struct scm_t_atfork_entry *atfork_entries;
|
||||
|
||||
void
|
||||
scm_c_atfork (scm_t_atfork_callback pre, scm_t_atfork_callback post, void *data)
|
||||
{
|
||||
struct scm_t_atfork_entry *new_entry;
|
||||
|
||||
new_entry = scm_gc_malloc (sizeof (*new_entry), "atfork entry");
|
||||
|
||||
scm_i_pthread_mutex_lock (&atfork_lock);
|
||||
new_entry->next = atfork_entries;
|
||||
new_entry->prev = NULL;
|
||||
if (atfork_entries)
|
||||
atfork_entries->prev = new_entry;
|
||||
new_entry->pre = pre;
|
||||
new_entry->post = post;
|
||||
new_entry->data = data;
|
||||
atfork_entries = new_entry;
|
||||
scm_i_pthread_mutex_unlock (&atfork_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
before_fork (void)
|
||||
{
|
||||
struct scm_t_atfork_entry *ent;
|
||||
|
||||
scm_i_pthread_mutex_lock (&atfork_lock);
|
||||
for (ent = atfork_entries; ent; ent = ent->next)
|
||||
ent->pre (ent->data);
|
||||
}
|
||||
|
||||
static void
|
||||
after_fork (void)
|
||||
{
|
||||
struct scm_t_atfork_entry *ent;
|
||||
|
||||
for (ent = atfork_entries; ent && ent->next; ent = ent->next);
|
||||
for (; ent; ent = ent->prev)
|
||||
ent->post (ent->data);
|
||||
scm_i_pthread_mutex_unlock (&atfork_lock);
|
||||
}
|
||||
|
||||
static void*
|
||||
do_fork (void *data)
|
||||
{
|
||||
int *pid = data;
|
||||
*pid = fork();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SCM_DEFINE (scm_fork, "primitive-fork", 0, 0, 0,
|
||||
(),
|
||||
"Creates a new \"child\" process by duplicating the current \"parent\" process.\n"
|
||||
|
@ -1248,7 +1307,11 @@ SCM_DEFINE (scm_fork, "primitive-fork", 0, 0, 0,
|
|||
#define FUNC_NAME s_scm_fork
|
||||
{
|
||||
int pid;
|
||||
pid = fork ();
|
||||
|
||||
before_fork ();
|
||||
GC_call_with_alloc_lock (do_fork, &pid);
|
||||
after_fork ();
|
||||
|
||||
if (pid == -1)
|
||||
SCM_SYSERROR;
|
||||
return scm_from_int (pid);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#define SCM_POSIX_H
|
||||
|
||||
/* Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2003, 2006, 2008,
|
||||
* 2009, 2010, 2011 Free Software Foundation, Inc.
|
||||
* 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
|
||||
|
@ -64,7 +64,13 @@ SCM_API SCM scm_ttyname (SCM port);
|
|||
SCM_API SCM scm_execl (SCM filename, SCM args);
|
||||
SCM_API SCM scm_execlp (SCM filename, SCM args);
|
||||
SCM_API SCM scm_execle (SCM filename, SCM env, SCM args);
|
||||
|
||||
typedef void (*scm_t_atfork_callback) (void *data);
|
||||
SCM_API void scm_c_atfork (scm_t_atfork_callback pre,
|
||||
scm_t_atfork_callback post,
|
||||
void *data);
|
||||
SCM_API SCM scm_fork (void);
|
||||
|
||||
SCM_API SCM scm_uname (void);
|
||||
SCM_API SCM scm_environ (SCM env);
|
||||
SCM_API SCM scm_tmpnam (void);
|
||||
|
|
|
@ -614,6 +614,70 @@ weak_set_remove_x (scm_t_weak_set *set, unsigned long hash,
|
|||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
lock_weak_set (scm_t_weak_set *set)
|
||||
{
|
||||
scm_i_pthread_mutex_lock (&set->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
unlock_weak_set (scm_t_weak_set *set)
|
||||
{
|
||||
scm_i_pthread_mutex_unlock (&set->lock);
|
||||
}
|
||||
|
||||
/* A weak set of weak sets, for use in the pthread_atfork handler. */
|
||||
static SCM all_weak_sets = SCM_BOOL_F;
|
||||
|
||||
static void
|
||||
lock_all_weak_sets (void *unused)
|
||||
{
|
||||
scm_t_weak_set *s;
|
||||
scm_t_weak_entry *entries;
|
||||
unsigned long k, size;
|
||||
scm_t_weak_entry copy;
|
||||
|
||||
s = SCM_WEAK_SET (all_weak_sets);
|
||||
lock_weak_set (s);
|
||||
size = s->size;
|
||||
entries = s->entries;
|
||||
|
||||
for (k = 0; k < size; k++)
|
||||
if (entries[k].hash)
|
||||
{
|
||||
copy_weak_entry (&entries[k], ©);
|
||||
if (copy.key)
|
||||
lock_weak_set (SCM_WEAK_SET (SCM_PACK (copy.key)));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
unlock_all_weak_sets (void *unused)
|
||||
{
|
||||
scm_t_weak_set *s;
|
||||
scm_t_weak_entry *entries;
|
||||
unsigned long k, size;
|
||||
scm_t_weak_entry copy;
|
||||
|
||||
s = SCM_WEAK_SET (all_weak_sets);
|
||||
size = s->size;
|
||||
entries = s->entries;
|
||||
|
||||
for (k = 0; k < size; k++)
|
||||
if (entries[k].hash)
|
||||
{
|
||||
copy_weak_entry (&entries[k], ©);
|
||||
if (copy.key)
|
||||
unlock_weak_set (SCM_WEAK_SET (SCM_PACK (copy.key)));
|
||||
}
|
||||
|
||||
unlock_weak_set (s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static SCM
|
||||
make_weak_set (unsigned long k)
|
||||
{
|
||||
|
@ -660,7 +724,7 @@ do_vacuum_weak_set (SCM set)
|
|||
if (scm_i_pthread_mutex_trylock (&s->lock) == 0)
|
||||
{
|
||||
vacuum_weak_set (s);
|
||||
scm_i_pthread_mutex_unlock (&s->lock);
|
||||
unlock_weak_set (s);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -725,6 +789,9 @@ scm_c_make_weak_set (unsigned long k)
|
|||
|
||||
scm_c_register_weak_gc_callback (ret, do_vacuum_weak_set);
|
||||
|
||||
if (scm_is_true (all_weak_sets))
|
||||
scm_weak_set_add_x (all_weak_sets, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -739,12 +806,12 @@ scm_weak_set_clear_x (SCM set)
|
|||
{
|
||||
scm_t_weak_set *s = SCM_WEAK_SET (set);
|
||||
|
||||
scm_i_pthread_mutex_lock (&s->lock);
|
||||
lock_weak_set (s);
|
||||
|
||||
memset (s->entries, 0, sizeof (scm_t_weak_entry) * s->size);
|
||||
s->n_items = 0;
|
||||
|
||||
scm_i_pthread_mutex_unlock (&s->lock);
|
||||
unlock_weak_set (s);
|
||||
|
||||
return SCM_UNSPECIFIED;
|
||||
}
|
||||
|
@ -757,11 +824,11 @@ scm_c_weak_set_lookup (SCM set, unsigned long raw_hash,
|
|||
SCM ret;
|
||||
scm_t_weak_set *s = SCM_WEAK_SET (set);
|
||||
|
||||
scm_i_pthread_mutex_lock (&s->lock);
|
||||
lock_weak_set (s);
|
||||
|
||||
ret = weak_set_lookup (s, raw_hash, pred, closure, dflt);
|
||||
|
||||
scm_i_pthread_mutex_unlock (&s->lock);
|
||||
unlock_weak_set (s);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -774,11 +841,11 @@ scm_c_weak_set_add_x (SCM set, unsigned long raw_hash,
|
|||
SCM ret;
|
||||
scm_t_weak_set *s = SCM_WEAK_SET (set);
|
||||
|
||||
scm_i_pthread_mutex_lock (&s->lock);
|
||||
lock_weak_set (s);
|
||||
|
||||
ret = weak_set_add_x (s, raw_hash, pred, closure, obj);
|
||||
|
||||
scm_i_pthread_mutex_unlock (&s->lock);
|
||||
unlock_weak_set (s);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -790,11 +857,11 @@ scm_c_weak_set_remove_x (SCM set, unsigned long raw_hash,
|
|||
{
|
||||
scm_t_weak_set *s = SCM_WEAK_SET (set);
|
||||
|
||||
scm_i_pthread_mutex_lock (&s->lock);
|
||||
lock_weak_set (s);
|
||||
|
||||
weak_set_remove_x (s, raw_hash, pred, closure);
|
||||
|
||||
scm_i_pthread_mutex_unlock (&s->lock);
|
||||
unlock_weak_set (s);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -829,7 +896,7 @@ scm_c_weak_set_fold (scm_t_set_fold_fn proc, void *closure,
|
|||
|
||||
s = SCM_WEAK_SET (set);
|
||||
|
||||
scm_i_pthread_mutex_lock (&s->lock);
|
||||
lock_weak_set (s);
|
||||
|
||||
size = s->size;
|
||||
entries = s->entries;
|
||||
|
@ -845,14 +912,14 @@ scm_c_weak_set_fold (scm_t_set_fold_fn proc, void *closure,
|
|||
if (copy.key)
|
||||
{
|
||||
/* Release set lock while we call the function. */
|
||||
scm_i_pthread_mutex_unlock (&s->lock);
|
||||
unlock_weak_set (s);
|
||||
init = proc (closure, SCM_PACK (copy.key), init);
|
||||
scm_i_pthread_mutex_lock (&s->lock);
|
||||
lock_weak_set (s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scm_i_pthread_mutex_unlock (&s->lock);
|
||||
unlock_weak_set (s);
|
||||
|
||||
return init;
|
||||
}
|
||||
|
@ -897,6 +964,15 @@ scm_weak_set_map_to_list (SCM proc, SCM set)
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
scm_weak_set_prehistory (void)
|
||||
{
|
||||
all_weak_sets = scm_c_make_weak_set (0);
|
||||
scm_c_atfork (lock_all_weak_sets, unlock_all_weak_sets, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
scm_init_weak_set ()
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#ifndef SCM_WEAK_SET_H
|
||||
#define SCM_WEAK_SET_H
|
||||
|
||||
/* Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 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
|
||||
|
@ -57,7 +57,10 @@ SCM_INTERNAL SCM scm_weak_set_fold (SCM proc, SCM init, SCM set);
|
|||
SCM_INTERNAL SCM scm_weak_set_for_each (SCM proc, SCM set);
|
||||
SCM_INTERNAL SCM scm_weak_set_map_to_list (SCM proc, SCM set);
|
||||
|
||||
SCM_INTERNAL void scm_i_weak_set_lock (SCM set);
|
||||
SCM_INTERNAL void scm_i_weak_set_unlock (SCM set);
|
||||
SCM_INTERNAL void scm_i_weak_set_print (SCM exp, SCM port, scm_print_state *pstate);
|
||||
SCM_INTERNAL void scm_weak_set_prehistory (void);
|
||||
SCM_INTERNAL void scm_init_weak_set (void);
|
||||
|
||||
#endif /* SCM_WEAK_SET_H */
|
||||
|
|
|
@ -736,10 +736,75 @@ weak_table_remove_x (scm_t_weak_table *table, unsigned long hash,
|
|||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
lock_weak_table (scm_t_weak_table *table)
|
||||
{
|
||||
scm_i_pthread_mutex_lock (&table->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
unlock_weak_table (scm_t_weak_table *table)
|
||||
{
|
||||
scm_i_pthread_mutex_unlock (&table->lock);
|
||||
}
|
||||
|
||||
/* A weak table of weak tables, for use in the pthread_atfork handler. */
|
||||
static SCM all_weak_tables = SCM_BOOL_F;
|
||||
|
||||
static void
|
||||
lock_all_weak_tables (void *unused)
|
||||
{
|
||||
scm_t_weak_table *s;
|
||||
scm_t_weak_entry *entries;
|
||||
unsigned long k, size;
|
||||
scm_t_weak_entry copy;
|
||||
|
||||
s = SCM_WEAK_TABLE (all_weak_tables);
|
||||
lock_weak_table (s);
|
||||
size = s->size;
|
||||
entries = s->entries;
|
||||
|
||||
for (k = 0; k < size; k++)
|
||||
if (entries[k].hash)
|
||||
{
|
||||
copy_weak_entry (&entries[k], ©);
|
||||
if (copy.key)
|
||||
lock_weak_table (SCM_WEAK_TABLE (SCM_PACK (copy.key)));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
unlock_all_weak_tables (void *unused)
|
||||
{
|
||||
scm_t_weak_table *s;
|
||||
scm_t_weak_entry *entries;
|
||||
unsigned long k, size;
|
||||
scm_t_weak_entry copy;
|
||||
|
||||
s = SCM_WEAK_TABLE (all_weak_tables);
|
||||
size = s->size;
|
||||
entries = s->entries;
|
||||
|
||||
for (k = 0; k < size; k++)
|
||||
if (entries[k].hash)
|
||||
{
|
||||
copy_weak_entry (&entries[k], ©);
|
||||
if (copy.key)
|
||||
unlock_weak_table (SCM_WEAK_TABLE (SCM_PACK (copy.key)));
|
||||
}
|
||||
|
||||
unlock_weak_table (s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static SCM
|
||||
make_weak_table (unsigned long k, scm_t_weak_table_kind kind)
|
||||
{
|
||||
scm_t_weak_table *table;
|
||||
SCM ret;
|
||||
|
||||
int i = 0, n = k ? k : 31;
|
||||
while (i + 1 < HASHTABLE_SIZE_N && n > hashtable_size[i])
|
||||
|
@ -757,7 +822,12 @@ make_weak_table (unsigned long k, scm_t_weak_table_kind kind)
|
|||
table->min_size_index = i;
|
||||
scm_i_pthread_mutex_init (&table->lock, NULL);
|
||||
|
||||
return scm_cell (scm_tc7_weak_table, (scm_t_bits)table);
|
||||
ret = scm_cell (scm_tc7_weak_table, (scm_t_bits)table);
|
||||
|
||||
if (scm_is_true (all_weak_tables))
|
||||
scm_weak_table_putq_x (all_weak_tables, ret, SCM_BOOL_T);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -781,7 +851,7 @@ do_vacuum_weak_table (SCM table)
|
|||
if (scm_i_pthread_mutex_trylock (&t->lock) == 0)
|
||||
{
|
||||
vacuum_weak_table (t);
|
||||
scm_i_pthread_mutex_unlock (&t->lock);
|
||||
unlock_weak_table (t);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -868,11 +938,11 @@ scm_c_weak_table_ref (SCM table, unsigned long raw_hash,
|
|||
|
||||
t = SCM_WEAK_TABLE (table);
|
||||
|
||||
scm_i_pthread_mutex_lock (&t->lock);
|
||||
lock_weak_table (t);
|
||||
|
||||
ret = weak_table_ref (t, raw_hash, pred, closure, dflt);
|
||||
|
||||
scm_i_pthread_mutex_unlock (&t->lock);
|
||||
unlock_weak_table (t);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -890,11 +960,11 @@ scm_c_weak_table_put_x (SCM table, unsigned long raw_hash,
|
|||
|
||||
t = SCM_WEAK_TABLE (table);
|
||||
|
||||
scm_i_pthread_mutex_lock (&t->lock);
|
||||
lock_weak_table (t);
|
||||
|
||||
weak_table_put_x (t, raw_hash, pred, closure, key, value);
|
||||
|
||||
scm_i_pthread_mutex_unlock (&t->lock);
|
||||
unlock_weak_table (t);
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
|
@ -910,11 +980,11 @@ scm_c_weak_table_remove_x (SCM table, unsigned long raw_hash,
|
|||
|
||||
t = SCM_WEAK_TABLE (table);
|
||||
|
||||
scm_i_pthread_mutex_lock (&t->lock);
|
||||
lock_weak_table (t);
|
||||
|
||||
weak_table_remove_x (t, raw_hash, pred, closure);
|
||||
|
||||
scm_i_pthread_mutex_unlock (&t->lock);
|
||||
unlock_weak_table (t);
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
|
@ -962,12 +1032,12 @@ scm_weak_table_clear_x (SCM table)
|
|||
|
||||
t = SCM_WEAK_TABLE (table);
|
||||
|
||||
scm_i_pthread_mutex_lock (&t->lock);
|
||||
lock_weak_table (t);
|
||||
|
||||
memset (t->entries, 0, sizeof (scm_t_weak_entry) * t->size);
|
||||
t->n_items = 0;
|
||||
|
||||
scm_i_pthread_mutex_unlock (&t->lock);
|
||||
unlock_weak_table (t);
|
||||
|
||||
return SCM_UNSPECIFIED;
|
||||
}
|
||||
|
@ -983,7 +1053,7 @@ scm_c_weak_table_fold (scm_t_table_fold_fn proc, void *closure,
|
|||
|
||||
t = SCM_WEAK_TABLE (table);
|
||||
|
||||
scm_i_pthread_mutex_lock (&t->lock);
|
||||
lock_weak_table (t);
|
||||
|
||||
size = t->size;
|
||||
entries = t->entries;
|
||||
|
@ -999,16 +1069,16 @@ scm_c_weak_table_fold (scm_t_table_fold_fn proc, void *closure,
|
|||
if (copy.key && copy.value)
|
||||
{
|
||||
/* Release table lock while we call the function. */
|
||||
scm_i_pthread_mutex_unlock (&t->lock);
|
||||
unlock_weak_table (t);
|
||||
init = proc (closure,
|
||||
SCM_PACK (copy.key), SCM_PACK (copy.value),
|
||||
init);
|
||||
scm_i_pthread_mutex_lock (&t->lock);
|
||||
lock_weak_table (t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scm_i_pthread_mutex_unlock (&t->lock);
|
||||
unlock_weak_table (t);
|
||||
|
||||
return init;
|
||||
}
|
||||
|
@ -1163,6 +1233,9 @@ scm_weak_table_prehistory (void)
|
|||
GC_new_kind (GC_new_free_list (),
|
||||
GC_MAKE_PROC (GC_new_proc (mark_weak_value_table), 0),
|
||||
0, 0);
|
||||
|
||||
all_weak_tables = scm_c_make_weak_table (0, SCM_WEAK_TABLE_KIND_KEY);
|
||||
scm_c_atfork (lock_all_weak_tables, unlock_all_weak_tables, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue