]> git.proxmox.com Git - libgit2.git/blob - src/pool.c
Refresh patches
[libgit2.git] / src / pool.c
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
8 #include "pool.h"
9
10 #include "posix.h"
11 #ifndef GIT_WIN32
12 #include <unistd.h>
13 #endif
14
15 struct git_pool_page {
16 git_pool_page *next;
17 size_t size;
18 size_t avail;
19 GIT_ALIGN(char data[GIT_FLEX_ARRAY], 8);
20 };
21
22 static void *pool_alloc_page(git_pool *pool, size_t size);
23
24 #ifndef GIT_DEBUG_POOL
25
26 static size_t system_page_size = 0;
27
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;
35 }
36
37 int git_pool_init(git_pool *pool, size_t item_size)
38 {
39 GIT_ASSERT_ARG(pool);
40 GIT_ASSERT_ARG(item_size >= 1);
41
42 memset(pool, 0, sizeof(git_pool));
43 pool->item_size = item_size;
44 pool->page_size = system_page_size;
45
46 return 0;
47 }
48
49 void git_pool_clear(git_pool *pool)
50 {
51 git_pool_page *scan, *next;
52
53 for (scan = pool->pages; scan != NULL; scan = next) {
54 next = scan->next;
55 git__free(scan);
56 }
57
58 pool->pages = NULL;
59 }
60
61 static void *pool_alloc_page(git_pool *pool, size_t size)
62 {
63 git_pool_page *page;
64 const size_t new_page_size = (size <= pool->page_size) ? pool->page_size : size;
65 size_t alloc_size;
66
67 if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, new_page_size, sizeof(git_pool_page)) ||
68 !(page = git__malloc(alloc_size)))
69 return NULL;
70
71 page->size = new_page_size;
72 page->avail = new_page_size - size;
73 page->next = pool->pages;
74
75 pool->pages = page;
76
77 return page->data;
78 }
79
80 static void *pool_alloc(git_pool *pool, size_t size)
81 {
82 git_pool_page *page = pool->pages;
83 void *ptr = NULL;
84
85 if (!page || page->avail < size)
86 return pool_alloc_page(pool, size);
87
88 ptr = &page->data[page->size - page->avail];
89 page->avail -= size;
90
91 return ptr;
92 }
93
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
114 int git_pool_global_init(void)
115 {
116 return 0;
117 }
118
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
132 int git_pool_init(git_pool *pool, size_t item_size)
133 {
134 GIT_ASSERT_ARG(pool);
135 GIT_ASSERT_ARG(item_size >= 1);
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);
141
142 return 0;
143 }
144
145 void git_pool_clear(git_pool *pool)
146 {
147 git_vector_free_deep(&pool->allocations);
148 }
149
150 static void *pool_alloc(git_pool *pool, size_t size) {
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
178 static size_t alloc_size(git_pool *pool, size_t count)
179 {
180 const size_t align = sizeof(void *) - 1;
181
182 if (pool->item_size > 1) {
183 const size_t item_size = (pool->item_size + align) & ~align;
184 return item_size * count;
185 }
186
187 return (count + align) & ~align;
188 }
189
190 void *git_pool_malloc(git_pool *pool, size_t items)
191 {
192 return pool_alloc(pool, alloc_size(pool, items));
193 }
194
195 void *git_pool_mallocz(git_pool *pool, size_t items)
196 {
197 const size_t size = alloc_size(pool, items);
198 void *ptr = pool_alloc(pool, size);
199 if (ptr)
200 memset(ptr, 0x0, size);
201 return ptr;
202 }
203
204 char *git_pool_strndup(git_pool *pool, const char *str, size_t n)
205 {
206 char *ptr = NULL;
207
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);
211
212 if (n == SIZE_MAX)
213 return NULL;
214
215 if ((ptr = git_pool_malloc(pool, (n + 1))) != NULL) {
216 memcpy(ptr, str, n);
217 ptr[n] = '\0';
218 }
219
220 return ptr;
221 }
222
223 char *git_pool_strdup(git_pool *pool, const char *str)
224 {
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
229 return git_pool_strndup(pool, str, strlen(str));
230 }
231
232 char *git_pool_strdup_safe(git_pool *pool, const char *str)
233 {
234 return str ? git_pool_strdup(pool, str) : NULL;
235 }
236
237 char *git_pool_strcat(git_pool *pool, const char *a, const char *b)
238 {
239 void *ptr;
240 size_t len_a, len_b, total;
241
242 GIT_ASSERT_ARG_WITH_RETVAL(pool, NULL);
243 GIT_ASSERT_ARG_WITH_RETVAL(pool->item_size == sizeof(char), NULL);
244
245 len_a = a ? strlen(a) : 0;
246 len_b = b ? strlen(b) : 0;
247
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) {
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 }
259 return ptr;
260 }