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-24-g2721f91


From: Andy Wingo
Subject: [Guile-commits] GNU Guile branch, master, updated. v2.1.0-24-g2721f91
Date: Sun, 23 Oct 2011 18:55:36 +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=2721f9182da74cf98426cc335f3f39c265cc412d

The branch, master has been updated
       via  2721f9182da74cf98426cc335f3f39c265cc412d (commit)
       via  7887be7df59b6f909aa9008454354f45dac1a8ea (commit)
       via  26b263541b56cf79f2c249950c5eadb87ce28b68 (commit)
       via  c259741533f6cdaaeb909fc233ba281898c3f2c2 (commit)
      from  46e372ef71ae7774b05a44a7443887a70efa8da0 (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 2721f9182da74cf98426cc335f3f39c265cc412d
Author: Andy Wingo <address@hidden>
Date:   Sun Oct 23 20:51:52 2011 +0200

    add scm_c_make_port; the port table is now a weak set
    
    * libguile/ports.c (scm_c_make_port_with_encoding, scm_c_make_port): New
      functions, to replace scm_new_port_table_entry.  Use a weak set
      instead of a weak table.
      (scm_i_remove_port):
      (scm_c_port_for_each, scm_port_for_each): Adapt to use weak set.
      (scm_i_void_port): Use scm_c_make_port.
      (scm_init_ports): Make a weak set.
    
    * libguile/fports.c:
    * libguile/ioext.c:
    * libguile/r6rs-ports.c:
    * libguile/strports.c:
    * libguile/vports.c: Adapt to use the new scm_c_make_port API.

commit 7887be7df59b6f909aa9008454354f45dac1a8ea
Author: Andy Wingo <address@hidden>
Date:   Sun Oct 23 20:46:48 2011 +0200

    symbols.c uses weak sets
    
    * libguile/symbols.c (lookup_interned_symbol)
      (lookup_interned_latin1_symbol, intern_symbol): Adapt to use weak sets
      instead of weak-key hash tables.

commit 26b263541b56cf79f2c249950c5eadb87ce28b68
Author: Andy Wingo <address@hidden>
Date:   Sun Oct 23 20:45:01 2011 +0200

    add weak sets
    
    * libguile/weak-set.c:
    * libguile/weak-set.h: New files, implementing weak sets, for use in the
      symbol table and port set.  Eventually we will be able to remove weak
      pairs.
    
    * libguile.h:
    * libguile/Makefile.am: Add new files.
    
    * libguile/evalext.c:
    * libguile/gc.c:
    * libguile/init.c:
    * libguile/print.c:
    * libguile/tags.h: Add support for the new types.

commit c259741533f6cdaaeb909fc233ba281898c3f2c2
Author: Andy Wingo <address@hidden>
Date:   Sat Oct 15 11:22:10 2011 +0200

    revise comments in libguile/tags.h
    
    * libguile/tags.h: Revise the comments to reflect libgc reality.

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

Summary of changes:
 libguile.h            |    1 +
 libguile/Makefile.am  |    4 +
 libguile/evalext.c    |    1 +
 libguile/fports.c     |   35 +--
 libguile/gc.c         |    2 +
 libguile/init.c       |    1 +
 libguile/ioext.c      |   12 +-
 libguile/ports.c      |  158 ++++-----
 libguile/ports.h      |   13 +-
 libguile/print.c      |    3 +
 libguile/r6rs-ports.c |   88 ++----
 libguile/strports.c   |   31 +-
 libguile/symbols.c    |   91 ++----
 libguile/tags.h       |  213 ++++++------
 libguile/vports.c     |   15 +-
 libguile/weak-set.c   |  887 +++++++++++++++++++++++++++++++++++++++++++++++++
 libguile/weak-set.h   |   69 ++++
 17 files changed, 1243 insertions(+), 381 deletions(-)
 create mode 100644 libguile/weak-set.c
 create mode 100644 libguile/weak-set.h

diff --git a/libguile.h b/libguile.h
index 2c10d05..24a3c96 100644
--- a/libguile.h
+++ b/libguile.h
@@ -115,6 +115,7 @@ extern "C" {
 #include "libguile/srfi-4.h"
 #include "libguile/version.h"
 #include "libguile/vports.h"
+#include "libguile/weak-set.h"
 #include "libguile/weaks.h"
 #include "libguile/backtrace.h"
 #include "libguile/debug.h"
diff --git a/libguile/Makefile.am b/libguile/Makefile.am
index 1817100..6f78d06 100644
--- a/libguile/Makefile.am
+++ b/libguile/Makefile.am
@@ -218,6 +218,7 @@ address@hidden@_la_SOURCES =                                
\
        version.c                               \
        vm.c                                    \
        vports.c                                \
+       weak-set.c                              \
        weaks.c
 
 DOT_X_FILES =                                  \
@@ -314,6 +315,7 @@ DOT_X_FILES =                                       \
        vectors.x                               \
        version.x                               \
        vports.x                                \
+       weak-set.x                              \
        weaks.x
 
 # vm-related snarfs
@@ -415,6 +417,7 @@ DOT_DOC_FILES =                             \
        vectors.doc                             \
        version.doc                             \
        vports.doc                              \
+       weak-set.doc                            \
        weaks.doc
 
 EXTRA_DOT_DOC_FILES = @EXTRA_DOT_DOC_FILES@
@@ -617,6 +620,7 @@ modinclude_HEADERS =                                \
        vm-expand.h                             \
        vm.h                                    \
        vports.h                                \
+       weak-set.h                              \
        weaks.h
 
 nodist_modinclude_HEADERS = version.h scmconfig.h
diff --git a/libguile/evalext.c b/libguile/evalext.c
index 1e5bd68..83b70f1 100644
--- a/libguile/evalext.c
+++ b/libguile/evalext.c
@@ -76,6 +76,7 @@ SCM_DEFINE (scm_self_evaluating_p, "self-evaluating?", 1, 0, 
0,
        case scm_tc7_wvect:
        case scm_tc7_pointer:
        case scm_tc7_hashtable:
+       case scm_tc7_weak_set:
        case scm_tc7_fluid:
        case scm_tc7_dynamic_state:
         case scm_tc7_frame:
diff --git a/libguile/fports.c b/libguile/fports.c
index 0b84d44..f379db1 100644
--- a/libguile/fports.c
+++ b/libguile/fports.c
@@ -532,7 +532,7 @@ scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
 #define FUNC_NAME "scm_fdes_to_port"
 {
   SCM port;
-  scm_t_port *pt;
+  scm_t_fport *fp;
   int flags;
 
   /* test that fdes is valid.  */
@@ -551,26 +551,21 @@ scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
       SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
     }
 
-  scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
+  fp = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
+                                                  "file port");
+  fp->fdes = fdes;
+
+  port = scm_c_make_port (scm_tc16_fport, mode_bits, (scm_t_bits)fp);
+  
+  SCM_PTAB_ENTRY (port)->rw_random = SCM_FDES_RANDOM_P (fdes);
+
+  if (mode_bits & SCM_BUF0)
+    scm_fport_buffer_add (port, 0, 0);
+  else
+    scm_fport_buffer_add (port, -1, -1);
 
-  port = scm_new_port_table_entry (scm_tc16_fport);
-  SCM_SET_CELL_TYPE(port, scm_tc16_fport | mode_bits);
-  pt = SCM_PTAB_ENTRY(port);
-  {
-    scm_t_fport *fp
-      = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
-                                                  "file port");
-
-    fp->fdes = fdes;
-    pt->rw_random = SCM_FDES_RANDOM_P (fdes);
-    SCM_SETSTREAM (port, fp);
-    if (mode_bits & SCM_BUF0)
-      scm_fport_buffer_add (port, 0, 0);
-    else
-      scm_fport_buffer_add (port, -1, -1);
-  }
   SCM_SET_FILENAME (port, name);
-  scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
+
   return port;
 }
 #undef FUNC_NAME
diff --git a/libguile/gc.c b/libguile/gc.c
index c68f295..42b29fb 100644
--- a/libguile/gc.c
+++ b/libguile/gc.c
@@ -751,6 +751,8 @@ scm_i_tag_name (scm_t_bits tag)
       return "foreign";
     case scm_tc7_hashtable:
       return "hashtable";
+    case scm_tc7_weak_set:
+      return "weak-set";
     case scm_tc7_fluid:
       return "fluid";
     case scm_tc7_dynamic_state:
diff --git a/libguile/init.c b/libguile/init.c
index 8aae6b5..d288a73 100644
--- a/libguile/init.c
+++ b/libguile/init.c
@@ -489,6 +489,7 @@ scm_i_init_guile (void *base)
   scm_init_trees ();
   scm_init_version ();
   scm_init_weaks ();
+  scm_init_weak_set ();
   scm_init_guardians (); /* requires smob_prehistory */
   scm_init_vports ();
   scm_init_standard_ports ();  /* Requires fports */
diff --git a/libguile/ioext.c b/libguile/ioext.c
index 6b0c9b8..cb55fb2 100644
--- a/libguile/ioext.c
+++ b/libguile/ioext.c
@@ -1,4 +1,4 @@
-/*     Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2006 Free 
Software Foundation, Inc.
+/*     Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2006, 
2011 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
@@ -269,7 +269,7 @@ SCM_DEFINE (scm_primitive_move_to_fdes, 
"primitive-move->fdes", 2, 0, 0,
 #undef FUNC_NAME
 
 static SCM
-get_matching_port (void *closure, SCM port, SCM val, SCM result)
+get_matching_port (void *closure, SCM port, SCM result)
 {
   int fd = * (int *) closure;
   scm_t_port *entry = SCM_PTAB_ENTRY (port);
@@ -292,11 +292,9 @@ SCM_DEFINE (scm_fdes_to_ports, "fdes->ports", 1, 0, 0,
   SCM result = SCM_EOL;
   int int_fd = scm_to_int (fd);
 
-  scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
-  result = scm_internal_hash_fold (get_matching_port,
-                                  (void*) &int_fd, result, 
-                                  scm_i_port_weak_hash);
-  scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
+  result = scm_c_weak_set_fold (get_matching_port,
+                                (void*) &int_fd, result, 
+                                scm_i_port_weak_set);
   return result;
 }
 #undef FUNC_NAME    
diff --git a/libguile/ports.c b/libguile/ports.c
index a4d3bd8..6c4561e 100644
--- a/libguile/ports.c
+++ b/libguile/ports.c
@@ -56,7 +56,7 @@
 #include "libguile/validate.h"
 #include "libguile/ports.h"
 #include "libguile/vectors.h"
-#include "libguile/weaks.h"
+#include "libguile/weak-set.h"
 #include "libguile/fluids.h"
 #include "libguile/eq.h"
 
@@ -508,9 +508,7 @@ scm_i_dynwind_current_load_port (SCM port)
   We need a global registry of ports to flush them all at exit, and to
   get all the ports matching a file descriptor.
  */
