17
17
#define DEBUG_RUN_CHECKS (pool ) ba_debug_checks(pool)
18
18
#define DEBUG_SET_VAR (var , value ) DO_WHILE_EXPRS((var = value))
19
19
#define DEBUG_INC_VAR (var ) DO_WHILE_EXPRS((var++))
20
+ #define DEBUG_DEC_VAR (var ) DO_WHILE_EXPRS((var--))
20
21
#else
21
22
#define DEBUG_RUN_CHECKS (pool ) DO_WHILE_EMPTY
22
23
#define DEBUG_SET_VAR (var , value ) DO_WHILE_EMPTY
23
24
#define DEBUG_INC_VAR (var ) DO_WHILE_EMPTY
25
+ #define DEBUG_DEC_VAR (var ) DO_WHILE_EMPTY
24
26
#endif /* NDEBUG */
25
27
26
28
// minimum size of a single pool of the linear base allocator
@@ -37,9 +39,11 @@ typedef struct umf_ba_main_linear_pool_meta_t {
37
39
os_mutex_t lock ;
38
40
char * data_ptr ;
39
41
size_t size_left ;
42
+ size_t pool_n_allocs ; // number of allocations in this pool
40
43
#ifndef NDEBUG
41
44
size_t n_pools ;
42
- #endif /* NDEBUG */
45
+ size_t global_n_allocs ; // global number of allocations in all pools
46
+ #endif /* NDEBUG */
43
47
} umf_ba_main_linear_pool_meta_t ;
44
48
45
49
// the main pool of the linear base allocator (there is only one such pool)
@@ -62,7 +66,8 @@ struct umf_ba_next_linear_pool_t {
62
66
// to be freed in umf_ba_linear_destroy())
63
67
umf_ba_next_linear_pool_t * next_pool ;
64
68
65
- size_t pool_size ; // size of this pool (argument of ba_os_alloc() call)
69
+ size_t pool_size ; // size of this pool (argument of ba_os_alloc() call)
70
+ size_t pool_n_allocs ; // number of allocations in this pool
66
71
67
72
// data area of all pools except of the main (the first one) starts here
68
73
char data [];
@@ -104,7 +109,9 @@ umf_ba_linear_pool_t *umf_ba_linear_create(size_t pool_size) {
104
109
pool -> metadata .data_ptr = data_ptr ;
105
110
pool -> metadata .size_left = size_left ;
106
111
pool -> next_pool = NULL ; // this is the only pool now
112
+ pool -> metadata .pool_n_allocs = 0 ;
107
113
DEBUG_SET_VAR (pool -> metadata .n_pools , 1 );
114
+ DEBUG_SET_VAR (pool -> metadata .global_n_allocs , 0 );
108
115
109
116
// init lock
110
117
os_mutex_t * lock = util_mutex_init (& pool -> metadata .lock );
@@ -139,6 +146,7 @@ void *umf_ba_linear_alloc(umf_ba_linear_pool_t *pool, size_t size) {
139
146
}
140
147
141
148
new_pool -> pool_size = pool_size ;
149
+ new_pool -> pool_n_allocs = 0 ;
142
150
143
151
void * data_ptr = & new_pool -> data ;
144
152
size_t size_left =
@@ -158,12 +166,79 @@ void *umf_ba_linear_alloc(umf_ba_linear_pool_t *pool, size_t size) {
158
166
void * ptr = pool -> metadata .data_ptr ;
159
167
pool -> metadata .data_ptr += aligned_size ;
160
168
pool -> metadata .size_left -= aligned_size ;
169
+ if (pool -> next_pool ) {
170
+ pool -> next_pool -> pool_n_allocs ++ ;
171
+ } else {
172
+ pool -> metadata .pool_n_allocs ++ ;
173
+ }
174
+ DEBUG_INC_VAR (pool -> metadata .global_n_allocs );
161
175
DEBUG_RUN_CHECKS (pool );
162
176
util_mutex_unlock (& pool -> metadata .lock );
163
177
164
178
return ptr ;
165
179
}
166
180
181
+ // check if ptr belongs to pool
182
+ static inline int pool_contains_ptr (void * pool , size_t pool_size ,
183
+ void * data_begin , void * ptr ) {
184
+ return ((char * )ptr >= (char * )data_begin &&
185
+ (char * )ptr < ((char * )(pool )) + pool_size );
186
+ }
187
+
188
+ // umf_ba_linear_free() really frees memory only if all allocations from an inactive pool were freed
189
+ // It returns:
190
+ // 0 - ptr belonged to the pool and was freed
191
+ // -1 - ptr doesn't belong to the pool and wasn't freed
192
+ int umf_ba_linear_free (umf_ba_linear_pool_t * pool , void * ptr ) {
193
+ util_mutex_lock (& pool -> metadata .lock );
194
+ DEBUG_RUN_CHECKS (pool );
195
+ if (pool_contains_ptr (pool , pool -> metadata .pool_size , pool -> data , ptr )) {
196
+ pool -> metadata .pool_n_allocs -- ;
197
+ DEBUG_DEC_VAR (pool -> metadata .global_n_allocs );
198
+ size_t page_size = ba_os_get_page_size ();
199
+ if ((pool -> metadata .pool_n_allocs == 0 ) && pool -> next_pool &&
200
+ (pool -> metadata .pool_size > page_size )) {
201
+ // we can free the first (main) pool except of the first page containing the metadata
202
+ void * ptr = pool + page_size ;
203
+ size_t size = pool -> metadata .pool_size - page_size ;
204
+ ba_os_free (ptr , size );
205
+ }
206
+ DEBUG_RUN_CHECKS (pool );
207
+ util_mutex_unlock (& pool -> metadata .lock );
208
+ return 0 ;
209
+ }
210
+
211
+ umf_ba_next_linear_pool_t * next_pool = pool -> next_pool ;
212
+ umf_ba_next_linear_pool_t * prev_pool = NULL ;
213
+ while (next_pool ) {
214
+ if (pool_contains_ptr (next_pool , next_pool -> pool_size , next_pool -> data ,
215
+ ptr )) {
216
+ DEBUG_DEC_VAR (pool -> metadata .global_n_allocs );
217
+ next_pool -> pool_n_allocs -- ;
218
+ // pool->next_pool is the active pool - we cannot free it
219
+ if ((next_pool -> pool_n_allocs == 0 ) &&
220
+ next_pool != pool -> next_pool ) {
221
+ assert (prev_pool ); // it cannot be the active pool
222
+ assert (prev_pool -> next_pool == next_pool );
223
+ prev_pool -> next_pool = next_pool -> next_pool ;
224
+ DEBUG_DEC_VAR (pool -> metadata .n_pools );
225
+ void * ptr = next_pool ;
226
+ size_t size = next_pool -> pool_size ;
227
+ ba_os_free (ptr , size );
228
+ }
229
+ DEBUG_RUN_CHECKS (pool );
230
+ util_mutex_unlock (& pool -> metadata .lock );
231
+ return 0 ;
232
+ }
233
+ prev_pool = next_pool ;
234
+ next_pool = next_pool -> next_pool ;
235
+ }
236
+
237
+ util_mutex_unlock (& pool -> metadata .lock );
238
+ // ptr doesn't belong to the pool and wasn't freed
239
+ return -1 ;
240
+ }
241
+
167
242
void umf_ba_linear_destroy (umf_ba_linear_pool_t * pool ) {
168
243
// Do not destroy if we are running in the proxy library,
169
244
// because it may need those resources till
@@ -172,7 +247,14 @@ void umf_ba_linear_destroy(umf_ba_linear_pool_t *pool) {
172
247
return ;
173
248
}
174
249
250
+ #ifndef NDEBUG
175
251
DEBUG_RUN_CHECKS (pool );
252
+ if (pool -> metadata .global_n_allocs ) {
253
+ fprintf (stderr , "umf_ba_linear_destroy(): global_n_allocs = %zu\n" ,
254
+ pool -> metadata .global_n_allocs );
255
+ assert (pool -> metadata .global_n_allocs == 0 );
256
+ }
257
+ #endif /* NDEBUG */
176
258
177
259
umf_ba_next_linear_pool_t * current_pool ;
178
260
umf_ba_next_linear_pool_t * next_pool = pool -> next_pool ;
0 commit comments