summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Courtes <ludovic.courtes@laas.fr>2006-06-11 20:13:58 +0000
committerLudovic Courtès <ludo@gnu.org>2008-09-10 20:27:08 +0200
commit651a0735225da3e4887df018824e9baaada5194e (patch)
tree8ff6e56f6fa9988e2a5412859241fa6bf7f88e78
parent92d8fd328c66df2132e13ff1428bb83b2f4350c2 (diff)
downloadguile-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.c81
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");
}