1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 11:40:18 +02:00

GC of non-blocking port does not block

* libguile/ports.h (SCM_F_PORT_FINALIZING)
  (SCM_PORT_FINALIZING_P, SCM_SET_PORT_FINALIZING): New private
  definitions.
* libguile/ports.c (finalize_port): Set the port-finalizing flag.
  (scm_i_write_bytes): If the port is finalizing but output returned
  EWOULDBLOCK, warn and discard the output.
This commit is contained in:
Andy Wingo 2016-08-31 19:31:12 +02:00
parent b8a53b98b3
commit b733ca461c
2 changed files with 40 additions and 6 deletions

View file

@ -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;
}

View file

@ -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;