1 /* Test the allocate_once function.
2 Copyright (C) 2018-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <allocate_once.h>
22 #include <support/check.h>
23 #include <support/support.h>
25 /* Allocate a new string. */
27 allocate_string (void *closure
)
29 return xstrdup (closure
);
32 /* Allocation and deallocation functions which are not expected to be
36 allocate_not_called (void *closure
)
38 FAIL_EXIT1 ("allocation function called unexpectedly (%p)", closure
);
42 deallocate_not_called (void *closure
, void *ptr
)
44 FAIL_EXIT1 ("deallocate function called unexpectedly (%p, %p)",
48 /* Counter for various function calls. */
49 static int function_called
;
51 /* An allocation function which returns NULL and records that it has
54 allocate_return_null (void *closure
)
56 /* The function should only be called once. */
57 TEST_COMPARE (function_called
, 0);
63 /* The following is used to check the retry logic, by causing a fake
65 static void *fake_race_place
;
66 static char fake_race_region
[3]; /* To obtain unique addresses. */
69 fake_race_allocate (void *closure
)
71 TEST_VERIFY (closure
== &fake_race_region
[0]);
72 TEST_COMPARE (function_called
, 0);
74 /* Fake allocation by another thread. */
75 fake_race_place
= &fake_race_region
[1];
76 return &fake_race_region
[2];
80 fake_race_deallocate (void *closure
, void *ptr
)
82 /* Check that the pointer returned from fake_race_allocate is
83 deallocated (and not the one stored in fake_race_place). */
84 TEST_VERIFY (ptr
== &fake_race_region
[2]);
86 TEST_VERIFY (fake_race_place
== &fake_race_region
[1]);
87 TEST_VERIFY (closure
== &fake_race_region
[0]);
88 TEST_COMPARE (function_called
, 1);
92 /* Similar to fake_race_allocate, but expects to be paired with free
93 as the deallocation function. */
95 fake_race_allocate_for_free (void *closure
)
97 TEST_VERIFY (closure
== &fake_race_region
[0]);
98 TEST_COMPARE (function_called
, 0);
100 /* Fake allocation by another thread. */
101 fake_race_place
= &fake_race_region
[1];
102 return xstrdup ("to be freed");
110 /* Simple allocation. */
112 char *string1
= allocate_once (&place1
, allocate_string
,
113 deallocate_not_called
,
114 (char *) "test string 1");
115 TEST_VERIFY_EXIT (string1
!= NULL
);
116 TEST_VERIFY (strcmp ("test string 1", string1
) == 0);
117 /* Second call returns the first pointer, without calling any
120 == allocate_once (&place1
, allocate_not_called
,
121 deallocate_not_called
,
122 (char *) "test string 1a"));
124 /* Different place should result in another call. */
126 char *string2
= allocate_once (&place2
, allocate_string
,
127 deallocate_not_called
,
128 (char *) "test string 2");
129 TEST_VERIFY_EXIT (string2
!= NULL
);
130 TEST_VERIFY (strcmp ("test string 2", string2
) == 0);
131 TEST_VERIFY (string1
!= string2
);
133 /* Check error reporting (NULL return value from the allocation
136 char *string3
= allocate_once (&place3
, allocate_return_null
,
137 deallocate_not_called
, NULL
);
138 TEST_VERIFY (string3
== NULL
);
139 TEST_COMPARE (function_called
, 1);
141 /* Check that the deallocation function is called if the race is
144 TEST_VERIFY (allocate_once (&fake_race_place
,
146 fake_race_deallocate
,
147 &fake_race_region
[0])
148 == &fake_race_region
[1]);
149 TEST_COMPARE (function_called
, 2);
151 TEST_VERIFY (allocate_once (&fake_race_place
,
153 fake_race_deallocate
,
154 &fake_race_region
[0])
155 == &fake_race_region
[1]);
156 TEST_COMPARE (function_called
, 3);
158 /* Similar, but this time rely on that free is called. */
160 fake_race_place
= NULL
;
161 TEST_VERIFY (allocate_once (&fake_race_place
,
162 fake_race_allocate_for_free
,
164 &fake_race_region
[0])
165 == &fake_race_region
[1]);
166 TEST_COMPARE (function_called
, 1);
168 TEST_VERIFY (allocate_once (&fake_race_place
,
169 fake_race_allocate_for_free
,
171 &fake_race_region
[0])
172 == &fake_race_region
[1]);
173 TEST_COMPARE (function_called
, 3);
181 #include <support/test-driver.c>