-SCM scm_i_port_weak_hash;
-
-scm_i_pthread_mutex_t scm_i_port_table_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
+SCM scm_i_port_weak_set;
 
 
 /* Port finalization.  */
@@ -579,47 +577,51 @@ finalize_port (GC_PTR ptr, GC_PTR data)
 
 
 
-/* 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"
+scm_c_make_port_with_encoding (scm_t_bits tag, unsigned long mode_bits,
+                               const char *encoding,
+                               scm_t_string_failed_conversion_handler handler,
+                               scm_t_bits stream)
 {
-  /*
-    We initialize the cell to empty, this is in case scm_gc_calloc
-    triggers GC ; we don't want the GC to scan a half-finished Z.
-   */
-  
-  SCM z = scm_cons (SCM_EOL, SCM_EOL);
-  scm_t_port *entry = (scm_t_port *) scm_gc_calloc (sizeof (scm_t_port), 
"port");
-  const char *enc;
+  SCM ret;
+  scm_t_port *entry;
+
+  entry = (scm_t_port *) scm_gc_calloc (sizeof (scm_t_port), "port");
+  ret = scm_cell (tag | mode_bits, (scm_t_bits)entry);
 
   entry->file_name = SCM_BOOL_F;
   entry->rw_active = SCM_PORT_NEITHER;
-  entry->port = z;
-
-  /* Initialize this port with the thread's current default
-     encoding.  */
-  enc = scm_i_default_port_encoding ();
-  entry->encoding = enc ? scm_gc_strdup (enc, "port") : NULL;
-
+  entry->port = ret;
+  entry->stream = stream;
+  entry->encoding = encoding ? scm_gc_strdup (encoding, "port") : NULL;
   /* The conversion descriptors will be opened lazily.  */
   entry->input_cd = (iconv_t) -1;
   entry->output_cd = (iconv_t) -1;
+  entry->ilseq_handler = handler;
 
-  entry->ilseq_handler = scm_i_get_conversion_strategy (SCM_BOOL_F);
-
-  SCM_SET_CELL_TYPE (z, tag);
-  SCM_SETPTAB_ENTRY (z, entry);
-
-  scm_hashq_set_x (scm_i_port_weak_hash, z, SCM_BOOL_F);
+  scm_weak_set_add_x (scm_i_port_weak_set, ret);
 
   /* For each new port, register a finalizer so that it port type's free
      function can be invoked eventually.  */
-  register_finalizer_for_port (z);
+  register_finalizer_for_port (ret);
 
-  return z;
+  return ret;
+}
+
+SCM
+scm_c_make_port (scm_t_bits tag, unsigned long mode_bits, scm_t_bits stream)
+{
+  return scm_c_make_port_with_encoding (tag, mode_bits,
+                                        scm_i_default_port_encoding (),
+                                        scm_i_get_conversion_strategy 
(SCM_BOOL_F),
+                                        stream);
+}
+
+SCM
+scm_new_port_table_entry (scm_t_bits tag)
+{
+  return scm_c_make_port (tag, 0, 0);
 }
-#undef FUNC_NAME
 
 /* Remove a port from the table and destroy it.  */
 
@@ -629,10 +631,11 @@ scm_i_remove_port (SCM port)
 {
   scm_t_port *p;
 
-  scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
-
   p = SCM_PTAB_ENTRY (port);
   scm_port_non_buffer (p);
+  SCM_SETPTAB_ENTRY (port, 0);
+  scm_weak_set_remove_x (scm_i_port_weak_set, port);
+
   p->putback_buf = NULL;
   p->putback_buf_size = 0;
 
@@ -647,29 +650,10 @@ scm_i_remove_port (SCM port)
       iconv_close (p->output_cd);
       p->output_cd = (iconv_t) -1;
     }
-
-  SCM_SETPTAB_ENTRY (port, 0);
-
-  scm_hashq_remove_x (scm_i_port_weak_hash, port);
-
-  scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
 }
 #undef FUNC_NAME
 
 
