summaryrefslogtreecommitdiff
path: root/libguile/fdes-finalizers.c
blob: 4b3fced0268ca22ba751846a681682f8411dc2c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/* Copyright 2016,2018
     Free Software Foundation, Inc.

   This file is part of Guile.

   Guile 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.

   Guile 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 Guile.  If not, see
   <https://www.gnu.org/licenses/>.  */


#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "boolean.h"
#include "eval.h"
#include "extensions.h"
#include "gsubr.h"
#include "hashtab.h"
#include "list.h"
#include "numbers.h"
#include "pairs.h"
#include "threads.h"
#include "version.h"

#include "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 "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);
}