summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libguile/ports.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/libguile/ports.c b/libguile/ports.c
index a840ff538..391981bcc 100644
--- a/libguile/ports.c
+++ b/libguile/ports.c
@@ -697,15 +697,32 @@ SCM_DEFINE (scm_port_for_each, "port-for-each", 1, 0, 0,
#define FUNC_NAME s_scm_port_for_each
{
int i;
+ SCM ports;
+
SCM_VALIDATE_PROC (1, proc);
/* when pre-emptive multithreading is supported, access to the port
table will need to be controlled by a mutex. */
+
+ /* Even without pre-emptive multithreading, running arbitrary code
+ while scanning the port table is unsafe because the port table
+ can change arbitrarily (from a GC, for example). So we build a
+ list in advance while blocking the GC. -mvo */
+
SCM_DEFER_INTS;
+ scm_block_gc++;
+ ports = SCM_EOL;
for (i = 0; i < scm_port_table_size; i++)
+ ports = scm_cons (scm_port_table[i]->port, ports);
+ scm_block_gc--;
+ SCM_ALLOW_INTS;
+
+ while (ports != SCM_EOL)
{
- scm_apply (proc, scm_cons (scm_port_table[i]->port, SCM_EOL), SCM_EOL);
+ scm_apply (proc, scm_cons (SCM_CAR (ports), SCM_EOL), SCM_EOL);
+ ports = SCM_CDR (ports);
}
+
return SCM_UNSPECIFIED;
}
#undef FUNC_NAME