-/* Functions for debugging.  */
-#ifdef GUILE_DEBUG
-SCM_DEFINE (scm_pt_size, "pt-size", 0, 0, 0,
-            (),
-           "Return the number of ports in the port table.  @code{pt-size}\n"
-           "is only included in @code{--enable-guile-debug} builds.")
-#define FUNC_NAME s_scm_pt_size
-{
-  return scm_from_int (SCM_HASHTABLE_N_ITEMS (scm_i_port_weak_hash));
-}
-#undef FUNC_NAME
-#endif
-
 void
 scm_port_non_buffer (scm_t_port *pt)
 {
@@ -862,30 +846,38 @@ SCM_DEFINE (scm_close_output_port, "close-output-port", 
1, 0, 0,
 }
 #undef FUNC_NAME
 
+struct for_each_data 
+{
+  void (*proc) (void *data, SCM p);
+  void *data;
+};
+
 static SCM
-collect_keys (void *unused, SCM key, SCM value, SCM result)
+for_each_trampoline (void *data, SCM port, SCM result)
 {
-  return scm_cons (key, result);
+  struct for_each_data *d = data;
+  
+  d->proc (d->data, port);
+
+  return result;
 }
 
 void
 scm_c_port_for_each (void (*proc)(void *data, SCM p), void *data)
 {
-  SCM ports;
+  struct for_each_data d;
+  
+  d.proc = proc;
+  d.data = data;
 
-  /* Copy out the port table as a list so that we get strong references
-     to all the values.  */
-  scm_i_pthread_mutex_lock (&scm_i_port_table_mutex);
-  ports = scm_internal_hash_fold (collect_keys, NULL,
-                                 SCM_EOL, scm_i_port_weak_hash);
-  scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
+  scm_c_weak_set_fold (for_each_trampoline, &d, SCM_EOL,
+                       scm_i_port_weak_set);
+}
 
-  for (; scm_is_pair (ports); ports = scm_cdr (ports))
-    {
-      SCM p = scm_car (ports);
-      if (SCM_PORTP (p))
-        proc (data, p);
-    }
+static void
+scm_for_each_trampoline (void *data, SCM port)
+{
+  scm_call_1 (PTR2SCM (data), port);
 }
 
 SCM_DEFINE (scm_port_for_each, "port-for-each", 1, 0, 0,
@@ -898,21 +890,10 @@ SCM_DEFINE (scm_port_for_each, "port-for-each", 1, 0, 0,
            "have no effect as far as @var{port-for-each} is concerned.") 
 #define FUNC_NAME s_scm_port_for_each
 {
-  SCM ports;
-
   SCM_VALIDATE_PROC (1, proc);
 
-  /* Copy out the port table as a list so that we get strong references
-     to all the values.  */
-  scm_i_pthread_mutex_lock (&scm_i_port_table_mutex);
-  ports = scm_internal_hash_fold (collect_keys, NULL,
-                                 SCM_EOL, scm_i_port_weak_hash);
-  scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
-
-  for (; scm_is_pair (ports); ports = scm_cdr (ports))
-    if (SCM_PORTP (SCM_CAR (ports)))
-      scm_call_1 (proc, SCM_CAR (ports));
-
+  scm_c_port_for_each (scm_for_each_trampoline, SCM2PTR (proc));
+  
   return SCM_UNSPECIFIED;
 }
 #undef FUNC_NAME
@@ -2470,18 +2451,13 @@ write_void_port (SCM port SCM_UNUSED,
 static SCM
 scm_i_void_port (long mode_bits)
 {
-  scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
-  {
-    SCM answer = scm_new_port_table_entry (scm_tc16_void_port);
-    scm_t_port * pt = SCM_PTAB_ENTRY(answer);
+  SCM ret;
+
+  ret = scm_c_make_port (scm_tc16_void_port, mode_bits, 0);
 
-    scm_port_non_buffer (pt);
+  scm_port_non_buffer (SCM_PTAB_ENTRY (ret));
   
-    SCM_SETSTREAM (answer, 0);
-    SCM_SET_CELL_TYPE (answer, scm_tc16_void_port | mode_bits);
-    scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
-    return answer;
-  }
+  return ret;
 }
 
 SCM
@@ -2521,7 +2497,7 @@ scm_init_ports ()
   cur_errport_fluid = scm_make_fluid ();
   cur_loadport_fluid = scm_make_fluid ();
 
-  scm_i_port_weak_hash = scm_make_weak_key_hash_table (SCM_I_MAKINUM(31));
+  scm_i_port_weak_set = scm_c_make_weak_set (31);
 
 #include "libguile/ports.x"
 
diff --git a/libguile/ports.h b/libguile/ports.h
index 80da9a0..f5c98ab 100644
--- a/libguile/ports.h
+++ b/libguile/ports.h
@@ -118,8 +118,7 @@ typedef struct
 } scm_t_port;
 
 
-SCM_INTERNAL scm_i_pthread_mutex_t scm_i_port_table_mutex;
-SCM_INTERNAL SCM scm_i_port_weak_hash;
+SCM_INTERNAL SCM scm_i_port_weak_set;
 
 
 #define SCM_READ_BUFFER_EMPTY_P(c_port) (c_port->read_pos >= c_port->read_end)
@@ -254,6 +253,16 @@ SCM_API SCM scm_set_current_error_port (SCM port);
 SCM_API void scm_dynwind_current_input_port (SCM port);
 SCM_API void scm_dynwind_current_output_port (SCM port);
 SCM_API void scm_dynwind_current_error_port (SCM port);
+
+SCM_API SCM
+scm_c_make_port_with_encoding (scm_t_bits tag,
+                               unsigned long mode_bits,
+                               const char *encoding,
+                               scm_t_string_failed_conversion_handler handler,
+                               scm_t_bits stream);
+SCM_API SCM scm_c_make_port (scm_t_bits tag, unsigned long mode_bits,
+                             scm_t_bits stream);
+
 SCM_API SCM scm_new_port_table_entry (scm_t_bits tag);
 SCM_API void scm_grow_port_cbuf (SCM port, size_t requested);
 SCM_API SCM scm_pt_size (void);
diff --git a/libguile/print.c b/libguile/print.c
index 31e17f1..a619bfe 100644
--- a/libguile/print.c
+++ b/libguile/print.c
@@ -621,6 +621,9 @@ iprin1 (SCM exp, SCM port, scm_print_state *pstate)
        case scm_tc7_hashtable:
          scm_i_hashtable_print (exp, port, pstate);
          break;
+       case scm_tc7_weak_set:
+         scm_i_weak_set_print (exp, port, pstate);
+         break;
        case scm_tc7_fluid:
          scm_i_fluid_print (exp, port, pstate);
          break;
diff --git a/libguile/r6rs-ports.c b/libguile/r6rs-ports.c
index 7ee56af..06576e9 100644
--- a/libguile/r6rs-ports.c
+++ b/libguile/r6rs-ports.c
@@ -84,17 +84,14 @@ make_bip (SCM bv)
   scm_t_port *c_port;
   const unsigned long mode_bits = SCM_OPN | SCM_RDNG;
 
-  scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
+  port = scm_c_make_port_with_encoding (bytevector_input_port_type,
+                                        mode_bits,
+                                        NULL, /* encoding */
+                                        SCM_FAILED_CONVERSION_ERROR,
+                                        SCM_UNPACK (bv));
 
-  port = scm_new_port_table_entry (bytevector_input_port_type);
   c_port = SCM_PTAB_ENTRY (port);
 
-  /* Match the expectation of `binary-port?'.  */
-  c_port->encoding = NULL;
-
-  /* Prevent BV from being GC'd.  */
-  SCM_SETSTREAM (port, SCM_UNPACK (bv));
-
   /* Have the port directly access the bytevector.  */
   c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
   c_len = SCM_BYTEVECTOR_LENGTH (bv);
@@ -103,11 +100,6 @@ make_bip (SCM bv)
   c_port->read_end = (unsigned char *) c_bv + c_len;
   c_port->read_buf_size = c_len;
 
-  /* Mark PORT as open, readable and unbuffered (hmm, how elegant...).  */
-  SCM_SET_CELL_TYPE (port, bytevector_input_port_type | mode_bits);
-
-  scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
-
   return port;
 }
 
@@ -312,27 +304,19 @@ make_cbip (SCM read_proc, SCM get_position_proc,
   SCM_SIMPLE_VECTOR_SET (method_vector, 2, set_position_proc);
   SCM_SIMPLE_VECTOR_SET (method_vector, 3, close_proc);
 
-  scm_i_pthread_mutex_lock (&scm_i_port_table_mutex);
+  port = scm_c_make_port_with_encoding (custom_binary_input_port_type,
+                                        mode_bits,
+                                        NULL, /* encoding */
+                                        SCM_FAILED_CONVERSION_ERROR,
+                                        SCM_UNPACK (method_vector));
 
-  port = scm_new_port_table_entry (custom_binary_input_port_type);
   c_port = SCM_PTAB_ENTRY (port);
 
-  /* Match the expectation of `binary-port?'.  */
-  c_port->encoding = NULL;
-
-  /* Attach it the method vector.  */
-  SCM_SETSTREAM (port, SCM_UNPACK (method_vector));
-
   /* Have the port directly access the buffer (bytevector).  */
   c_port->read_pos = c_port->read_buf = (unsigned char *) c_bv;
   c_port->read_end = (unsigned char *) c_bv;
   c_port->read_buf_size = c_len;
 
-  /* Mark PORT as open, readable and unbuffered (hmm, how elegant...).  */
-  SCM_SET_CELL_TYPE (port, custom_binary_input_port_type | mode_bits);
-
-  scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
-
   return port;
 }
 
@@ -829,26 +813,19 @@ make_bop (void)
   scm_t_bop_buffer *buf;
   const unsigned long mode_bits = SCM_OPN | SCM_WRTNG;
 
-  scm_i_pthread_mutex_lock (&scm_i_port_table_mutex);
-
-  port = scm_new_port_table_entry (bytevector_output_port_type);
-  c_port = SCM_PTAB_ENTRY (port);
-
-  /* Match the expectation of `binary-port?'.  */
-  c_port->encoding = NULL;
-
   buf = (scm_t_bop_buffer *) scm_gc_malloc (sizeof (* buf), SCM_GC_BOP);
   bop_buffer_init (buf);
 
-  c_port->write_buf = c_port->write_pos = c_port->write_end = NULL;
-  c_port->write_buf_size = 0;
-
-  SCM_SET_BOP_BUFFER (port, buf);
+  port = scm_c_make_port_with_encoding (bytevector_output_port_type,
+                                        mode_bits,
+                                        NULL, /* encoding */
+                                        SCM_FAILED_CONVERSION_ERROR,
+                                        (scm_t_bits)buf);
 
-  /* Mark PORT as open and writable.  */
-  SCM_SET_CELL_TYPE (port, bytevector_output_port_type | mode_bits);
+  c_port = SCM_PTAB_ENTRY (port);
 
-  scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
+  c_port->write_buf = c_port->write_pos = c_port->write_end = NULL;
+  c_port->write_buf_size = 0;
 
   /* Make the bop procedure.  */
   SCM_NEWSMOB (bop_proc, bytevector_output_port_procedure, buf);
@@ -988,26 +965,18 @@ make_cbop (SCM write_proc, SCM get_position_proc,
   SCM_SIMPLE_VECTOR_SET (method_vector, 2, set_position_proc);
   SCM_SIMPLE_VECTOR_SET (method_vector, 3, close_proc);
 
-  scm_i_pthread_mutex_lock (&scm_i_port_table_mutex);
+  port = scm_c_make_port_with_encoding (custom_binary_output_port_type,
+                                        mode_bits,
+                                        NULL, /* encoding */
+                                        SCM_FAILED_CONVERSION_ERROR,
+                                        SCM_UNPACK (method_vector));
 
-  port = scm_new_port_table_entry (custom_binary_output_port_type);
   c_port = SCM_PTAB_ENTRY (port);
 
-  /* Match the expectation of `binary-port?'.  */
-  c_port->encoding = NULL;
-
-  /* Attach it the method vector.  */
-  SCM_SETSTREAM (port, SCM_UNPACK (method_vector));
-
   /* Have the port directly access the buffer (bytevector).  */
   c_port->write_buf = c_port->write_pos = c_port->write_end = NULL;
   c_port->write_buf_size = c_port->read_buf_size = 0;
 
-  /* Mark PORT as open, writable and unbuffered.  */
-  SCM_SET_CELL_TYPE (port, custom_binary_output_port_type | mode_bits);
-
-  scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
-
   return port;
 }
 
@@ -1105,13 +1074,8 @@ make_tp (SCM binary_port, unsigned long mode)
   scm_t_port *c_port;
   const unsigned long mode_bits = SCM_OPN | mode;
   
-  scm_i_pthread_mutex_lock (&scm_i_port_table_mutex);
-
-  port = scm_new_port_table_entry (transcoded_port_type);
-
-  SCM_SETSTREAM (port, SCM_UNPACK (binary_port));
-
-  SCM_SET_CELL_TYPE (port, transcoded_port_type | mode_bits);
+  port = scm_c_make_port (transcoded_port_type, mode_bits,
+                          SCM_UNPACK (binary_port));
 
   if (SCM_INPUT_PORT_P (port))
     {
@@ -1124,8 +1088,6 @@ make_tp (SCM binary_port, unsigned long mode)
       SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0);
     }
   
-  scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
-
   return port;
 }
 
diff --git a/libguile/strports.c b/libguile/strports.c
index b7fec47..2b3a5ea 100644
--- a/libguile/strports.c
+++ b/libguile/strports.c
@@ -277,17 +277,14 @@ scm_mkstrport (SCM pos, SCM str, long modes, const char 
*caller)
 {
   SCM z, buf;
   scm_t_port *pt;
-  size_t str_len, c_pos;
+  const char *encoding;
+  size_t read_buf_size, str_len, c_pos;
   char *c_buf;
 
   if (!((modes & SCM_WRTNG) || (modes & SCM_RDNG)))
     scm_misc_error ("scm_mkstrport", "port must read or write", SCM_EOL);
 
-  scm_dynwind_begin (0);
-  scm_i_dynwind_pthread_mutex_lock (&scm_i_port_table_mutex);
-
-  z = scm_new_port_table_entry (scm_tc16_strport);
-  pt = SCM_PTAB_ENTRY(z);
+  encoding = scm_i_default_port_encoding ();
 
   if (scm_is_false (str))
     {
@@ -297,8 +294,8 @@ scm_mkstrport (SCM pos, SCM str, long modes, const char 
*caller)
       c_buf = (char *) SCM_BYTEVECTOR_CONTENTS (buf);
 
       /* Reset `read_buf_size'.  It will contain the actual number of
-        bytes written to PT.  */
-      pt->read_buf_size = 0;
+        bytes written to the port.  */
+      read_buf_size = 0;
       c_pos = 0;
     }
   else
@@ -308,8 +305,8 @@ scm_mkstrport (SCM pos, SCM str, long modes, const char 
*caller)
 
       SCM_ASSERT (scm_is_string (str), str, SCM_ARG1, caller);
 
-      /* Create a copy of STR in the encoding of PT.  */
-      copy = scm_to_stringn (str, &str_len, pt->encoding,
+      /* Create a copy of STR in ENCODING.  */
+      copy = scm_to_stringn (str, &str_len, encoding,
                             SCM_FAILED_CONVERSION_ERROR);
       buf = scm_c_make_bytevector (str_len);
       c_buf = (char *) SCM_BYTEVECTOR_CONTENTS (buf);
@@ -317,26 +314,26 @@ scm_mkstrport (SCM pos, SCM str, long modes, const char 
*caller)
       free (copy);
 
       c_pos = scm_to_unsigned_integer (pos, 0, str_len);
-      pt->read_buf_size = str_len;
+      read_buf_size = str_len;
     }
 
-  SCM_SETSTREAM (z, SCM_UNPACK (buf));
-  SCM_SET_CELL_TYPE (z, scm_tc16_strport | modes);
+  z = scm_c_make_port_with_encoding (scm_tc16_strport, modes,
+                                     encoding,
+                                     SCM_FAILED_CONVERSION_ERROR,
+                                     (scm_t_bits)buf);
 
+  pt = SCM_PTAB_ENTRY (z);
   pt->write_buf = pt->read_buf = (unsigned char *) c_buf;
   pt->read_pos = pt->write_pos = pt->read_buf + c_pos;
+  pt->read_buf_size = read_buf_size;
   pt->write_buf_size = str_len;
   pt->write_end = pt->read_end = pt->read_buf + pt->read_buf_size;
-
   pt->rw_random = 1;
 
-  scm_dynwind_end ();
-
   /* Ensure WRITE_POS is writable.  */
   if ((modes & SCM_WRTNG) && pt->write_pos == pt->write_end)
     st_flush (z);
 
-  scm_i_set_conversion_strategy_x (z, SCM_FAILED_CONVERSION_ERROR);
   return z;
 }
 
