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