1 /* Copyright 2013-2014,2018
2      Free Software Foundation, Inc.
3 
4    This file is part of Guile.
5 
6    Guile is free software: you can redistribute it and/or modify it
7    under the terms of the GNU Lesser General Public License as published
8    by the Free Software Foundation, either version 3 of the License, or
9    (at your option) any later version.
10 
11    Guile is distributed in the hope that it will be useful, but WITHOUT
12    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14    License for more details.
15 
16    You should have received a copy of the GNU Lesser General Public
17    License along with Guile.  If not, see
18    <https://www.gnu.org/licenses/>.  */
19 
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 #undef NDEBUG
25 
26 #include <assert.h>
27 #include <libguile.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 
31 #define SMOBS_COUNT (10000)
32 
33 struct x_tag
34 {
35   SCM scm_value;
36   int c_value;
37 };
38 
39 typedef struct x_tag x_t;
40 
41 unsigned int mark_call_count = 0;
42 
43 static scm_t_bits x_tag;
44 static SCM make_x (void);
45 static SCM mark_x (SCM x);
46 static int print_x (SCM x, SCM port, scm_print_state * pstate);
47 static size_t free_x (SCM x);
48 static void init_smob_type (void);
49 static void test_scm_smob_mark (void);
50 
51 static SCM
make_x()52 make_x ()
53 {
54   static int i = 0;
55   SCM s_x;
56   x_t *c_x;
57 
58   i++;
59   c_x = (x_t *) scm_gc_malloc (sizeof (x_t), "x");
60   c_x->scm_value = scm_from_int (i);
61   c_x->c_value = i;
62   SCM_NEWSMOB (s_x, x_tag, c_x);
63   return s_x;
64 }
65 
66 static SCM
mark_x(SCM x)67 mark_x (SCM x)
68 {
69   x_t *c_x;
70   c_x = (x_t *) SCM_SMOB_DATA (x);
71   scm_gc_mark (c_x->scm_value);
72   mark_call_count++;
73   return SCM_BOOL_F;
74 }
75 
76 static size_t
free_x(SCM x)77 free_x (SCM x)
78 {
79   x_t *c_x;
80   c_x = (x_t *) SCM_SMOB_DATA (x);
81   scm_gc_free (c_x, sizeof (x_t), "x");
82   c_x = NULL;
83   return 0;
84 }
85 
86 static int
print_x(SCM x,SCM port,scm_print_state * pstate SCM_UNUSED)87 print_x (SCM x, SCM port, scm_print_state * pstate SCM_UNUSED)
88 {
89   x_t *c_x = (x_t *) SCM_SMOB_DATA (x);
90   scm_puts ("#<x ", port);
91   if (c_x == (x_t *) NULL)
92     scm_puts ("(freed)", port);
93   else
94     scm_write (c_x->scm_value, port);
95   scm_puts (">", port);
96 
97   return 1;
98 }
99 
100 static void
test_scm_smob_mark()101 test_scm_smob_mark ()
102 {
103   int i;
104   mark_call_count = 0;
105   for (i = 0; i < SMOBS_COUNT; i++)
106     make_x ();
107   scm_gc ();
108   if (mark_call_count < SMOBS_COUNT)
109     {
110       fprintf (stderr, "FAIL: SMOB mark function called for each SMOB\n");
111       exit (EXIT_FAILURE);
112     }
113 }
114 
115 static void
init_smob_type()116 init_smob_type ()
117 {
118   x_tag = scm_make_smob_type ("x", sizeof (x_t));
119   scm_set_smob_free (x_tag, free_x);
120   scm_set_smob_print (x_tag, print_x);
121   scm_set_smob_mark (x_tag, mark_x);
122 }
123 
124 static void
tests(void * data,int argc,char ** argv)125 tests (void *data, int argc, char **argv)
126 {
127   init_smob_type ();
128   test_scm_smob_mark ();
129 }
130 
131 int
main(int argc,char * argv[])132 main (int argc, char *argv[])
133 {
134   scm_boot_guile (argc, argv, tests, NULL);
135   return 0;
136 }
137