diff --git a/libguile/symbols.c b/libguile/symbols.c
index 59aca00..1739ac0 100644
--- a/libguile/symbols.c
+++ b/libguile/symbols.c
@@ -33,8 +33,7 @@
 #include "libguile/fluids.h"
 #include "libguile/strings.h"
 #include "libguile/vectors.h"
-#include "libguile/hashtab.h"
-#include "libguile/weaks.h"
+#include "libguile/weak-set.h"
 #include "libguile/modules.h"
 #include "libguile/read.h"
 #include "libguile/srfi-13.h"
@@ -52,7 +51,6 @@
 
 
 static SCM symbols;
-static scm_i_pthread_mutex_t symbols_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER;
 
 #ifdef GUILE_DEBUG
 SCM_DEFINE (scm_sys_symbols, "%symbols", 0, 0, 0,
@@ -104,21 +102,13 @@ static SCM
 lookup_interned_symbol (SCM name, unsigned long raw_hash)
 {
   struct string_lookup_data data;
-  SCM handle;
 
   data.string = name;
   data.string_hash = raw_hash;
   
-  scm_i_pthread_mutex_lock (&symbols_lock);
-  handle = scm_hash_fn_get_handle_by_hash (symbols, raw_hash,
-                                           string_lookup_predicate_fn,
-                                           &data);  
-  scm_i_pthread_mutex_unlock (&symbols_lock);
-
-  if (scm_is_true (handle))
-    return SCM_CAR (handle);
-  else
-    return SCM_BOOL_F;
+  return scm_c_weak_set_lookup (symbols, raw_hash,
+                                string_lookup_predicate_fn,
+                                &data, SCM_BOOL_F);
 }
 
 struct latin1_lookup_data
@@ -144,63 +134,37 @@ lookup_interned_latin1_symbol (const char *str, size_t 
len,
                                unsigned long raw_hash)
 {
   struct latin1_lookup_data data;
-  SCM handle;
 
   data.str = str;
   data.len = len;
   data.string_hash = raw_hash;
   
-  scm_i_pthread_mutex_lock (&symbols_lock);
-  handle = scm_hash_fn_get_handle_by_hash (symbols, raw_hash,
-                                           latin1_lookup_predicate_fn,
-                                           &data);  
-  scm_i_pthread_mutex_unlock (&symbols_lock);
-
-  if (scm_is_true (handle))
-    return SCM_CAR (handle);
-  else
-    return SCM_BOOL_F;
+  return scm_c_weak_set_lookup (symbols, raw_hash,
+                                latin1_lookup_predicate_fn,
+                                &data, SCM_BOOL_F);
 }
 
-static unsigned long
-symbol_lookup_hash_fn (SCM obj, unsigned long max, void *closure)
+static int
+symbol_lookup_predicate_fn (SCM sym, void *closure)
 {
-  return scm_i_symbol_hash (obj) % max;
-}
+  SCM other = PTR2SCM (closure);
 
-static SCM
-symbol_lookup_assoc_fn (SCM obj, SCM alist, void *closure)
-{
-  for (; !scm_is_null (alist); alist = SCM_CDR (alist))
+  if (scm_i_symbol_hash (sym) == scm_i_symbol_hash (other)
+      && scm_i_symbol_length (sym) == scm_i_symbol_length (other))
     {
-      SCM sym = SCM_CAAR (alist);
-
-      if (scm_i_symbol_hash (sym) == scm_i_symbol_hash (obj)
-          && scm_is_true (scm_string_equal_p (scm_symbol_to_string (sym),
-                                              scm_symbol_to_string (obj))))
-        return SCM_CAR (alist);
+      if (scm_i_is_narrow_symbol (sym))
+        return scm_i_is_narrow_symbol (other)
+          && (strncmp (scm_i_symbol_chars (sym),
+                       scm_i_symbol_chars (other),
+                       scm_i_symbol_length (other)) == 0);
+      else
+        return scm_is_true
+          (scm_string_equal_p (scm_symbol_to_string (sym),
+                               scm_symbol_to_string (other)));
     }
-
-  return SCM_BOOL_F;
+  return 0;
 }
-
-/* Intern SYMBOL, an uninterned symbol.  Might return a different
-   symbol, if another one was interned at the same time.  */
-static SCM
-intern_symbol (SCM symbol)
-{
-  SCM handle;
-
-  scm_i_pthread_mutex_lock (&symbols_lock);
-  handle = scm_hash_fn_create_handle_x (symbols, symbol, SCM_UNDEFINED,
-                                        symbol_lookup_hash_fn,
-                                        symbol_lookup_assoc_fn,
-                                        NULL);
-  scm_i_pthread_mutex_unlock (&symbols_lock);
-
-  return SCM_CAR (handle);
-}
-
+ 
 static SCM
 scm_i_str2symbol (SCM str)
 {
@@ -215,7 +179,12 @@ scm_i_str2symbol (SCM str)
       /* The symbol was not found, create it.  */
       symbol = scm_i_make_symbol (str, 0, raw_hash,
                                  scm_cons (SCM_BOOL_F, SCM_EOL));
-      return intern_symbol (symbol);
+
+      /* Might return a different symbol, if another one was interned at
+         the same time.  */
+      return scm_c_weak_set_add_x (symbols, raw_hash,
+                                   symbol_lookup_predicate_fn,
+                                   SCM2PTR (symbol), symbol);
     }
 }
 
@@ -497,7 +466,7 @@ scm_from_utf8_symboln (const char *sym, size_t len)
 void
 scm_symbols_prehistory ()
 {
-  symbols = scm_make_weak_key_hash_table (scm_from_int (2139));
+  symbols = scm_c_make_weak_set (5000);
 }
 
 
