diff options
author | Ludovic Courtes <ludovic.courtes@laas.fr> | 2006-06-11 20:13:58 +0000 |
---|---|---|
committer | Ludovic Courtès <ludo@gnu.org> | 2008-09-10 20:27:08 +0200 |
commit | 651a0735225da3e4887df018824e9baaada5194e (patch) | |
tree | 8ff6e56f6fa9988e2a5412859241fa6bf7f88e78 | |
parent | 92d8fd328c66df2132e13ff1428bb83b2f4350c2 (diff) | |
download | guile-651a0735225da3e4887df018824e9baaada5194e.tar.gz |
Implemented port finalization.
* libguile/ports.c (register_finalizer_for_port): New.
(finalize_port): New.
(scm_new_port_table_entry): Call `register_finalizer_for_port ()'
before returning the new port.
(scm_ports_prehistory): Use `scm_gc_malloc_pointerless ()' instead of
`scm_gc_malloc ()' when allocating room for SCM_I_PORT_TABLE.
git-archimport-id: lcourtes@laas.fr--2005-libre/guile-core--boehm-gc--1.9--patch-37
-rw-r--r-- | libguile/ports.c | 81 |
1 files changed, 76 insertions, 5 deletions
diff --git a/libguile/ports.c b/libguile/ports.c index d5f4ee6e6..bcf4a89f1 100644 --- a/libguile/ports.c +++ b/libguile/ports.c @@ -482,8 +482,70 @@ long scm_i_port_table_room = 20; /* Actual size of the array. */ scm_i_pthread_mutex_t scm_i_port_table_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER; -/* This function is not and should not be thread safe. */ + +/* Port finalization. */ + +static void finalize_port (GC_PTR, GC_PTR); + +/* Register a finalizer for PORT, if needed by its port type. */ +static SCM_C_INLINE_KEYWORD void +register_finalizer_for_port (SCM port) +{ + long port_type; + + port_type = SCM_TC2PTOBNUM (SCM_CELL_TYPE (port)); + if (scm_ptobs[port_type].free) + { + GC_finalization_proc prev_finalizer; + GC_PTR prev_finalization_data; + + GC_REGISTER_FINALIZER_NO_ORDER (SCM2PTR (port), finalize_port, 0, + &prev_finalizer, + &prev_finalization_data); + } +} + +/* Finalize the object (a port) pointed to by PTR. */ +static void +finalize_port (GC_PTR ptr, GC_PTR data) +{ + long port_type; + SCM port = PTR2SCM (ptr); + + if (!SCM_PORTP (port)) + abort (); + + if (SCM_OPENP (port)) + { + if (SCM_REVEALED (port) > 0) + /* Keep "revealed" ports alive and re-register a finalizer. */ + register_finalizer_for_port (port); + else + { + port_type = SCM_TC2PTOBNUM (SCM_CELL_TYPE (port)); + if (port_type >= scm_numptob) + abort (); + + if (scm_ptobs[port_type].free) + /* Yes, I really do mean `.free' rather than `.close'. `.close' + is for explicit `close-port' by user. */ + scm_ptobs[port_type].free (port); + + SCM_SETSTREAM (port, 0); + SCM_CLR_PORT_OPEN_FLAG (port); + scm_remove_from_port_table (port); + + scm_gc_ports_collected++; + } + } +} + + + + + +/* This function is not and should not be thread safe. */ SCM scm_new_port_table_entry (scm_t_bits tag) #define FUNC_NAME "scm_new_port_table_entry" @@ -501,6 +563,8 @@ scm_new_port_table_entry (scm_t_bits tag) since it can never be freed during gc. */ /* XXX (Ludo): Why not do it actually? */ size_t new_size = scm_i_port_table_room * 2; + /* XXX (Ludo): Can we use `GC_REALLOC' with + `GC_MALLOC_ATOMIC'-allocated data? */ void *newt = scm_gc_realloc ((char *) scm_i_port_table, scm_i_port_table_room * sizeof (scm_t_port *), new_size * sizeof (scm_t_port *), @@ -520,7 +584,11 @@ scm_new_port_table_entry (scm_t_bits tag) entry->port = z; SCM_SET_CELL_TYPE(z, tag); SCM_SETPTAB_ENTRY(z, entry); - + + /* For each new port, register a finalizer so that it port type's free + function can be invoked eventually. */ + register_finalizer_for_port (z); + return z; } #undef FUNC_NAME @@ -1618,9 +1686,12 @@ scm_ports_prehistory () scm_numptob = 0; scm_ptobs = NULL; - scm_i_port_table = scm_gc_malloc (scm_i_port_table_room - * sizeof (scm_t_port *), - "port-table"); + /* In order for the ports to be collectable, the port table must not be + scanned by the GC. */ + scm_i_port_table = + scm_gc_malloc_pointerless (scm_i_port_table_room + * sizeof (scm_t_port *), + "port-table"); } |