[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Guile-commits] 02/02: GC of non-blocking port does not block
From: |
Andy Wingo |
Subject: |
[Guile-commits] 02/02: GC of non-blocking port does not block |
Date: |
Wed, 31 Aug 2016 17:33:07 +0000 (UTC) |
wingo pushed a commit to branch master
in repository guile.
commit b733ca461ce03c6daeadca0f2eb4da13ccdd2930
Author: Andy Wingo <address@hidden>
Date: Wed Aug 31 19:31:12 2016 +0200
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.
---
libguile/ports.c | 27 ++++++++++++++++++++++++++-
libguile/ports.h | 19 ++++++++++++++-----
2 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/libguile/ports.c b/libguile/ports.c
index 278bbe9..1209b43 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 6fe9ecd..93a1a59 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;