diff --git a/libguile/tags.h b/libguile/tags.h
index c90838e..f5a07dc 100644
--- a/libguile/tags.h
+++ b/libguile/tags.h
@@ -123,51 +123,57 @@ typedef union SCM { struct { scm_t_bits n; } n; } SCM;
 
 /* Representation of scheme objects:
  *
- * Guile's type system is designed to work on systems where scm_t_bits and SCM
- * variables consist of at least 32 bits.  The objects that a SCM variable can
- * represent belong to one of the following two major categories:
- *
- * - Immediates -- meaning that the SCM variable contains an entire Scheme
- *   object.  That means, all the object's data (including the type tagging
- *   information that is required to identify the object's type) must fit into
- *   32 bits.
- *
- * - Non-immediates -- meaning that the SCM variable holds a pointer into the
- *   heap of cells (see below).  On systems where a pointer needs more than 32
- *   bits this means that scm_t_bits and SCM variables need to be large enough
- *   to hold such pointers.  In contrast to immediates, the object's data of
- *   a non-immediate can consume arbitrary amounts of memory: The heap cell
- *   being pointed to consists of at least two scm_t_bits variables and thus
- *   can be used to hold pointers to malloc'ed memory of any size.
- *
- * The 'heap' is the memory area that is under control of Guile's garbage
- * collector.  It holds 'single-cells' or 'double-cells', which consist of
- * either two or four scm_t_bits variables, respectively.  It is guaranteed
- * that the address of a cell on the heap is 8-byte aligned.  That is, since
- * non-immediates hold a cell address, the three least significant bits of a
- * non-immediate can be used to store additional information.  The bits are
- * used to store information about the object's type and thus are called
- * tc3-bits, where tc stands for type-code.  
- *
- * For a given SCM value, the distinction whether it holds an immediate or
- * non-immediate object is based on the tc3-bits (see above) of its scm_t_bits
+ * Guile's type system is designed to work on systems where scm_t_bits
+ * and SCM variables consist of at least 32 bits.  The objects that a
+ * SCM variable can represent belong to one of the following two major
+ * categories:
+ *
+ * - Immediates -- meaning that the SCM variable contains an entire
+ *   Scheme object.  That means, all the object's data (including the
+ *   type tagging information that is required to identify the object's
+ *   type) must fit into 32 bits.
+ *
+ * - Heap objects -- meaning that the SCM variable holds a pointer into
+ *   the heap.  On systems where a pointer needs more than 32 bits this
+ *   means that scm_t_bits and SCM variables need to be large enough to
+ *   hold such pointers.  In contrast to immediates, the data associated
+ *   with a heap object can consume arbitrary amounts of memory.
+ *
+ * The 'heap' is the memory area that is under control of Guile's
+ * garbage collector.  It holds allocated memory of various sizes.  The
+ * impact on the runtime type system is that Guile needs to be able to
+ * determine the type of an object given the pointer.  Usually the way
+ * that Guile does this is by storing a "type tag" in the first word of
+ * the object.
+ *
+ * Some objects are common enough that they get special treatment.
+ * Since Guile guarantees that the address of a GC-allocated object on
+ * the heap is 8-byte aligned, Guile can play tricks with the lower 3
+ * bits.  That is, since heap objects encode a pointer to an
+ * 8-byte-aligned pointer, the three least significant bits of a SCM can
+ * be used to store additional information.  The bits are used to store
+ * information about the object's type and thus are called tc3-bits,
+ * where tc stands for type-code.
+ *
+ * For a given SCM value, the distinction whether it holds an immediate
+ * or heap object is based on the tc3-bits (see above) of its scm_t_bits
  * equivalent: If the tc3-bits equal #b000, then the SCM value holds a
- * non-immediate, and the scm_t_bits variable's value is just the pointer to
- * the heap cell.
+ * heap object, and the scm_t_bits variable's value is just the pointer
+ * to the heap cell.
  *
  * Summarized, the data of a scheme object that is represented by a SCM
- * variable consists of a) the SCM variable itself, b) in case of
- * non-immediates the data of the single-cell or double-cell the SCM object
- * points to, c) in case of non-immediates potentially additional data outside
- * of the heap (like for example malloc'ed data), and d) in case of
- * non-immediates potentially additional data inside of the heap, since data
- * stored in b) and c) may hold references to other cells.
+ * variable consists of a) the SCM variable itself, b) in case of heap
+ * objects memory that the SCM object points to, c) in case of heap
+ * objects potentially additional data outside of the heap (like for
+ * example malloc'ed data), and d) in case of heap objects potentially
+ * additional data inside of the heap, since data stored in b) and c)
+ * may hold references to other cells.
  *
  *
  * Immediates
  *
  * Operations on immediate objects can typically be processed faster than on
- * non-immediates.  The reason is that the object's data can be extracted
+ * heap objects.  The reason is that the object's data can be extracted
  * directly from the SCM variable (or rather a corresponding scm_t_bits
  * variable), instead of having to perform additional memory accesses to
  * obtain the object's data from the heap.  In order to get the best possible
@@ -201,69 +207,56 @@ typedef union SCM { struct { scm_t_bits n; } n; } SCM;
  * special objects listed above.
  *
  *
- * Non-Immediates
- *
- * All object types not mentioned above in the list of immedate objects are
- * represented as non-immediates.  Whether a non-immediate scheme object is
- * represented by a single-cell or a double-cell depends on the object's type,
- * namely on the set of attributes that have to be stored with objects of that
- * type.  Every non-immediate type is allowed to define its own layout and
- * interpretation of the data stored in its cell (with some restrictions, see
- * below).
- *
- * One of the design goals of guile's type system is to make it possible to
- * store a scheme pair with as little memory usage as possible.  The minimum
- * amount of memory that is required to store two scheme objects (car and cdr
- * of a pair) is the amount of memory required by two scm_t_bits or SCM
- * variables.  Therefore pairs in guile are stored in single-cells.
- *
- * Another design goal for the type system is to store procedure objects
- * created by lambda expresssions (closures) and class instances (goops
- * objects) with as little memory usage as possible.  Closures are represented
- * by a reference to the function code and a reference to the closure's
- * environment.  Class instances are represented by a reference to the
- * instance's class definition and a reference to the instance's data.  Thus,
- * closures as well as class instances also can be stored in single-cells.
- *
- * Certain other non-immediate types also store their data in single-cells.
- * By design decision, the heap is split into areas for single-cells and
- * double-cells, but not into areas for single-cells-holding-pairs and areas
- * for single-cells-holding-non-pairs.  Any single-cell on the heap therefore
- * can hold pairs (consisting of two scm_t_bits variables representing two
- * scheme objects - the car and cdr of the pair) and non-pairs (consisting of
- * two scm_t_bits variables that hold bit patterns as defined by the layout of
- * the corresponding object's type).
+ * Heap Objects
+ *
+ * All object types not mentioned above in the list of immedate objects
+ * are represented as heap objects.  The amount of memory referenced by
+ * a heap object depends on the object's type, namely on the set of
+ * attributes that have to be stored with objects of that type.  Every
+ * heap object type is allowed to define its own layout and
+ * interpretation of the data stored in its cell (with some
+ * restrictions, see below).
+ *
+ * One of the design goals of guile's type system is to make it possible
+ * to store a scheme pair with as little memory usage as possible.  The
+ * minimum amount of memory that is required to store two scheme objects
+ * (car and cdr of a pair) is the amount of memory required by two
+ * scm_t_bits or SCM variables.  Therefore pairs in guile are stored in
+ * two words, and are tagged with a bit pattern in the SCM value, not
+ * with a type tag on the heap.
  *
  *
  * Garbage collection
  *
- * During garbage collection, unreachable cells on the heap will be freed.
- * That is, the garbage collector will detect cells which have no SCM variable
- * pointing towards them.  In order to properly release all memory belonging
- * to the object to which a cell belongs, the gc needs to be able to interpret
- * the cell contents in the correct way.  That means that the gc needs to be
- * able to determine the object type associated with a cell only from the cell
- * itself.
- *
- * Consequently, if the gc detects an unreachable single-cell, those two
- * scm_t_bits variables must provide enough information to determine whether
- * they belong to a pair (i. e. both scm_t_bits variables represent valid
- * scheme objects), to a closure, a class instance or if they belong to any
- * other non-immediate.  Guile's type system is designed to make it possible
- * to determine a the type to which a cell belongs in the majority of cases
- * from the cell's first scm_t_bits variable.  (Given a SCM variable X holding
- * a non-immediate object, the macro SCM_CELL_TYPE(X) will deliver the
- * corresponding cell's first scm_t_bits variable.)
- *
- * If the cell holds a scheme pair, then we already know that the first
- * scm_t_bits variable of the cell will hold a scheme object with one of the
- * following tc3-codes: #b000 (non-immediate), #b010 (small integer), #b110
- * (small integer), #b100 (non-integer immediate).  All these tc3-codes have
- * in common, that their least significant bit is #b0.  This fact is used by
- * the garbage collector to identify cells that hold pairs.  The remaining
- * tc3-codes are assigned as follows: #b001 (class instance or, more
- * precisely, a struct, of which a class instance is a special case), #b011
- * (closure), #b101/#b111 (all remaining non-immediate types).
+ * During garbage collection, unreachable objects on the heap will be
+ * freed.  To determine the set of reachable objects, by default, the GC
+ * just traces all words in all heap objects.  It is possible to
+ * register custom tracing ("marking") procedures.
+ *
+ * If an object is unreachable, by default, the GC just notes this fact
+ * and moves on.  Later allocations will clear out the memory associated
+ * with the object, and re-use it.  It is possible to register custom
+ * finalizers, however.
+ *
+ *
+ * Run-time type introspection
+ *
+ * Guile's type system is designed to make it possible to determine a
+ * the type of a heap object from the object's first scm_t_bits
+ * variable.  (Given a SCM variable X holding a heap object, the macro
+ * SCM_CELL_TYPE(X) will deliver the corresponding object's first
+ * scm_t_bits variable.)
+ *
+ * If the object holds a scheme pair, then we already know that the
+ * first scm_t_bits variable of the cell will hold a scheme object with
+ * one of the following tc3-codes: #b000 (heap object), #b010 (small
+ * integer), #b110 (small integer), #b100 (non-integer immediate).  All
+ * these tc3-codes have in common, that their least significant bit is
+ * #b0.  This fact is used by the garbage collector to identify cells
+ * that hold pairs.  The remaining tc3-codes are assigned as follows:
+ * #b001 (class instance or, more precisely, a struct, of which a class
+ * instance is a special case), #b011 (closure), #b101/#b111 (all
+ * remaining heap object types).
  *
  *
  * Summary of type codes of scheme objects (SCM variables)
@@ -274,7 +267,7 @@ typedef union SCM { struct { scm_t_bits n; } n; } SCM;
  * of the SCM variables corresponding scm_t_bits value.
  *
  * Note that (as has been explained above) tc1==1 can only occur in the first
- * scm_t_bits variable of a cell belonging to a non-immediate object that is
+ * scm_t_bits variable of a cell belonging to a heap object that is
  * not a pair.  For an explanation of the tc tags with tc1==1, see the next
  * section with the summary of the type codes on the heap.
  *
@@ -283,13 +276,13 @@ typedef union SCM { struct { scm_t_bits n; } n; } SCM;
  *  (1:  This can never be the case for a scheme object.)
  *
  * tc2:
- *   00:  Either a non-immediate or some non-integer immediate
+ *   00:  Either a heap object or some non-integer immediate
  *  (01:  This can never be the case for a scheme object.)
  *   10:  Small integer
  *  (11:  This can never be the case for a scheme object.)
  *
  * tc3:
- *   000:  a non-immediate object (pair, closure, class instance etc.)
+ *   000:  a heap object (pair, closure, class instance etc.)
  *  (001:  This can never be the case for a scheme object.)
  *   010:  an even small integer (least significant bit is 0).
  *  (011:  This can never be the case for a scheme object.)
@@ -298,8 +291,8 @@ typedef union SCM { struct { scm_t_bits n; } n; } SCM;
  *   110:  an odd small integer (least significant bit is 1).
  *  (111:  This can never be the case for a scheme object.)
  *
- * The remaining bits of the non-immediate objects form the pointer to the
- * heap cell.  The remaining bits of the small integers form the integer's
+ * The remaining bits of the heap objects form the pointer to the heap
+ * cell.  The remaining bits of the small integers form the integer's
  * value and sign.  Thus, the only scheme objects for which a further
  * subdivision is of interest are the ones with tc3==100.
  *
@@ -321,19 +314,19 @@ typedef union SCM { struct { scm_t_bits n; } n; } SCM;
  *
  * tc2:
  *   00:  the cell belongs to a pair with no short integer in its car.
- *   01:  the cell belongs to a non-pair (struct or some other non-immediate).
+ *   01:  the cell belongs to a non-pair (struct or some other heap object).
  *   10:  the cell belongs to a pair with a short integer in its car.
- *   11:  the cell belongs to a non-pair (closure or some other non-immediate).
+ *   11:  the cell belongs to a non-pair (closure or some other heap object).
  *
  * tc3:
- *   000:  the cell belongs to a pair with a non-immediate in its car.
+ *   000:  the cell belongs to a pair with a heap object in its car.
  *   001:  the cell belongs to a struct
  *   010:  the cell belongs to a pair with an even short integer in its car.
  *   011:  the cell belongs to a closure
  *   100:  the cell belongs to a pair with a non-integer immediate in its car.
- *   101:  the cell belongs to some other non-immediate.
+ *   101:  the cell belongs to some other heap object.
  *   110:  the cell belongs to a pair with an odd short integer in its car.
- *   111:  the cell belongs to some other non-immediate.
+ *   111:  the cell belongs to some other heap object.
  *
  * tc7 (for tc3==1x1):
  *   See below for the list of types.  Note the special case of scm_tc7_vector
@@ -352,7 +345,7 @@ typedef union SCM { struct { scm_t_bits n; } n; } SCM;
 
 
 
-/* Checking if a SCM variable holds an immediate or a non-immediate object:
+/* Checking if a SCM variable holds an immediate or a heap object:
  * This check can either be performed by checking for tc3==000 or tc3==00x,
  * since for a SCM variable it is known that tc1==0.  */
 #define SCM_IMP(x)             (6 & SCM_UNPACK (x))
