diff options
author | Andy Wingo <wingo@pobox.com> | 2016-08-30 23:35:10 +0200 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2016-08-30 23:35:10 +0200 |
commit | 2fa2e50a0fdb49e70d6882e06d1a2dcc2ae10a69 (patch) | |
tree | 73aa2e3a049edb5109ec521eccde6d064a2fa7a8 /libguile | |
parent | 4256e0655f6b2aae53c3345196288c92423ff277 (diff) | |
download | guile-2fa2e50a0fdb49e70d6882e06d1a2dcc2ae10a69.tar.gz |
Add file descriptor finalizers
* doc/ref/posix.texi (Ports and File Descriptors): Document new
interfaces.
* libguile/filesys.c (scm_close, scm_close_fdes)
* libguile/fports.c (fport_close):
* libguile/ioext.c (scm_primitive_move_to_fdes): Call
scm_run_fdes_finalizers.
* module/ice-9/fdes-finalizers.scm:
* test-suite/tests/fdes-finalizers.test:
* libguile/fdes-finalizers.h:
* libguile/fdes-finalizers.c: New files.
* module/Makefile.am:
* test-suite/Makefile.am:
* libguile/Makefile.am:
* libguile.h:
* libguile/init.c: Wire up new files.
Diffstat (limited to 'libguile')
-rw-r--r-- | libguile/Makefile.am | 4 | ||||
-rw-r--r-- | libguile/fdes-finalizers.c | 129 | ||||
-rw-r--r-- | libguile/fdes-finalizers.h | 34 | ||||
-rw-r--r-- | libguile/filesys.c | 3 | ||||
-rw-r--r-- | libguile/fports.c | 2 | ||||
-rw-r--r-- | libguile/init.c | 2 | ||||
-rw-r--r-- | libguile/ioext.c | 2 |
7 files changed, 176 insertions, 0 deletions
diff --git a/libguile/Makefile.am b/libguile/Makefile.am index dab09e1a3..8161ade4e 100644 --- a/libguile/Makefile.am +++ b/libguile/Makefile.am @@ -143,6 +143,7 @@ libguile_@GUILE_EFFECTIVE_VERSION@_la_SOURCES = \ evalext.c \ expand.c \ extensions.c \ + fdes-finalizers.c \ feature.c \ filesys.c \ finalizers.c \ @@ -252,6 +253,7 @@ DOT_X_FILES = \ evalext.x \ expand.x \ extensions.x \ + fdes-finalizers.x \ feature.x \ filesys.x \ fluids.x \ @@ -358,6 +360,7 @@ DOT_DOC_FILES = \ evalext.doc \ expand.doc \ extensions.doc \ + fdes-finalizers.doc \ feature.doc \ filesys.doc \ fluids.doc \ @@ -586,6 +589,7 @@ modinclude_HEADERS = \ evalext.h \ expand.h \ extensions.h \ + fdes-finalizers.h \ feature.h \ finalizers.h \ filesys.h \ diff --git a/libguile/fdes-finalizers.c b/libguile/fdes-finalizers.c new file mode 100644 index 000000000..fd4689e13 --- /dev/null +++ b/libguile/fdes-finalizers.c @@ -0,0 +1,129 @@ +/* Copyright (C) 2016 Free Software Foundation, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libguile/_scm.h" +#include "libguile/hashtab.h" +#include "libguile/numbers.h" +#include "libguile/fdes-finalizers.h" + + + +/* Table of fdes finalizers and associated lock. */ +static scm_i_pthread_mutex_t fdes_finalizers_lock = + SCM_I_PTHREAD_MUTEX_INITIALIZER; +static SCM fdes_finalizers; + +SCM_DEFINE (scm_add_fdes_finalizer_x, "add-fdes-finalizer!", 2, 0, 0, + (SCM fd, SCM finalizer), + "Add a finalizer that will be called when @var{fd} is closed.") +#define FUNC_NAME s_scm_add_fdes_finalizer_x +{ + SCM h; + + /* Check type. */ + scm_to_uint (fd); + + scm_i_pthread_mutex_lock (&fdes_finalizers_lock); + h = scm_hashv_create_handle_x (fdes_finalizers, fd, SCM_EOL); + scm_set_cdr_x (h, scm_cons (finalizer, scm_cdr (h))); + scm_i_pthread_mutex_unlock (&fdes_finalizers_lock); + + return SCM_UNSPECIFIED; +} +#undef FUNC_NAME + +SCM_DEFINE (scm_remove_fdes_finalizer_x, "remove-fdes-finalizer!", 2, 0, 0, + (SCM fd, SCM finalizer), + "Remove a finalizer that was previously added to the file\n" + "descriptor @var{fd}.") +#define FUNC_NAME s_scm_remove_fdes_finalizer_x +{ + SCM h; + + /* Check type. */ + scm_to_uint (fd); + + scm_i_pthread_mutex_lock (&fdes_finalizers_lock); + h = scm_hashv_get_handle (fdes_finalizers, fd); + if (scm_is_true (h)) + scm_set_cdr_x (h, scm_delq1_x (finalizer, scm_cdr (h))); + scm_i_pthread_mutex_unlock (&fdes_finalizers_lock); + + return SCM_UNSPECIFIED; +} +#undef FUNC_NAME + +struct fdes_finalizer_data +{ + SCM finalizer; + SCM fd; +}; + +static SCM +do_run_finalizer (void *data) +{ + struct fdes_finalizer_data *fdata = data; + return scm_call_1 (fdata->finalizer, fdata->fd); +} + +void +scm_run_fdes_finalizers (int fd) +{ + SCM finalizers; + struct fdes_finalizer_data data; + + data.fd = scm_from_int (fd); + + scm_i_pthread_mutex_lock (&fdes_finalizers_lock); + finalizers = scm_hashv_ref (fdes_finalizers, data.fd, SCM_EOL); + if (!scm_is_null (finalizers)) + scm_hashv_remove_x (fdes_finalizers, data.fd); + scm_i_pthread_mutex_unlock (&fdes_finalizers_lock); + + for (; !scm_is_null (finalizers); finalizers = scm_cdr (finalizers)) + { + data.finalizer = scm_car (finalizers); + scm_internal_catch (SCM_BOOL_T, do_run_finalizer, &data, + scm_handle_by_message_noexit, NULL); + } +} + + + + +static void +scm_init_fdes_finalizers (void) +{ +#include "libguile/fdes-finalizers.x" +} + +void +scm_register_fdes_finalizers () +{ + fdes_finalizers = scm_c_make_hash_table (0); + + scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION, + "scm_init_fdes_finalizers", + (scm_t_extension_init_func) scm_init_fdes_finalizers, + NULL); +} diff --git a/libguile/fdes-finalizers.h b/libguile/fdes-finalizers.h new file mode 100644 index 000000000..cadbb0404 --- /dev/null +++ b/libguile/fdes-finalizers.h @@ -0,0 +1,34 @@ +#ifndef SCM_FDES_FINALIZERS_H +#define SCM_FDES_FINALIZERS_H + +/* Copyright (C) 2016 Free Software Foundation, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + + + +#include "libguile/__scm.h" + + + +SCM_INTERNAL SCM scm_add_fdes_finalizer_x (SCM fd, SCM finalizer); +SCM_INTERNAL SCM scm_remove_fdes_finalizer_x (SCM fd, SCM finalizer); +SCM_INTERNAL void scm_run_fdes_finalizers (int fd); + +SCM_INTERNAL void scm_register_fdes_finalizers (void); + +#endif /* SCM_FDES_FINALIZERS_H */ diff --git a/libguile/filesys.c b/libguile/filesys.c index c4f2653c2..0bc366953 100644 --- a/libguile/filesys.c +++ b/libguile/filesys.c @@ -43,6 +43,7 @@ #include "libguile/_scm.h" #include "libguile/smob.h" +#include "libguile/fdes-finalizers.h" #include "libguile/feature.h" #include "libguile/fports.h" #include "libguile/strings.h" @@ -290,6 +291,7 @@ SCM_DEFINE (scm_close, "close", 1, 0, 0, return scm_close_port (fd_or_port); fd = scm_to_int (fd_or_port); scm_evict_ports (fd); /* see scsh manual. */ + scm_run_fdes_finalizers (fd); SCM_SYSCALL (rv = close (fd)); /* following scsh, closing an already closed file descriptor is not an error. */ @@ -312,6 +314,7 @@ SCM_DEFINE (scm_close_fdes, "close-fdes", 1, 0, 0, int rv; c_fd = scm_to_int (fd); + scm_run_fdes_finalizers (c_fd); SCM_SYSCALL (rv = close (c_fd)); if (rv < 0) SCM_SYSERROR; diff --git a/libguile/fports.c b/libguile/fports.c index f535f8a25..5886f628d 100644 --- a/libguile/fports.c +++ b/libguile/fports.c @@ -49,6 +49,7 @@ #include <full-write.h> #include "libguile/_scm.h" +#include "libguile/fdes-finalizers.h" #include "libguile/strings.h" #include "libguile/validate.h" #include "libguile/gc.h" @@ -656,6 +657,7 @@ fport_close (SCM port) { scm_t_fport *fp = SCM_FSTREAM (port); + scm_run_fdes_finalizers (fp->fdes); if (close (fp->fdes) != 0) /* It's not useful to retry after EINTR, as the file descriptor is in an undefined state. See http://lwn.net/Articles/365294/. diff --git a/libguile/init.c b/libguile/init.c index 7e0c30d9c..1e4889c97 100644 --- a/libguile/init.c +++ b/libguile/init.c @@ -56,6 +56,7 @@ #include "libguile/eval.h" #include "libguile/evalext.h" #include "libguile/expand.h" +#include "libguile/fdes-finalizers.h" #include "libguile/feature.h" #include "libguile/filesys.h" #include "libguile/finalizers.h" @@ -398,6 +399,7 @@ scm_i_init_guile (void *base) scm_bootstrap_programs (); scm_bootstrap_vm (); scm_register_r6rs_ports (); + scm_register_fdes_finalizers (); scm_register_foreign (); scm_register_foreign_object (); scm_register_srfi_1 (); diff --git a/libguile/ioext.c b/libguile/ioext.c index 58a6219f3..43c915a09 100644 --- a/libguile/ioext.c +++ b/libguile/ioext.c @@ -29,6 +29,7 @@ #include "libguile/_scm.h" #include "libguile/dynwind.h" +#include "libguile/fdes-finalizers.h" #include "libguile/feature.h" #include "libguile/fports.h" #include "libguile/hashtab.h" @@ -266,6 +267,7 @@ SCM_DEFINE (scm_primitive_move_to_fdes, "primitive-move->fdes", 2, 0, 0, if (rv == -1) SCM_SYSERROR; stream->fdes = new_fd; + scm_run_fdes_finalizers (old_fd); SCM_SYSCALL (close (old_fd)); return SCM_BOOL_T; } |