diff --git a/libguile/ports.c b/libguile/ports.c index 278bbe9e7..1209b439a 100644 --- a/libguile/ports.c +++ b/libguile/ports.c @@ -691,6 +691,7 @@ finalize_port (void *ptr, void *data) if (SCM_OPENP (port)) { + SCM_SET_PORT_FINALIZING (port); scm_internal_catch (SCM_BOOL_T, do_close, ptr, scm_handle_by_message_noexit, NULL); scm_gc_ports_collected++; @@ -2797,7 +2798,31 @@ scm_i_write_bytes (SCM port, SCM src, size_t start, size_t count) size_t ret = ptob->c_write (port, src, start + written, count - written); if (ret == (size_t) -1) - port_poll (port, POLLOUT, -1); + { + if (SCM_PORT_FINALIZING_P (port)) + { + /* This port is being closed because it became unreachable + and was finalized, but it has buffered output, and the + resource is not currently writable. Instead of + blocking, discard buffered output and warn. To avoid + this situation, force-output on the port before letting + it go! */ + scm_puts + ("Warning: Discarding buffered output on non-blocking port\n" + " ", + scm_current_warning_port ()); + scm_display (port, scm_current_warning_port()); + scm_puts + ("\n" + " closed by the garbage collector. To avoid this\n" + " behavior and this warning, call `force-output' or\n" + " `close-port' on the port before letting go of it.\n", + scm_current_warning_port ()); + break; + } + else + port_poll (port, POLLOUT, -1); + } else written += ret; } diff --git a/libguile/ports.h b/libguile/ports.h index 6fe9ecd2b..93a1a59de 100644 --- a/libguile/ports.h +++ b/libguile/ports.h @@ -52,11 +52,14 @@ SCM_INTERNAL SCM scm_i_port_weak_set; there is a flag indicating whether the port is open or not, and then some "mode bits": flags indicating whether the port is an input and/or an output port and how Guile should buffer the port. */ -#define SCM_OPN (1U<<16) /* Is the port open? */ -#define SCM_RDNG (1U<<17) /* Is it a readable port? */ -#define SCM_WRTNG (1U<<18) /* Is it writable? */ -#define SCM_BUF0 (1U<<19) /* Is it unbuffered? */ -#define SCM_BUFLINE (1U<<20) /* Is it line-buffered? */ +#define SCM_OPN (1U<<8) /* Is the port open? */ +#define SCM_RDNG (1U<<9) /* Is it a readable port? */ +#define SCM_WRTNG (1U<<10) /* Is it writable? */ +#define SCM_BUF0 (1U<<11) /* Is it unbuffered? */ +#define SCM_BUFLINE (1U<<12) /* Is it line-buffered? */ +#ifdef BUILDING_LIBGUILE +#define SCM_F_PORT_FINALIZING (1U<<13) /* Port is being closed via GC. */ +#endif #define SCM_PORTP(x) (SCM_HAS_TYP7 (x, scm_tc7_port)) #define SCM_OPPORTP(x) (SCM_PORTP (x) && (SCM_CELL_WORD_0 (x) & SCM_OPN)) @@ -68,6 +71,12 @@ SCM_INTERNAL SCM scm_i_port_weak_set; #define SCM_CLOSEDP(x) (!SCM_OPENP (x)) #define SCM_CLR_PORT_OPEN_FLAG(p) \ SCM_SET_CELL_WORD_0 ((p), SCM_CELL_WORD_0 (p) & ~SCM_OPN) +#ifdef BUILDING_LIBGUILE +#define SCM_PORT_FINALIZING_P(x) \ + (SCM_CELL_WORD_0 (x) & SCM_F_PORT_FINALIZING) +#define SCM_SET_PORT_FINALIZING(p) \ + SCM_SET_CELL_WORD_0 ((p), SCM_CELL_WORD_0 (p) | SCM_F_PORT_FINALIZING) +#endif typedef struct scm_t_port_type scm_t_port_type; typedef struct scm_t_port scm_t_port;