@@ -364,7 +357,7 @@ typedef union SCM { struct { scm_t_bits n; } n; } SCM;
 
 /* Checking if a SCM variable holds a pair (for historical reasons, in Guile
  * also known as a cons-cell): This is done by first checking that the SCM
- * variable holds a non-immediate, and second, by checking that tc1==0 holds
+ * variable holds a heap object, and second, by checking that tc1==0 holds
  * for the SCM_CELL_TYPE of the SCM variable.  
 */
 
@@ -424,7 +417,7 @@ typedef union SCM { struct { scm_t_bits n; } n; } SCM;
 #define scm_tc7_with_fluids    63
 #define scm_tc7_unused_19      69
 #define scm_tc7_program                79
-#define scm_tc7_unused_9       85
+#define scm_tc7_weak_set       85
 #define scm_tc7_unused_10      87
 #define scm_tc7_unused_20      93
 #define scm_tc7_unused_11      95
@@ -621,7 +614,7 @@ enum scm_tc8_tags
   case scm_tc2_int + 112: case scm_tc2_int + 116: case scm_tc3_imm24 + 112:\
   case scm_tc2_int + 120: case scm_tc2_int + 124: case scm_tc3_imm24 + 120
 
-/* For cons pairs with non-immediate values in the SCM_CAR
+/* For cons pairs with heap objects in the SCM_CAR
  */
 #define scm_tcs_cons_nimcar \
        scm_tc3_cons + 0:\
