-/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2003, 2004, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2003, 2004, 2006, 2007 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
#include <errno.h>
#include <fcntl.h> /* for chsize on mingw */
+#include <assert.h>
+
#include "libguile/_scm.h"
#include "libguile/async.h"
#include "libguile/eval.h"
#include <string.h>
#endif
-#ifdef HAVE_MALLOC_H
-#include <malloc.h>
-#endif
-
#ifdef HAVE_IO_H
#include <io.h>
#endif
if (255 <= scm_numptob)
goto ptoberr;
SCM_CRITICAL_SECTION_START;
- SCM_SYSCALL (tmp = (char *) realloc ((char *) scm_ptobs,
- (1 + scm_numptob)
- * sizeof (scm_t_ptob_descriptor)));
+ tmp = (char *) scm_gc_realloc ((char *) scm_ptobs,
+ scm_numptob * sizeof (scm_t_ptob_descriptor),
+ (1 + scm_numptob)
+ * sizeof (scm_t_ptob_descriptor),
+ "port-type");
if (tmp)
{
scm_ptobs = (scm_t_ptob_descriptor *) tmp;
\f
/* The port table --- an array of pointers to ports. */
-scm_t_port **scm_i_port_table;
+scm_t_port **scm_i_port_table = NULL;
-long scm_i_port_table_size = 0; /* Number of ports in scm_i_port_table. */
-long scm_i_port_table_room = 20; /* Size of the array. */
+long scm_i_port_table_size = 0; /* Number of ports in SCM_I_PORT_TABLE. */
+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. */
+\f
+/* 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++;
+ }
+ }
+}
+
+
+\f
+
+/* 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"
{
/* initial malloc is in gc.c. this doesn't use scm_gc_malloc etc.,
since it can never be freed during gc. */
- void *newt = scm_realloc ((char *) scm_i_port_table,
- (size_t) (sizeof (scm_t_port *)
- * scm_i_port_table_room * 2));
+ /* 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 *),
+ "port-table");
scm_i_port_table = (scm_t_port **) newt;
- scm_i_port_table_room *= 2;
+ scm_i_port_table_room = new_size;
}
entry->entry = scm_i_port_table_size;
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
pt->rw_active = SCM_PORT_WRITE;
}
-void
+void
scm_flush (SCM port)
{
long i = SCM_PTOBNUM (port);
+ assert ((i >= 0) && (i < scm_i_port_table_size));
(scm_ptobs[i].flush) (port);
}
{
size_t new_size = pt->read_buf_size * 2;
unsigned char *tmp = (unsigned char *)
+ /* XXX: Can we use `GC_REALLOC' with `GC_MALLOC_ATOMIC'-allocated
+ data? (Ludo) */
scm_gc_realloc (pt->putback_buf, pt->read_buf_size, new_size,
"putback buffer");
if (pt->putback_buf == NULL)
{
pt->putback_buf
- = (unsigned char *) scm_gc_malloc (SCM_INITIAL_PUTBACK_BUF_SIZE,
- "putback buffer");
+ = (unsigned char *) scm_gc_malloc_pointerless
+ (SCM_INITIAL_PUTBACK_BUF_SIZE, "putback buffer");
pt->putback_buf_size = SCM_INITIAL_PUTBACK_BUF_SIZE;
}
{
port = SCM_COERCE_OUTPORT (port);
SCM_VALIDATE_OPENPORT (1, port);
- return scm_from_int (SCM_LINUM (port));
+ return scm_from_long (SCM_LINUM (port));
}
#undef FUNC_NAME
{
port = SCM_COERCE_OUTPORT (port);
SCM_VALIDATE_OPENPORT (1, port);
- SCM_PTAB_ENTRY (port)->line_number = scm_to_int (line);
+ SCM_PTAB_ENTRY (port)->line_number = scm_to_long (line);
return SCM_UNSPECIFIED;
}
#undef FUNC_NAME
scm_ports_prehistory ()
{
scm_numptob = 0;
- scm_ptobs = (scm_t_ptob_descriptor *) scm_malloc (sizeof (scm_t_ptob_descriptor));
+ scm_ptobs = NULL;
+
+ /* 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");
}
\f