diff options
author | Andy Wingo <wingo@pobox.com> | 2016-04-03 11:39:21 +0200 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2016-04-04 16:30:56 +0200 |
commit | 67b147fb7a5e8771b0314fcc0fcc826db09d9949 (patch) | |
tree | 16fb15deb0f53abbd4dfc8e511a4443aba775a66 | |
parent | 4460f1f15280e3378633115fe9035448a68c636b (diff) | |
download | guile-67b147fb7a5e8771b0314fcc0fcc826db09d9949.tar.gz |
Remove port free functions; just close instead
* libguile/ports.h (scm_t_port_type_flags): Replace
SCM_PORT_TYPE_HAS_FLUSH with SCM_PORT_TYPE_NEEDS_CLOSE_ON_GC.
(scm_t_ptob_descriptor): Remove free function.
* libguile/ports.c (scm_set_port_needs_close_on_gc): New function.
(scm_set_port_flush): Don't set flags.
(scm_c_make_port_with_encoding, scm_close_port): Use the new flag to
determine when to add a finalizer and also when to include the port in
the weak set.
(scm_set_port_free): Remove.
(do_close, finalize_port): Close port instead of calling free
function.
* libguile/r6rs-ports.c (initialize_transcoded_ports):
* libguile/vports.c (scm_make_sfptob):
* libguile/fports.c (scm_make_fptob): Mark these ports as needing close
on GC.
* libguile/fports.c (fport_free): Remove.
* NEWS: Update.
* doc/ref/api-io.texi (Port Implementation): Update.
-rw-r--r-- | NEWS | 11 | ||||
-rw-r--r-- | doc/ref/api-io.texi | 22 | ||||
-rw-r--r-- | libguile/fports.c | 9 | ||||
-rw-r--r-- | libguile/ports.c | 59 | ||||
-rw-r--r-- | libguile/ports.h | 7 | ||||
-rw-r--r-- | libguile/r6rs-ports.c | 1 | ||||
-rw-r--r-- | libguile/vports.c | 1 |
7 files changed, 50 insertions, 60 deletions
@@ -24,6 +24,17 @@ as arguments to the `setvbuf' function. Port mark functions have not been called since the switch to the BDW garbage collector. +** Remove `scm_set_port_free' + +It used to be that if an open port became unreachable, a special "free" +function would be called instead of the "close" function. Now that the +BDW-GC collector allows us to run arbitrary code in finalizers, we can +simplify to just call "close" on the port and remove the separate free +functions. Note that hooking into the garbage collector has some +overhead. For that reason Guile exposes a new interface, +`scm_set_port_needs_close_on_gc', allowing port implementations to +indicate to Guile whether they need closing on GC or not. + Changes in 2.1.2 (changes since the 2.1.1 alpha release): diff --git a/doc/ref/api-io.texi b/doc/ref/api-io.texi index 80a227202..c175d2eac 100644 --- a/doc/ref/api-io.texi +++ b/doc/ref/api-io.texi @@ -2303,14 +2303,6 @@ A pointer to a NUL terminated string: the name of the port type. This is the only element of @code{scm_ptob_descriptor} which is not a procedure. Set via the first argument to @code{scm_make_port_type}. -@item free -Called when the port is collected during gc. It -should free any resources used by the port. -Set using - -@deftypefun void scm_set_port_free (scm_t_bits tc, size_t (*free) (SCM port)) -@end deftypefun - @item print Called when @code{write} is called on the port object, to print a port description. E.g., for an fport it may produce something like: @@ -2328,13 +2320,21 @@ Not used at present. Set using @end deftypefun @item close -Called when the port is closed, unless it was collected during gc. It -should free any resources used by the port. -Set using +Called when the port is closed. It should free any resources used by +the port. Set using @deftypefun void scm_set_port_close (scm_t_bits tc, int (*close) (SCM port)) @end deftypefun +By default, ports that are garbage collected just go away without +closing. If your port type needs to release some external resource like +a file descriptor, or needs to make sure that its internal buffers are +flushed even if the port is collected while it was open, then mark the +port type as needing a close on GC. + +@deftypefun void scm_set_port_needs_close_on_gc (scm_t_bits tc, int needs_close_p) +@end deftypefun + @item write Accept data which is to be written using the port. The port implementation may choose to buffer the data instead of processing it directly. diff --git a/libguile/fports.c b/libguile/fports.c index 8ad8ba0ca..3f4c8cc2e 100644 --- a/libguile/fports.c +++ b/libguile/fports.c @@ -858,19 +858,12 @@ fport_close (SCM port) return 0; } -static size_t -fport_free (SCM port) -{ - fport_close (port); - return 0; -} - static scm_t_bits scm_make_fptob () { scm_t_bits tc = scm_make_port_type ("file", fport_fill_input, fport_write); - scm_set_port_free (tc, fport_free); + scm_set_port_needs_close_on_gc (tc, 1); scm_set_port_print (tc, fport_print); scm_set_port_flush (tc, fport_flush); scm_set_port_end_input (tc, fport_end_input); diff --git a/libguile/ports.c b/libguile/ports.c index 3f1b5b1c5..e42f983c5 100644 --- a/libguile/ports.c +++ b/libguile/ports.c @@ -268,12 +268,6 @@ scm_make_port_type (char *name, } void -scm_set_port_free (scm_t_bits tc, size_t (*free) (SCM)) -{ - scm_c_port_type_ref (SCM_TC2PTOBNUM (tc))->free = free; -} - -void scm_set_port_print (scm_t_bits tc, int (*print) (SCM exp, SCM port, scm_print_state *pstate)) { @@ -293,11 +287,20 @@ scm_set_port_close (scm_t_bits tc, int (*close) (SCM)) } void -scm_set_port_flush (scm_t_bits tc, void (*flush) (SCM port)) +scm_set_port_needs_close_on_gc (scm_t_bits tc, int needs_close_p) { scm_t_ptob_descriptor *ptob = scm_c_port_type_ref (SCM_TC2PTOBNUM (tc)); - ptob->flush = flush; - ptob->flags |= SCM_PORT_TYPE_HAS_FLUSH; + + if (needs_close_p) + ptob->flags |= SCM_PORT_TYPE_NEEDS_CLOSE_ON_GC; + else + ptob->flags &= ~SCM_PORT_TYPE_NEEDS_CLOSE_ON_GC; +} + +void +scm_set_port_flush (scm_t_bits tc, void (*flush) (SCM port)) +{ + scm_c_port_type_ref (SCM_TC2PTOBNUM (tc))->flush = flush; } void @@ -633,22 +636,10 @@ SCM scm_i_port_weak_set; /* Port finalization. */ -struct do_free_data -{ - scm_t_ptob_descriptor *ptob; - SCM port; -}; - static SCM -do_free (void *body_data) +do_close (void *data) { - struct do_free_data *data = body_data; - - /* `close' is for explicit `close-port' by user. `free' is for this - purpose: ports collected by the GC. */ - data->ptob->free (data->port); - - return SCM_BOOL_T; + return scm_close_port (SCM_PACK_POINTER (data)); } /* Finalize the object (a port) pointed to by PTR. */ @@ -662,16 +653,8 @@ finalize_port (void *ptr, void *data) if (SCM_OPENP (port)) { - struct do_free_data data; - - SCM_CLR_PORT_OPEN_FLAG (port); - - data.ptob = SCM_PORT_DESCRIPTOR (port); - data.port = port; - - scm_internal_catch (SCM_BOOL_T, do_free, &data, + scm_internal_catch (SCM_BOOL_T, do_close, ptr, scm_handle_by_message_noexit, NULL); - scm_gc_ports_collected++; } } @@ -732,11 +715,11 @@ scm_c_make_port_with_encoding (scm_t_bits tag, unsigned long mode_bits, pti->pending_eof = 0; pti->alist = SCM_EOL; - if (SCM_PORT_DESCRIPTOR (ret)->free) - scm_i_set_finalizer (SCM2PTR (ret), finalize_port, NULL); - - if (SCM_PORT_DESCRIPTOR (ret)->flags & SCM_PORT_TYPE_HAS_FLUSH) - scm_weak_set_add_x (scm_i_port_weak_set, ret); + if (SCM_PORT_DESCRIPTOR (ret)->flags & SCM_PORT_TYPE_NEEDS_CLOSE_ON_GC) + { + scm_i_set_finalizer (SCM2PTR (ret), finalize_port, NULL); + scm_weak_set_add_x (scm_i_port_weak_set, ret); + } return ret; } @@ -848,7 +831,7 @@ SCM_DEFINE (scm_close_port, "close-port", 1, 0, 0, pti = SCM_PORT_GET_INTERNAL (port); SCM_CLR_PORT_OPEN_FLAG (port); - if (SCM_PORT_DESCRIPTOR (port)->flags & SCM_PORT_TYPE_HAS_FLUSH) + if (SCM_PORT_DESCRIPTOR (port)->flags & SCM_PORT_TYPE_NEEDS_CLOSE_ON_GC) scm_weak_set_remove_x (scm_i_port_weak_set, port); if (SCM_PORT_DESCRIPTOR (port)->close) diff --git a/libguile/ports.h b/libguile/ports.h index f6c217fe3..379fba294 100644 --- a/libguile/ports.h +++ b/libguile/ports.h @@ -177,14 +177,15 @@ SCM_INTERNAL SCM scm_i_port_weak_set; typedef enum scm_t_port_type_flags { - SCM_PORT_TYPE_HAS_FLUSH = 1 << 0 + /* Indicates that the port should be closed if it is garbage collected + while it is open. */ + SCM_PORT_TYPE_NEEDS_CLOSE_ON_GC = 1 << 0 } scm_t_port_type_flags; /* port-type description. */ typedef struct scm_t_ptob_descriptor { char *name; - size_t (*free) (SCM); int (*print) (SCM exp, SCM port, scm_print_state *pstate); SCM (*equalp) (SCM, SCM); int (*close) (SCM port); @@ -223,13 +224,13 @@ SCM_API scm_t_bits scm_make_port_type (char *name, void (*write) (SCM port, const void *data, size_t size)); -SCM_API void scm_set_port_free (scm_t_bits tc, size_t (*free) (SCM)); SCM_API void scm_set_port_print (scm_t_bits tc, int (*print) (SCM exp, SCM port, scm_print_state *pstate)); SCM_API void scm_set_port_equalp (scm_t_bits tc, SCM (*equalp) (SCM, SCM)); SCM_API void scm_set_port_close (scm_t_bits tc, int (*close) (SCM)); +SCM_API void scm_set_port_needs_close_on_gc (scm_t_bits tc, int needs_close_p); SCM_API void scm_set_port_flush (scm_t_bits tc, void (*flush) (SCM port)); SCM_API void scm_set_port_end_input (scm_t_bits tc, diff --git a/libguile/r6rs-ports.c b/libguile/r6rs-ports.c index e4f3b5ca2..274560251 100644 --- a/libguile/r6rs-ports.c +++ b/libguile/r6rs-ports.c @@ -1249,6 +1249,7 @@ initialize_transcoded_ports (void) scm_set_port_flush (transcoded_port_type, tp_flush); scm_set_port_close (transcoded_port_type, tp_close); + scm_set_port_needs_close_on_gc (transcoded_port_type, 1); } SCM_INTERNAL SCM scm_i_make_transcoded_port (SCM); diff --git a/libguile/vports.c b/libguile/vports.c index 17eac8695..c08df2ed0 100644 --- a/libguile/vports.c +++ b/libguile/vports.c @@ -225,6 +225,7 @@ scm_make_sfptob () scm_set_port_flush (tc, sf_flush); scm_set_port_close (tc, sf_close); + scm_set_port_needs_close_on_gc (tc, 1); scm_set_port_input_waiting (tc, sf_input_waiting); return tc; |