diff --git a/libguile/vports.c b/libguile/vports.c
index 5178d79..05d4590 100644
--- a/libguile/vports.c
+++ b/libguile/vports.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995,1996,1998,1999,2000,2001, 2002, 2003, 2006, 2009, 2010 
Free Software Foundation, Inc.
+/* Copyright (C) 1995,1996,1998,1999,2000,2001, 2002, 2003, 2006, 2009, 2010, 
2011 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
@@ -198,7 +198,6 @@ SCM_DEFINE (scm_make_soft_port, "make-soft-port", 2, 0, 0,
 #define FUNC_NAME s_scm_make_soft_port
 {
   int vlen;
-  scm_t_port *pt;
   SCM z;
 
   SCM_VALIDATE_VECTOR (1, pv);
@@ -206,14 +205,10 @@ SCM_DEFINE (scm_make_soft_port, "make-soft-port", 2, 0, 0,
   SCM_ASSERT ((vlen == 5) || (vlen == 6), pv, 1, FUNC_NAME);
   SCM_VALIDATE_STRING (2, modes);
   
-  scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
-  z = scm_new_port_table_entry (scm_tc16_sfport);
-  pt = SCM_PTAB_ENTRY (z);
-  scm_port_non_buffer (pt);
-  SCM_SET_CELL_TYPE (z, scm_tc16_sfport | scm_i_mode_bits (modes));
-
-  SCM_SETSTREAM (z, SCM_UNPACK (pv));
-  scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
+  z = scm_c_make_port (scm_tc16_sfport, scm_i_mode_bits (modes),
+                       SCM_UNPACK (pv));
+  scm_port_non_buffer (SCM_PTAB_ENTRY (z));
+
   return z;
 }
 #undef FUNC_NAME
diff --git a/libguile/weak-set.c b/libguile/weak-set.c
new file mode 100644
index 0000000..7f7717e
--- /dev/null
+++ b/libguile/weak-set.c
@@ -0,0 +1,887 @@
+/* Copyright (C) 2011 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
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+
+#include "libguile/_scm.h"
+#include "libguile/hash.h"
+#include "libguile/eval.h"
+#include "libguile/ports.h"
+#include "libguile/bdw-gc.h"
+
+#include "libguile/validate.h"
+#include "libguile/weak-set.h"
+
+
+/* Weak Sets
+
+   This file implements weak sets.  One example of a weak set is the
+   symbol table, where you want all instances of the `foo' symbol to map
+   to one object.  So when you load a file and it wants a symbol with
+   the characters "foo", you one up in the table, using custom hash and
+   equality predicates.  Only if one is not found will you bother to
+   cons one up and intern it.
+
+   Another use case for weak sets is the set of open ports.  Guile needs
+   to be able to flush them all when the process exits, but the set
+   shouldn't prevent the GC from collecting the port (and thus closing
+   it).
+
+   Weak sets are implemented using an open-addressed hash table.
+   Basically this means that there is an array of entries, and the item
+   is expected to be found the slot corresponding to its hash code,
+   modulo the length of the array.
+
+   Collisions are handled using linear probing with the Robin Hood
+   technique.  See Pedro Celis' paper, "Robin Hood Hashing":
+
+     http://www.cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf
+
+   The vector of entries is allocated as an "atomic" piece of memory, so
+   that the GC doesn't trace it.  When an item is added to the set, a
+   disappearing link is registered to its location.  If the item is
+   collected, then that link will be zeroed out.
+
+   An entry is not just an item, though; the hash code is also stored in
+   the entry.  We munge hash codes so that they are never 0.  In this
+   way we can detect removed entries (key of zero but nonzero hash
+   code), and can then reshuffle elements as needed to maintain the
+   robin hood ordering.
+
+   Compared to buckets-and-chains hash tables, open addressing has the
+   advantage that it is very cache-friendly.  It also uses less memory.
+
+   Implementation-wise, there are two things to note.
+
+     1. We assume that hash codes are evenly distributed across the
+        range of unsigned longs.  The actual hash code stored in the
+        entry is left-shifted by 1 bit (losing 1 bit of hash precision),
+        and then or'd with 1.  In this way we ensure that the hash field
+        of an occupied entry is nonzero.  To map to an index, we
+        right-shift the hash by one, divide by the size, and take the
+        remainder.
+
+     2. Since the "keys" (the objects in the set) are stored in an
+        atomic region with disappearing links, they need to be accessed
+        with the GC alloc lock.  `copy_weak_entry' will do that for
+        you.  The hash code itself can be read outside the lock,
+        though.
+*/
+
+
+typedef struct {
+  unsigned long hash;
+  scm_t_bits key;
+} scm_t_weak_entry;
+
+
+struct weak_entry_data {
+  scm_t_weak_entry *in;
+  scm_t_weak_entry *out;
+};
+  
+static void*
+do_copy_weak_entry (void *data)
+{
+  struct weak_entry_data *e = data;
+
+  e->out->hash = e->in->hash;
+  e->out->key = e->in->key;
+
+  return NULL;
+}
+
+static void
+copy_weak_entry (scm_t_weak_entry *src, scm_t_weak_entry *dst)
+{
+  struct weak_entry_data data;
+
+  data.in = src;
+  data.out = dst;
+      
+  GC_call_with_alloc_lock (do_copy_weak_entry, &data);
+}
+  
+
+typedef struct {
+  scm_t_weak_entry *entries;    /* the data */
+  scm_i_pthread_mutex_t lock;   /* the lock */
+  unsigned long size;          /* total number of slots. */
+  unsigned long n_items;       /* number of items in set */
+  unsigned long lower;         /* when to shrink */
+  unsigned long upper;         /* when to grow */
+  int size_index;              /* index into hashset_size */
+  int min_size_index;          /* minimum size_index */
+} scm_t_weak_set;
+
+
+#define SCM_WEAK_SET_P(x) (!SCM_IMP (x) && SCM_TYP7(x) == scm_tc7_weak_set)
+#define SCM_VALIDATE_WEAK_SET(pos, arg) \
+  SCM_MAKE_VALIDATE_MSG (pos, arg, WEAK_SET_P, "weak-set")
+#define SCM_WEAK_SET(x) ((scm_t_weak_set *) SCM_CELL_WORD_1 (x))
+
+
+static unsigned long
+hash_to_index (unsigned long hash, unsigned long size)
+{
+  return (hash >> 1) % size;
+}
+
+static unsigned long
+entry_distance (unsigned long hash, unsigned long k, unsigned long size)
+{
+  unsigned long origin = hash_to_index (hash, size);
+
+  if (k >= origin)
+    return k - origin;
+  else
+    /* The other key was displaced and wrapped around.  */
+    return size - origin + k;
+}
+
+static void
+move_weak_entry (scm_t_weak_entry *from, scm_t_weak_entry *to)
+{
+  if (from->hash)
+    {
+      scm_t_weak_entry copy;
+      
+      copy_weak_entry (from, &copy);
+      to->hash = copy.hash;
+      to->key = copy.key;
+
+      if (copy.key && SCM_NIMP (SCM_PACK (copy.key)))
+        {
+          GC_unregister_disappearing_link ((GC_PTR) &from->key);
+          SCM_I_REGISTER_DISAPPEARING_LINK ((GC_PTR) &to->key,
+                                            (GC_PTR) to->key);
+        }
+    }
+  else
+    {
+      to->hash = 0;
+      to->key = 0;
+    }
+}
+
+static void
+rob_from_rich (scm_t_weak_set *set, unsigned long k)
+{
+  unsigned long empty, size;
+
+  size = set->size;
+
+  /* If we are to free up slot K in the set, we need room to do so.  */
+  assert (set->n_items < size);
+  
+  empty = k;
+  do 
+    empty = (empty + 1) % size;
+  /* Here we access key outside the lock.  Is this a problem?  At first
+     glance, I wouldn't think so.  */
+  while (set->entries[empty].key);
+
+  do
+    {
+      unsigned long last = empty ? (empty - 1) : (size - 1);
+      move_weak_entry (&set->entries[last], &set->entries[empty]);
+      empty = last;
+    }
+  while (empty != k);
+
+  /* Just for sanity.  */
+  set->entries[empty].hash = 0;
+  set->entries[empty].key = 0;
+}
+
+static void
+give_to_poor (scm_t_weak_set *set, unsigned long k)
+{
+  /* Slot K was just freed up; possibly shuffle others down.  */
+  unsigned long size = set->size;
+
+  while (1)
+    {
+      unsigned long next = (k + 1) % size;
+      unsigned long hash;
+      scm_t_weak_entry copy;
+
+      hash = set->entries[next].hash;
+
+      if (!hash || hash_to_index (hash, size) == next)
+        break;
+
+      copy_weak_entry (&set->entries[next], &copy);
+
+      if (!copy.key)
+        /* Lost weak reference.  */
+        {
+          give_to_poor (set, next);
+          set->n_items--;
+          continue;
+        }
+
+      move_weak_entry (&set->entries[next], &set->entries[k]);
+
+      k = next;
+    }
+
+  /* We have shuffled down any entries that should be shuffled down; now
+     free the end.  */
+  set->entries[k].hash = 0;
+  set->entries[k].key = 0;
+}
+
+
+
+
+/* Growing or shrinking is triggered when the load factor
+ *
+ *   L = N / S    (N: number of items in set, S: bucket vector length)
+ *
+ * passes an upper limit of 0.9 or a lower limit of 0.2.
+ *
+ * The implementation stores the upper and lower number of items which
+ * trigger a resize in the hashset object.
+ *
+ * Possible hash set sizes (primes) are stored in the array
+ * hashset_size.
+ */
+
+static unsigned long hashset_size[] = {
+  31, 61, 113, 223, 443, 883, 1759, 3517, 7027, 14051, 28099, 56197, 112363,
+  224717, 449419, 898823, 1797641, 3595271, 7190537, 14381041, 28762081,
+  57524111, 115048217, 230096423
+};
+
+#define HASHSET_SIZE_N (sizeof(hashset_size)/sizeof(unsigned long))
+
+static void
+resize_set (scm_t_weak_set *set)
+{
+  scm_t_weak_entry *old_entries, *new_entries;
+  int i;
+  unsigned long old_size, new_size, old_k;
+
+  old_entries = set->entries;
+  old_size = set->size;
+  
+  if (set->n_items < set->lower)
+    {
+      /* rehashing is not triggered when i <= min_size */
+      i = set->size_index;
+      do
+       --i;
+      while (i > set->min_size_index
+            && set->n_items < hashset_size[i] / 4);
+    }
+  else
+    {
+      i = set->size_index + 1;
+      if (i >= HASHSET_SIZE_N)
+        /* The biggest size currently is 230096423, which for a 32-bit
+           machine will occupy 1.5GB of memory at a load of 80%.  There
+           is probably something better to do here, but if you have a
+           weak map of that size, you are hosed in any case.  */
+        abort ();
+    }
+
+  new_size = hashset_size[i];
+  new_entries = scm_gc_malloc_pointerless (new_size * sizeof(scm_t_weak_entry),
+                                           "weak set");
+  memset (new_entries, 0, new_size * sizeof(scm_t_weak_entry));
+
+  set->size_index = i;
+  set->size = new_size;
+  if (i <= set->min_size_index)
+    set->lower = 0;
+  else
+    set->lower = new_size / 5;
+  set->upper = 9 * new_size / 10;
+  set->n_items = 0;
+  set->entries = new_entries;
+
+  for (old_k = 0; old_k < old_size; old_k++)
+    {
+      scm_t_weak_entry copy;
+      unsigned long new_k, distance;
+
+      if (!old_entries[old_k].hash)
+        continue;
+      
+      copy_weak_entry (&old_entries[old_k], &copy);
+      
+      if (!copy.key)
+        continue;
+      
+      new_k = hash_to_index (copy.hash, new_size);
+
+      for (distance = 0; ; distance++, new_k = (new_k + 1) % new_size)
+        {
+          unsigned long other_hash = new_entries[new_k].hash;
+
+          if (!other_hash)
+            /* Found an empty entry. */
+            break;
+
+          /* Displace the entry if our distance is less, otherwise keep
+             looking. */
+          if (entry_distance (other_hash, new_k, new_size) < distance)
+            {
+              rob_from_rich (set, new_k);
+              break;
+            }
+        }
+          
+      set->n_items++;
+      new_entries[new_k].hash = copy.hash;
+      new_entries[new_k].key = copy.key;
+
+      if (SCM_NIMP (SCM_PACK (copy.key)))
+        SCM_I_REGISTER_DISAPPEARING_LINK ((GC_PTR) &new_entries[new_k].key,
+                                          (GC_PTR) new_entries[new_k].key);
+    }
+}
+
+/* Run after GC via do_vacuum_weak_set, this function runs over the
+   whole table, removing lost weak references, reshuffling the set as it
+   goes.  It might resize the set if it reaps enough entries.  */
+static void
+vacuum_weak_set (scm_t_weak_set *set)
+{
+  scm_t_weak_entry *entries = set->entries;
+  unsigned long size = set->size;
+  unsigned long k;
+
+  for (k = 0; k < size; k++)
+    {
+      unsigned long hash = entries[k].hash;
+      
+      if (hash)
+        {
+          scm_t_weak_entry copy;
+
+          copy_weak_entry (&entries[k], &copy);
+
+          if (!copy.key)
+            /* Lost weak reference; reshuffle.  */
+            {
+              give_to_poor (set, k);
+              set->n_items--;
+            }
+        }
+    }
+
+  if (set->n_items < set->lower)
+    resize_set (set);
+}
+
+
+
+
+static SCM
+weak_set_lookup (scm_t_weak_set *set, unsigned long hash,
+                 scm_t_set_predicate_fn pred, void *closure,
+                 SCM dflt)
+{
+  unsigned long k, distance, size;
+  scm_t_weak_entry *entries;
+  
+  size = set->size;
+  entries = set->entries;
+
+  hash = (hash << 1) | 0x1;
+  k = hash_to_index (hash, size);
+  
+  for (distance = 0; distance < size; distance++, k = (k + 1) % size)
+    {
+      unsigned long other_hash;
+
+    retry:
+      other_hash = entries[k].hash;
+
+      if (!other_hash)
+        /* Not found. */
+        return dflt;
+
+      if (hash == other_hash)
+        {
+          scm_t_weak_entry copy;
+          
+          copy_weak_entry (&entries[k], &copy);
+
+          if (!copy.key)
+            /* Lost weak reference; reshuffle.  */
+            {
+              give_to_poor (set, k);
+              set->n_items--;
+              goto retry;
+            }
+
+          if (pred (SCM_PACK (copy.key), closure))
+            /* Found. */
+            return SCM_PACK (copy.key);
+        }
+
+      /* If the entry's distance is less, our key is not in the set.  */
+      if (entry_distance (other_hash, k, size) < distance)
+        return dflt;
+    }
+
+  /* If we got here, then we were unfortunate enough to loop through the
+     whole set.  Shouldn't happen, but hey.  */
+  return dflt;
+}
+
+
+static SCM
+weak_set_add_x (scm_t_weak_set *set, unsigned long hash,
+                scm_t_set_predicate_fn pred, void *closure,
+                SCM obj)
+{
+  unsigned long k, distance, size;
+  scm_t_weak_entry *entries;
+  
+  size = set->size;
+  entries = set->entries;
+
+  hash = (hash << 1) | 0x1;
+  k = hash_to_index (hash, size);
+
+  for (distance = 0; ; distance++, k = (k + 1) % size)
+    {
+      unsigned long other_hash;
+
+    retry:
+      other_hash = entries[k].hash;
+
+      if (!other_hash)
+        /* Found an empty entry. */
+        break;
+
+      if (other_hash == hash)
+        {
+          scm_t_weak_entry copy;
+
+          copy_weak_entry (&entries[k], &copy);
+          
+          if (!copy.key)
+            /* Lost weak reference; reshuffle.  */
+            {
+              give_to_poor (set, k);
+              set->n_items--;
+              goto retry;
+            }
+
+          if (pred (SCM_PACK (copy.key), closure))
+            /* Found an entry with this key. */
+            return SCM_PACK (copy.key);
+        }
+
+      if (set->n_items > set->upper)
+        /* Full set, time to resize.  */
+        {
+          resize_set (set);
+          return weak_set_add_x (set, hash >> 1, pred, closure, obj);
+        }
+
+      /* Displace the entry if our distance is less, otherwise keep
+         looking. */
+      if (entry_distance (other_hash, k, size) < distance)
+        {
+          rob_from_rich (set, k);
+          break;
+        }
+    }
+          
+  set->n_items++;
+  entries[k].hash = hash;
+  entries[k].key = SCM_UNPACK (obj);
+
+  if (SCM_NIMP (obj))
+    SCM_I_REGISTER_DISAPPEARING_LINK ((GC_PTR) &entries[k].key,
+                                      (GC_PTR) SCM2PTR (obj));
+
+  return obj;
+}
+
+
+static void
+weak_set_remove_x (scm_t_weak_set *set, unsigned long hash,
+                   scm_t_set_predicate_fn pred, void *closure)
+{
+  unsigned long k, distance, size;
+  scm_t_weak_entry *entries;
+  
+  size = set->size;
+  entries = set->entries;
+
+  hash = (hash << 1) | 0x1;
+  k = hash_to_index (hash, size);
+
+  for (distance = 0; distance < size; distance++, k = (k + 1) % size)
+    {
+      unsigned long other_hash;
+
+    retry:
+      other_hash = entries[k].hash;
+
+      if (!other_hash)
+        /* Not found. */
+        return;
+
+      if (other_hash == hash)
+        {
+          scm_t_weak_entry copy;
+      
+          copy_weak_entry (&entries[k], &copy);
+          
+          if (!copy.key)
+            /* Lost weak reference; reshuffle.  */
+            {
+              give_to_poor (set, k);
+              set->n_items--;
+              goto retry;
+            }
+
+          if (pred (SCM_PACK (copy.key), closure))
+            /* Found an entry with this key. */
+            {
+              entries[k].hash = 0;
+              entries[k].key = 0;
+
+              if (SCM_NIMP (SCM_PACK (copy.key)))
+                GC_unregister_disappearing_link ((GC_PTR) &entries[k].key);
+
+              if (--set->n_items < set->lower)
+                resize_set (set);
+              else
+                give_to_poor (set, k);
+
+              return;
+            }
+        }
+
+      /* If the entry's distance is less, our key is not in the set.  */
+      if (entry_distance (other_hash, k, size) < distance)
+        return;
+    }
+}
+
+
+
+static SCM
+make_weak_set (unsigned long k)
+{
+  scm_t_weak_set *set;
+
+  int i = 0, n = k ? k : 31;
+  while (i + 1 < HASHSET_SIZE_N && n > hashset_size[i])
+    ++i;
+  n = hashset_size[i];
+
+  set = scm_gc_malloc (sizeof (*set), "weak-set");
+  set->entries = scm_gc_malloc_pointerless (n * sizeof(scm_t_weak_entry),
+                                            "weak-set");
+  memset (set->entries, 0, n * sizeof(scm_t_weak_entry));
+  set->n_items = 0;
+  set->size = n;
+  set->lower = 0;
+  set->upper = 9 * n / 10;
+  set->size_index = i;
+  set->min_size_index = i;
+  scm_i_pthread_mutex_init (&set->lock, NULL);
+
+  return scm_cell (scm_tc7_weak_set, (scm_t_bits)set);
+}
+
+void
+scm_i_weak_set_print (SCM exp, SCM port, scm_print_state *pstate)
+{
+  scm_puts ("#<", port);
+  scm_puts ("weak-set ", port);
+  scm_uintprint (SCM_WEAK_SET (exp)->n_items, 10, port);
+  scm_putc ('/', port);
+  scm_uintprint (SCM_WEAK_SET (exp)->size, 10, port);
+  scm_puts (">", port);
+}
+
+static void
+do_vacuum_weak_set (SCM set)
+{
+  scm_t_weak_set *s;
+
+  s = SCM_WEAK_SET (set);
+
+  if (scm_i_pthread_mutex_trylock (&s->lock) == 0)
+    {
+      vacuum_weak_set (s);
+      scm_i_pthread_mutex_unlock (&s->lock);
+    }
+
+  return;
+}
+
+/* The before-gc C hook only runs if GC_set_start_callback is available,
+   so if not, fall back on a finalizer-based implementation.  */
+static int
+weak_gc_callback (void **weak)
+{
+  void *val = weak[0];
+  void (*callback) (SCM) = weak[1];
+  
+  if (!val)
+    return 0;
+  
+  callback (PTR2SCM (val));
+
+  return 1;
+}
+
+#ifdef HAVE_GC_SET_START_CALLBACK
+static void*
+weak_gc_hook (void *hook_data, void *fn_data, void *data)
+{
+  if (!weak_gc_callback (fn_data))
+    scm_c_hook_remove (&scm_before_gc_c_hook, weak_gc_hook, fn_data);
+
+  return NULL;
+}
+#else
+static void
+weak_gc_finalizer (void *ptr, void *data)
+{
+  if (weak_gc_callback (ptr))
+    GC_REGISTER_FINALIZER_NO_ORDER (ptr, weak_gc_finalizer, data, NULL, NULL);
+}
+#endif
+
+static void
+scm_c_register_weak_gc_callback (SCM obj, void (*callback) (SCM))
+{
+  void **weak = GC_MALLOC_ATOMIC (sizeof (void*) * 2);
+
+  weak[0] = SCM2PTR (obj);
+  weak[1] = (void*)callback;
+  GC_GENERAL_REGISTER_DISAPPEARING_LINK (weak, SCM2PTR (obj));
+
+#ifdef HAVE_GC_SET_START_CALLBACK
+  scm_c_hook_add (&scm_after_gc_c_hook, weak_gc_hook, weak, 0);
+#else
+  GC_REGISTER_FINALIZER_NO_ORDER (weak, weak_gc_finalizer, NULL, NULL, NULL);
+#endif
+}
+
+SCM
+scm_c_make_weak_set (unsigned long k)
+{
+  SCM ret;
+
+  ret = make_weak_set (k);
+
+  scm_c_register_weak_gc_callback (ret, do_vacuum_weak_set);
+
+  return ret;
+}
+
+SCM
+scm_weak_set_p (SCM obj)
+{
+  return scm_from_bool (SCM_WEAK_SET_P (obj));
+}
+
+SCM
+scm_weak_set_clear_x (SCM set)
+{
+  scm_t_weak_set *s = SCM_WEAK_SET (set);
+
+  scm_i_pthread_mutex_lock (&s->lock);
+
+  memset (s->entries, 0, sizeof (scm_t_weak_entry) * s->size);
+  s->n_items = 0;
+
+  scm_i_pthread_mutex_unlock (&s->lock);
+
+  return SCM_UNSPECIFIED;
+}
+
+SCM
+scm_c_weak_set_lookup (SCM set, unsigned long raw_hash,
+                       scm_t_set_predicate_fn pred,
+                       void *closure, SCM dflt)
+{
+  SCM ret;
+  scm_t_weak_set *s = SCM_WEAK_SET (set);
+
+  scm_i_pthread_mutex_lock (&s->lock);
+
+  ret = weak_set_lookup (s, raw_hash, pred, closure, dflt);
+
+  scm_i_pthread_mutex_unlock (&s->lock);
+
+  return ret;
+}
+
+SCM
+scm_c_weak_set_add_x (SCM set, unsigned long raw_hash,
+                      scm_t_set_predicate_fn pred,
+                      void *closure, SCM obj)
+{
+  SCM ret;
+  scm_t_weak_set *s = SCM_WEAK_SET (set);
+
+  scm_i_pthread_mutex_lock (&s->lock);
+
+  ret = weak_set_add_x (s, raw_hash, pred, closure, obj);
+
+  scm_i_pthread_mutex_unlock (&s->lock);
+
+  return ret;
+}
+
+void
+scm_c_weak_set_remove_x (SCM set, unsigned long raw_hash,
+                         scm_t_set_predicate_fn pred,
+                         void *closure)
+{
+  scm_t_weak_set *s = SCM_WEAK_SET (set);
+
+  scm_i_pthread_mutex_lock (&s->lock);
+
+  weak_set_remove_x (s, raw_hash, pred, closure);
+
+  scm_i_pthread_mutex_unlock (&s->lock);
+}
+
+static int
+eq_predicate (SCM x, void *closure)
+{
+  return scm_is_eq (x, PTR2SCM (closure));
+}
+
+SCM
+scm_weak_set_add_x (SCM set, SCM obj)
+{
+  return scm_c_weak_set_add_x (set, scm_ihashq (obj, -1),
+                               eq_predicate, SCM2PTR (obj), obj);
+}
+
+SCM
+scm_weak_set_remove_x (SCM set, SCM obj)
+{
+  scm_c_weak_set_remove_x (set, scm_ihashq (obj, -1),
+                           eq_predicate, SCM2PTR (obj));
+
+  return SCM_UNSPECIFIED;
+}
+
+SCM
+scm_c_weak_set_fold (scm_t_set_fold_fn proc, void *closure,
+                     SCM init, SCM set)
+{
+  scm_t_weak_set *s;
+  scm_t_weak_entry *entries;
+  unsigned long k, size;
+
+  s = SCM_WEAK_SET (set);
+
+  scm_i_pthread_mutex_lock (&s->lock);
+
+  size = s->size;
+  entries = s->entries;
+
+  for (k = 0; k < size; k++)
+    {
+      if (entries[k].hash)
+        {
+          scm_t_weak_entry copy;
+          
+          copy_weak_entry (&entries[k], &copy);
+      
+          if (copy.key)
+            {
+              /* Release set lock while we call the function.  */
+              scm_i_pthread_mutex_unlock (&s->lock);
+              init = proc (closure, SCM_PACK (copy.key), init);
+              scm_i_pthread_mutex_lock (&s->lock);
+            }
+        }
+    }
+  
+  scm_i_pthread_mutex_unlock (&s->lock);
+  
+  return init;
+}
+
+static SCM
+fold_trampoline (void *closure, SCM item, SCM init)
+{
+  return scm_call_2 (PTR2SCM (closure), item, init);
+}
+
+SCM
+scm_weak_set_fold (SCM proc, SCM init, SCM set)
+{
+  return scm_c_weak_set_fold (fold_trampoline, SCM2PTR (proc), init, set);
+}
+
+static SCM
+for_each_trampoline (void *closure, SCM item, SCM seed)
+{
+  scm_call_1 (PTR2SCM (closure), item);
+  return seed;
+}
+
+SCM
+scm_weak_set_for_each (SCM proc, SCM set)
+{
+  scm_c_weak_set_fold (for_each_trampoline, SCM2PTR (proc), SCM_BOOL_F, set);
+
+  return SCM_UNSPECIFIED;
+}
+
+static SCM
+map_trampoline (void *closure, SCM item, SCM seed)
+{
+  return scm_cons (scm_call_1 (PTR2SCM (closure), item), seed);
+}
+
+SCM
+scm_weak_set_map_to_list (SCM proc, SCM set)
+{
+  return scm_c_weak_set_fold (map_trampoline, SCM2PTR (proc), SCM_EOL, set);
+}
+
+
+void
+scm_init_weak_set ()
+{
+#include "libguile/weak-set.x"
+}
+
+/*
+  Local Variables:
+  c-file-style: "gnu"
+  End:
+*/
diff --git a/libguile/weak-set.h b/libguile/weak-set.h
new file mode 100644
index 0000000..86781c7
--- /dev/null
+++ b/libguile/weak-set.h
@@ -0,0 +1,69 @@
+/* classes: h_files */
+
+#ifndef SCM_WEAK_SET_H
+#define SCM_WEAK_SET_H
+
+/* Copyright (C) 2011 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
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+
+
+#include "libguile/__scm.h"
+
+
+
+/* The weak set API is currently only used internally.  We could make it
+   public later, after some API review.  */
+
+/* Function that returns nonzero if the given object is the one we are
+   looking for.  */
+typedef int (*scm_t_set_predicate_fn) (SCM obj, void *closure);
+
+/* Function to fold over the elements of a set.  */
+typedef SCM (*scm_t_set_fold_fn) (void *closure, SCM key, SCM result);
+
+SCM_INTERNAL SCM scm_c_make_weak_set (unsigned long k);
+SCM_INTERNAL SCM scm_weak_set_p (SCM h);
+SCM_INTERNAL SCM scm_c_weak_set_lookup (SCM set, unsigned long raw_hash,
+                                        scm_t_set_predicate_fn pred,
+                                        void *closure, SCM dflt);
+SCM_INTERNAL SCM scm_c_weak_set_add_x (SCM set, unsigned long raw_hash,
+                                       scm_t_set_predicate_fn pred,
+                                       void *closure, SCM obj);
+SCM_INTERNAL void scm_c_weak_set_remove_x (SCM set, unsigned long raw_hash,
+                                           scm_t_set_predicate_fn pred,
+                                           void *closure);
+SCM_INTERNAL SCM scm_weak_set_add_x (SCM set, SCM obj);
+SCM_INTERNAL SCM scm_weak_set_remove_x (SCM set, SCM obj);
+SCM_INTERNAL SCM scm_weak_set_clear_x (SCM set);
+SCM_INTERNAL SCM scm_c_weak_set_fold (scm_t_set_fold_fn proc, void *closure,
+                                      SCM init, SCM set);
+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_print (SCM exp, SCM port, scm_print_state 
*pstate);
+SCM_INTERNAL void scm_init_weak_set (void);
+
+#endif  /* SCM_WEAK_SET_H */
+
+/*
+  Local Variables:
+  c-file-style: "gnu"
+  End:
+*/


hooks/post-receive
-- 
GNU Guile



reply via email to

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