Skip to content

Commit 2d4075a

Browse files
authored
Merge pull request #206 from ldorau/Do_not_fail_linear_allocator_with_OOM_in_Release_build
Do not fail linear allocator with OOM
2 parents eacd4d1 + f1c84f8 commit 2d4075a

File tree

1 file changed

+83
-16
lines changed

1 file changed

+83
-16
lines changed

src/base_alloc/base_alloc_linear.c

Lines changed: 83 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,59 @@
1919
// alignment of the linear base allocator
2020
#define MEMORY_ALIGNMENT (sizeof(uintptr_t))
2121

22-
// metadata of the linear base allocator
23-
typedef struct {
24-
size_t pool_size;
22+
typedef struct umf_ba_next_linear_pool_t umf_ba_next_linear_pool_t;
23+
24+
// metadata is set and used only in the main (the first) pool
25+
typedef struct umf_ba_main_linear_pool_meta_t {
26+
size_t pool_size; // size of each pool (argument of each ba_os_alloc() call)
2527
os_mutex_t lock;
2628
char *data_ptr;
2729
size_t size_left;
30+
#ifndef NDEBUG
31+
size_t n_pools;
32+
#endif /* NDEBUG */
2833
} umf_ba_main_linear_pool_meta_t;
2934

30-
// pool of the linear base allocator
35+
// the main pool of the linear base allocator (there is only one such pool)
3136
struct umf_ba_linear_pool {
37+
// address of the beginning of the next pool (a list of allocated pools
38+
// to be freed in umf_ba_linear_destroy())
39+
umf_ba_next_linear_pool_t *next_pool;
40+
41+
// metadata is set and used only in the main (the first) pool
3242
umf_ba_main_linear_pool_meta_t metadata;
33-
char data[]; // data area starts here
43+
44+
// data area of the main pool (the first one) starts here
45+
char data[];
46+
};
47+
48+
// the "next" pools of the linear base allocator (pools allocated later,
49+
// when we run out of the memory of the main pool)
50+
struct umf_ba_next_linear_pool_t {
51+
// address of the beginning of the next pool (a list of allocated pools
52+
// to be freed in umf_ba_linear_destroy())
53+
umf_ba_next_linear_pool_t *next_pool;
54+
55+
// data area of all pools except of the main (the first one) starts here
56+
char data[];
3457
};
3558

59+
#ifndef NDEBUG
60+
static void ba_debug_checks(umf_ba_linear_pool_t *pool) {
61+
// count pools
62+
size_t n_pools = 1;
63+
umf_ba_next_linear_pool_t *next_pool = pool->next_pool;
64+
while (next_pool) {
65+
n_pools++;
66+
next_pool = next_pool->next_pool;
67+
}
68+
assert(n_pools == pool->metadata.n_pools);
69+
}
70+
#endif /* NDEBUG */
71+
3672
umf_ba_linear_pool_t *umf_ba_linear_create(size_t pool_size) {
37-
size_t mutex_size = align_size(util_mutex_get_size(), MEMORY_ALIGNMENT);
3873
size_t metadata_size = sizeof(umf_ba_main_linear_pool_meta_t);
39-
pool_size = pool_size + metadata_size + mutex_size;
74+
pool_size = pool_size + metadata_size;
4075
if (pool_size < MINIMUM_LINEAR_POOL_SIZE) {
4176
pool_size = MINIMUM_LINEAR_POOL_SIZE;
4277
}
@@ -56,6 +91,10 @@ umf_ba_linear_pool_t *umf_ba_linear_create(size_t pool_size) {
5691
pool->metadata.pool_size = pool_size;
5792
pool->metadata.data_ptr = data_ptr;
5893
pool->metadata.size_left = size_left;
94+
pool->next_pool = NULL; // this is the only pool now
95+
#ifndef NDEBUG
96+
pool->metadata.n_pools = 1;
97+
#endif /* NDEBUG */
5998

6099
// init lock
61100
os_mutex_t *lock = util_mutex_init(&pool->metadata.lock);
@@ -69,27 +108,55 @@ umf_ba_linear_pool_t *umf_ba_linear_create(size_t pool_size) {
69108

70109
void *umf_ba_linear_alloc(umf_ba_linear_pool_t *pool, size_t size) {
71110
size_t aligned_size = align_size(size, MEMORY_ALIGNMENT);
72-
73111
util_mutex_lock(&pool->metadata.lock);
74112
if (pool->metadata.size_left < aligned_size) {
75-
fprintf(stderr,
76-
"error: umf_ba_linear_alloc() failed (requested size: %zu > "
77-
"space left: %zu)\n",
78-
aligned_size, pool->metadata.size_left);
79-
util_mutex_unlock(&pool->metadata.lock);
80-
assert(pool->metadata.size_left >= aligned_size);
81-
return NULL; // out of memory
113+
umf_ba_next_linear_pool_t *new_pool =
114+
(umf_ba_next_linear_pool_t *)ba_os_alloc(pool->metadata.pool_size);
115+
if (!new_pool) {
116+
util_mutex_unlock(&pool->metadata.lock);
117+
return NULL;
118+
}
119+
120+
void *data_ptr = &new_pool->data;
121+
size_t size_left = pool->metadata.pool_size -
122+
offsetof(umf_ba_next_linear_pool_t, data);
123+
align_ptr_size(&data_ptr, &size_left, MEMORY_ALIGNMENT);
124+
125+
pool->metadata.data_ptr = data_ptr;
126+
pool->metadata.size_left = size_left;
127+
128+
// add the new pool to the list of pools
129+
new_pool->next_pool = pool->next_pool;
130+
pool->next_pool = new_pool;
131+
#ifndef NDEBUG
132+
pool->metadata.n_pools++;
133+
#endif /* NDEBUG */
82134
}
83135

84136
void *ptr = pool->metadata.data_ptr;
85137
pool->metadata.data_ptr += aligned_size;
86138
pool->metadata.size_left -= aligned_size;
139+
#ifndef NDEBUG
140+
ba_debug_checks(pool);
141+
#endif /* NDEBUG */
87142
util_mutex_unlock(&pool->metadata.lock);
88143

89144
return ptr;
90145
}
91146

92147
void umf_ba_linear_destroy(umf_ba_linear_pool_t *pool) {
148+
#ifndef NDEBUG
149+
ba_debug_checks(pool);
150+
#endif /* NDEBUG */
151+
size_t size = pool->metadata.pool_size;
152+
umf_ba_next_linear_pool_t *current_pool;
153+
umf_ba_next_linear_pool_t *next_pool = pool->next_pool;
154+
while (next_pool) {
155+
current_pool = next_pool;
156+
next_pool = next_pool->next_pool;
157+
ba_os_free(current_pool, size);
158+
}
159+
93160
util_mutex_destroy_not_free(&pool->metadata.lock);
94-
ba_os_free(pool, pool->metadata.pool_size);
161+
ba_os_free(pool, size);
95162
}

0 commit comments

Comments
 (0)