]>
Commit | Line | Data |
---|---|---|
5f7b841d | 1 | /* Test the allocate_once function. |
04277e02 | 2 | Copyright (C) 2018-2019 Free Software Foundation, Inc. |
5f7b841d FW |
3 | This file is part of the GNU C Library. |
4 | ||
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. | |
9 | ||
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. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; if not, see | |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
5f7b841d FW |
18 | |
19 | #include <allocate_once.h> | |
20 | #include <mcheck.h> | |
21 | #include <string.h> | |
22 | #include <support/check.h> | |
23 | #include <support/support.h> | |
24 | ||
25 | /* Allocate a new string. */ | |
26 | static void * | |
27 | allocate_string (void *closure) | |
28 | { | |
29 | return xstrdup (closure); | |
30 | } | |
31 | ||
32 | /* Allocation and deallocation functions which are not expected to be | |
33 | called. */ | |
34 | ||
35 | static void * | |
36 | allocate_not_called (void *closure) | |
37 | { | |
38 | FAIL_EXIT1 ("allocation function called unexpectedly (%p)", closure); | |
39 | } | |
40 | ||
41 | static void | |
42 | deallocate_not_called (void *closure, void *ptr) | |
43 | { | |
44 | FAIL_EXIT1 ("deallocate function called unexpectedly (%p, %p)", | |
45 | closure, ptr); | |
46 | } | |
47 | ||
48 | /* Counter for various function calls. */ | |
49 | static int function_called; | |
50 | ||
51 | /* An allocation function which returns NULL and records that it has | |
52 | been called. */ | |
53 | static void * | |
54 | allocate_return_null (void *closure) | |
55 | { | |
56 | /* The function should only be called once. */ | |
57 | TEST_COMPARE (function_called, 0); | |
58 | ++function_called; | |
59 | return NULL; | |
60 | } | |
61 | ||
62 | ||
63 | /* The following is used to check the retry logic, by causing a fake | |
64 | race condition. */ | |
65 | static void *fake_race_place; | |
66 | static char fake_race_region[3]; /* To obtain unique addresses. */ | |
67 | ||
68 | static void * | |
69 | fake_race_allocate (void *closure) | |
70 | { | |
71 | TEST_VERIFY (closure == &fake_race_region[0]); | |
72 | TEST_COMPARE (function_called, 0); | |
73 | ++function_called; | |
74 | /* Fake allocation by another thread. */ | |
75 | fake_race_place = &fake_race_region[1]; | |
76 | return &fake_race_region[2]; | |
77 | } | |
78 | ||
79 | static void | |
80 | fake_race_deallocate (void *closure, void *ptr) | |
81 | { | |
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]); | |
85 | ||
86 | TEST_VERIFY (fake_race_place == &fake_race_region[1]); | |
87 | TEST_VERIFY (closure == &fake_race_region[0]); | |
88 | TEST_COMPARE (function_called, 1); | |
89 | ++function_called; | |
90 | } | |
91 | ||
92 | /* Similar to fake_race_allocate, but expects to be paired with free | |
93 | as the deallocation function. */ | |
94 | static void * | |
95 | fake_race_allocate_for_free (void *closure) | |
96 | { | |
97 | TEST_VERIFY (closure == &fake_race_region[0]); | |
98 | TEST_COMPARE (function_called, 0); | |
99 | ++function_called; | |
100 | /* Fake allocation by another thread. */ | |
101 | fake_race_place = &fake_race_region[1]; | |
102 | return xstrdup ("to be freed"); | |
103 | } | |
104 | ||
105 | static int | |
106 | do_test (void) | |
107 | { | |
108 | mtrace (); | |
109 | ||
110 | /* Simple allocation. */ | |
111 | void *place1 = NULL; | |
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 | |
118 | callbacks. */ | |
119 | TEST_VERIFY (string1 | |
120 | == allocate_once (&place1, allocate_not_called, | |
121 | deallocate_not_called, | |
122 | (char *) "test string 1a")); | |
123 | ||
124 | /* Different place should result in another call. */ | |
125 | void *place2 = NULL; | |
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); | |
132 | ||
133 | /* Check error reporting (NULL return value from the allocation | |
134 | function). */ | |
135 | void *place3 = NULL; | |
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); | |
140 | ||
141 | /* Check that the deallocation function is called if the race is | |
142 | lost. */ | |
143 | function_called = 0; | |
144 | TEST_VERIFY (allocate_once (&fake_race_place, | |
145 | fake_race_allocate, | |
146 | fake_race_deallocate, | |
147 | &fake_race_region[0]) | |
148 | == &fake_race_region[1]); | |
149 | TEST_COMPARE (function_called, 2); | |
150 | function_called = 3; | |
151 | TEST_VERIFY (allocate_once (&fake_race_place, | |
152 | fake_race_allocate, | |
153 | fake_race_deallocate, | |
154 | &fake_race_region[0]) | |
155 | == &fake_race_region[1]); | |
156 | TEST_COMPARE (function_called, 3); | |
157 | ||
158 | /* Similar, but this time rely on that free is called. */ | |
159 | function_called = 0; | |
160 | fake_race_place = NULL; | |
161 | TEST_VERIFY (allocate_once (&fake_race_place, | |
162 | fake_race_allocate_for_free, | |
163 | NULL, | |
164 | &fake_race_region[0]) | |
165 | == &fake_race_region[1]); | |
166 | TEST_COMPARE (function_called, 1); | |
167 | function_called = 3; | |
168 | TEST_VERIFY (allocate_once (&fake_race_place, | |
169 | fake_race_allocate_for_free, | |
170 | NULL, | |
171 | &fake_race_region[0]) | |
172 | == &fake_race_region[1]); | |
173 | TEST_COMPARE (function_called, 3); | |
174 | ||
175 | free (place2); | |
176 | free (place1); | |
177 | ||
178 | return 0; | |
179 | } | |
180 | ||
181 | #include <support/test-driver.c> |