1 /* Copyright (C) 2016  Free Software Foundation, Inc.
2  *
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public License
5  * as published by the Free Software Foundation; either version 3 of
6  * the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16  * 02110-1301 USA
17  */
18 
19 
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23 
24 #include "libguile/_scm.h"
25 #include "libguile/hashtab.h"
26 #include "libguile/numbers.h"
27 #include "libguile/fdes-finalizers.h"
28 
29 
30 
31 /* Table of fdes finalizers and associated lock.  */
32 static scm_i_pthread_mutex_t fdes_finalizers_lock =
33   SCM_I_PTHREAD_MUTEX_INITIALIZER;
34 static SCM fdes_finalizers;
35 
36 SCM_DEFINE (scm_add_fdes_finalizer_x, "add-fdes-finalizer!", 2, 0, 0,
37             (SCM fd, SCM finalizer),
38 	    "Add a finalizer that will be called when @var{fd} is closed.")
39 #define FUNC_NAME s_scm_add_fdes_finalizer_x
40 {
41   SCM h;
42 
43   /* Check type.  */
44   scm_to_uint (fd);
45 
46   scm_i_pthread_mutex_lock (&fdes_finalizers_lock);
47   h = scm_hashv_create_handle_x (fdes_finalizers, fd, SCM_EOL);
48   scm_set_cdr_x (h, scm_cons (finalizer, scm_cdr (h)));
49   scm_i_pthread_mutex_unlock (&fdes_finalizers_lock);
50 
51   return SCM_UNSPECIFIED;
52 }
53 #undef FUNC_NAME
54 
55 SCM_DEFINE (scm_remove_fdes_finalizer_x, "remove-fdes-finalizer!", 2, 0, 0,
56             (SCM fd, SCM finalizer),
57 	    "Remove a finalizer that was previously added to the file\n"
58             "descriptor @var{fd}.")
59 #define FUNC_NAME s_scm_remove_fdes_finalizer_x
60 {
61   SCM h;
62 
63   /* Check type.  */
64   scm_to_uint (fd);
65 
66   scm_i_pthread_mutex_lock (&fdes_finalizers_lock);
67   h = scm_hashv_get_handle (fdes_finalizers, fd);
68   if (scm_is_true (h))
69     scm_set_cdr_x (h, scm_delq1_x (finalizer, scm_cdr (h)));
70   scm_i_pthread_mutex_unlock (&fdes_finalizers_lock);
71 
72   return SCM_UNSPECIFIED;
73 }
74 #undef FUNC_NAME
75 
76 struct fdes_finalizer_data
77 {
78   SCM finalizer;
79   SCM fd;
80 };
81 
82 static SCM
do_run_finalizer(void * data)83 do_run_finalizer (void *data)
84 {
85   struct fdes_finalizer_data *fdata = data;
86   return scm_call_1 (fdata->finalizer, fdata->fd);
87 }
88 
89 void
scm_run_fdes_finalizers(int fd)90 scm_run_fdes_finalizers (int fd)
91 {
92   SCM finalizers;
93   struct fdes_finalizer_data data;
94 
95   data.fd = scm_from_int (fd);
96 
97   scm_i_pthread_mutex_lock (&fdes_finalizers_lock);
98   finalizers = scm_hashv_ref (fdes_finalizers, data.fd, SCM_EOL);
99   if (!scm_is_null (finalizers))
100     scm_hashv_remove_x (fdes_finalizers, data.fd);
101   scm_i_pthread_mutex_unlock (&fdes_finalizers_lock);
102 
103   for (; !scm_is_null (finalizers); finalizers = scm_cdr (finalizers))
104     {
105       data.finalizer = scm_car (finalizers);
106       scm_internal_catch (SCM_BOOL_T, do_run_finalizer, &data,
107                           scm_handle_by_message_noexit, NULL);
108     }
109 }
110 
111 
112 
113 
114 static void
scm_init_fdes_finalizers(void)115 scm_init_fdes_finalizers (void)
116 {
117 #include "libguile/fdes-finalizers.x"
118 }
119 
120 void
scm_register_fdes_finalizers()121 scm_register_fdes_finalizers ()
122 {
123   fdes_finalizers = scm_c_make_hash_table (0);
124 
125   scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
126                             "scm_init_fdes_finalizers",
127                             (scm_t_extension_init_func) scm_init_fdes_finalizers,
128                             NULL);
129 }
130