]>
Commit | Line | Data |
---|---|---|
eae0bfdc PP |
1 | /* |
2 | * Copyright (C) the libgit2 contributors. All rights reserved. | |
3 | * | |
4 | * This file is part of libgit2, distributed under the GNU GPL v2 with | |
5 | * a Linking Exception. For full terms see the included COPYING file. | |
6 | */ | |
7 | ||
2bc8fa02 | 8 | #include "pool.h" |
eae0bfdc | 9 | |
62e562f9 | 10 | #include "posix.h" |
2bc8fa02 RB |
11 | #ifndef GIT_WIN32 |
12 | #include <unistd.h> | |
13 | #endif | |
14 | ||
15 | struct git_pool_page { | |
16 | git_pool_page *next; | |
22a2d3d5 UG |
17 | size_t size; |
18 | size_t avail; | |
7ff7ca62 | 19 | GIT_ALIGN(char data[GIT_FLEX_ARRAY], 8); |
2bc8fa02 RB |
20 | }; |
21 | ||
22a2d3d5 | 22 | static void *pool_alloc_page(git_pool *pool, size_t size); |
14bedad9 | 23 | |
22a2d3d5 | 24 | #ifndef GIT_DEBUG_POOL |
2bc8fa02 | 25 | |
22a2d3d5 | 26 | static size_t system_page_size = 0; |
2bc8fa02 | 27 | |
22a2d3d5 UG |
28 | int git_pool_global_init(void) |
29 | { | |
30 | if (git__page_size(&system_page_size) < 0) | |
31 | system_page_size = 4096; | |
32 | /* allow space for malloc overhead */ | |
33 | system_page_size -= (2 * sizeof(void *)) + sizeof(git_pool_page); | |
34 | return 0; | |
1e5e02b4 VM |
35 | } |
36 | ||
22a2d3d5 | 37 | int git_pool_init(git_pool *pool, size_t item_size) |
2bc8fa02 | 38 | { |
c25aa7cd PP |
39 | GIT_ASSERT_ARG(pool); |
40 | GIT_ASSERT_ARG(item_size >= 1); | |
2bc8fa02 RB |
41 | |
42 | memset(pool, 0, sizeof(git_pool)); | |
43 | pool->item_size = item_size; | |
22a2d3d5 UG |
44 | pool->page_size = system_page_size; |
45 | ||
46 | return 0; | |
2bc8fa02 RB |
47 | } |
48 | ||
49 | void git_pool_clear(git_pool *pool) | |
50 | { | |
51 | git_pool_page *scan, *next; | |
52 | ||
1e5e02b4 | 53 | for (scan = pool->pages; scan != NULL; scan = next) { |
2bc8fa02 RB |
54 | next = scan->next; |
55 | git__free(scan); | |
56 | } | |
2bc8fa02 | 57 | |
1e5e02b4 | 58 | pool->pages = NULL; |
2bc8fa02 RB |
59 | } |
60 | ||
22a2d3d5 | 61 | static void *pool_alloc_page(git_pool *pool, size_t size) |
2bc8fa02 RB |
62 | { |
63 | git_pool_page *page; | |
22a2d3d5 | 64 | const size_t new_page_size = (size <= pool->page_size) ? pool->page_size : size; |
f1453c59 | 65 | size_t alloc_size; |
2bc8fa02 | 66 | |
f1453c59 | 67 | if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, new_page_size, sizeof(git_pool_page)) || |
d3416dfe | 68 | !(page = git__malloc(alloc_size))) |
19fa2bc1 | 69 | return NULL; |
2bc8fa02 | 70 | |
1e5e02b4 | 71 | page->size = new_page_size; |
f1453c59 | 72 | page->avail = new_page_size - size; |
1e5e02b4 | 73 | page->next = pool->pages; |
2bc8fa02 | 74 | |
1e5e02b4 | 75 | pool->pages = page; |
2bc8fa02 | 76 | |
19fa2bc1 | 77 | return page->data; |
2bc8fa02 RB |
78 | } |
79 | ||
22a2d3d5 | 80 | static void *pool_alloc(git_pool *pool, size_t size) |
2bc8fa02 | 81 | { |
1e5e02b4 VM |
82 | git_pool_page *page = pool->pages; |
83 | void *ptr = NULL; | |
2bc8fa02 | 84 | |
1e5e02b4 | 85 | if (!page || page->avail < size) |
19fa2bc1 RB |
86 | return pool_alloc_page(pool, size); |
87 | ||
1e5e02b4 VM |
88 | ptr = &page->data[page->size - page->avail]; |
89 | page->avail -= size; | |
2bc8fa02 | 90 | |
19fa2bc1 | 91 | return ptr; |
2bc8fa02 RB |
92 | } |
93 | ||
ed0571f8 RD |
94 | uint32_t git_pool__open_pages(git_pool *pool) |
95 | { | |
96 | uint32_t ct = 0; | |
97 | git_pool_page *scan; | |
98 | for (scan = pool->pages; scan != NULL; scan = scan->next) ct++; | |
99 | return ct; | |
100 | } | |
101 | ||
102 | bool git_pool__ptr_in_pool(git_pool *pool, void *ptr) | |
103 | { | |
104 | git_pool_page *scan; | |
105 | for (scan = pool->pages; scan != NULL; scan = scan->next) | |
106 | if ((void *)scan->data <= ptr && | |
107 | (void *)(((char *)scan->data) + scan->size) > ptr) | |
108 | return true; | |
109 | return false; | |
110 | } | |
111 | ||
112 | #else | |
113 | ||
22a2d3d5 UG |
114 | int git_pool_global_init(void) |
115 | { | |
116 | return 0; | |
117 | } | |
118 | ||
ed0571f8 RD |
119 | static int git_pool__ptr_cmp(const void * a, const void * b) |
120 | { | |
121 | if(a > b) { | |
122 | return 1; | |
123 | } | |
124 | if(a < b) { | |
125 | return -1; | |
126 | } | |
127 | else { | |
128 | return 0; | |
129 | } | |
130 | } | |
131 | ||
22a2d3d5 | 132 | int git_pool_init(git_pool *pool, size_t item_size) |
ed0571f8 | 133 | { |
c25aa7cd PP |
134 | GIT_ASSERT_ARG(pool); |
135 | GIT_ASSERT_ARG(item_size >= 1); | |
ed0571f8 RD |
136 | |
137 | memset(pool, 0, sizeof(git_pool)); | |
138 | pool->item_size = item_size; | |
139 | pool->page_size = git_pool__system_page_size(); | |
140 | git_vector_init(&pool->allocations, 100, git_pool__ptr_cmp); | |
22a2d3d5 UG |
141 | |
142 | return 0; | |
ed0571f8 RD |
143 | } |
144 | ||
145 | void git_pool_clear(git_pool *pool) | |
146 | { | |
147 | git_vector_free_deep(&pool->allocations); | |
148 | } | |
149 | ||
22a2d3d5 | 150 | static void *pool_alloc(git_pool *pool, size_t size) { |
ed0571f8 RD |
151 | void *ptr = NULL; |
152 | if((ptr = git__malloc(size)) == NULL) { | |
153 | return NULL; | |
154 | } | |
155 | git_vector_insert_sorted(&pool->allocations, ptr, NULL); | |
156 | return ptr; | |
157 | } | |
158 | ||
159 | bool git_pool__ptr_in_pool(git_pool *pool, void *ptr) | |
160 | { | |
161 | size_t pos; | |
162 | return git_vector_bsearch(&pos, &pool->allocations, ptr) != GIT_ENOTFOUND; | |
163 | } | |
164 | #endif | |
165 | ||
166 | void git_pool_swap(git_pool *a, git_pool *b) | |
167 | { | |
168 | git_pool temp; | |
169 | ||
170 | if (a == b) | |
171 | return; | |
172 | ||
173 | memcpy(&temp, a, sizeof(temp)); | |
174 | memcpy(a, b, sizeof(temp)); | |
175 | memcpy(b, &temp, sizeof(temp)); | |
176 | } | |
177 | ||
22a2d3d5 | 178 | static size_t alloc_size(git_pool *pool, size_t count) |
7ff7ca62 | 179 | { |
22a2d3d5 | 180 | const size_t align = sizeof(void *) - 1; |
7ff7ca62 VM |
181 | |
182 | if (pool->item_size > 1) { | |
22a2d3d5 | 183 | const size_t item_size = (pool->item_size + align) & ~align; |
7ff7ca62 VM |
184 | return item_size * count; |
185 | } | |
186 | ||
187 | return (count + align) & ~align; | |
188 | } | |
189 | ||
22a2d3d5 | 190 | void *git_pool_malloc(git_pool *pool, size_t items) |
d3416dfe | 191 | { |
7ff7ca62 | 192 | return pool_alloc(pool, alloc_size(pool, items)); |
d3416dfe VM |
193 | } |
194 | ||
22a2d3d5 | 195 | void *git_pool_mallocz(git_pool *pool, size_t items) |
d3416dfe | 196 | { |
22a2d3d5 | 197 | const size_t size = alloc_size(pool, items); |
d3416dfe VM |
198 | void *ptr = pool_alloc(pool, size); |
199 | if (ptr) | |
200 | memset(ptr, 0x0, size); | |
201 | return ptr; | |
202 | } | |
203 | ||
2bc8fa02 RB |
204 | char *git_pool_strndup(git_pool *pool, const char *str, size_t n) |
205 | { | |
ce33645f | 206 | char *ptr = NULL; |
2bc8fa02 | 207 | |
c25aa7cd PP |
208 | GIT_ASSERT_ARG_WITH_RETVAL(pool, NULL); |
209 | GIT_ASSERT_ARG_WITH_RETVAL(str, NULL); | |
210 | GIT_ASSERT_ARG_WITH_RETVAL(pool->item_size == sizeof(char), NULL); | |
2bc8fa02 | 211 | |
22a2d3d5 | 212 | if (n == SIZE_MAX) |
437f7d69 VM |
213 | return NULL; |
214 | ||
22a2d3d5 | 215 | if ((ptr = git_pool_malloc(pool, (n + 1))) != NULL) { |
2bc8fa02 | 216 | memcpy(ptr, str, n); |
ce33645f | 217 | ptr[n] = '\0'; |
19fa2bc1 | 218 | } |
ce33645f | 219 | |
2bc8fa02 RB |
220 | return ptr; |
221 | } | |
222 | ||
223 | char *git_pool_strdup(git_pool *pool, const char *str) | |
224 | { | |
c25aa7cd PP |
225 | GIT_ASSERT_ARG_WITH_RETVAL(pool, NULL); |
226 | GIT_ASSERT_ARG_WITH_RETVAL(str, NULL); | |
227 | GIT_ASSERT_ARG_WITH_RETVAL(pool->item_size == sizeof(char), NULL); | |
228 | ||
19fa2bc1 RB |
229 | return git_pool_strndup(pool, str, strlen(str)); |
230 | } | |
231 | ||
71d27358 RB |
232 | char *git_pool_strdup_safe(git_pool *pool, const char *str) |
233 | { | |
ce33645f | 234 | return str ? git_pool_strdup(pool, str) : NULL; |
71d27358 RB |
235 | } |
236 | ||
19fa2bc1 RB |
237 | char *git_pool_strcat(git_pool *pool, const char *a, const char *b) |
238 | { | |
239 | void *ptr; | |
22a2d3d5 | 240 | size_t len_a, len_b, total; |
19fa2bc1 | 241 | |
c25aa7cd PP |
242 | GIT_ASSERT_ARG_WITH_RETVAL(pool, NULL); |
243 | GIT_ASSERT_ARG_WITH_RETVAL(pool->item_size == sizeof(char), NULL); | |
19fa2bc1 RB |
244 | |
245 | len_a = a ? strlen(a) : 0; | |
246 | len_b = b ? strlen(b) : 0; | |
247 | ||
22a2d3d5 UG |
248 | if (GIT_ADD_SIZET_OVERFLOW(&total, len_a, len_b) || |
249 | GIT_ADD_SIZET_OVERFLOW(&total, total, 1)) | |
250 | return NULL; | |
251 | ||
252 | if ((ptr = git_pool_malloc(pool, total)) != NULL) { | |
19fa2bc1 RB |
253 | if (len_a) |
254 | memcpy(ptr, a, len_a); | |
255 | if (len_b) | |
256 | memcpy(((char *)ptr) + len_a, b, len_b); | |
257 | *(((char *)ptr) + len_a + len_b) = '\0'; | |
258 | } | |
19fa2bc1 | 259 | return ptr; |
2bc8fa02 | 260 | } |