]> git.proxmox.com Git - libgit2.git/blame - src/pool.c
New upstream version 1.4.3+dfsg.1
[libgit2.git] / src / pool.c
CommitLineData
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
15struct 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 22static void *pool_alloc_page(git_pool *pool, size_t size);
14bedad9 23
22a2d3d5 24#ifndef GIT_DEBUG_POOL
2bc8fa02 25
22a2d3d5 26static size_t system_page_size = 0;
2bc8fa02 27
22a2d3d5
UG
28int 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 37int 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
49void 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 61static 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 80static 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
94uint32_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
102bool 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
114int git_pool_global_init(void)
115{
116 return 0;
117}
118
ed0571f8
RD
119static 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 132int 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
145void git_pool_clear(git_pool *pool)
146{
147 git_vector_free_deep(&pool->allocations);
148}
149
22a2d3d5 150static 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
159bool 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
166void 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 178static 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 190void *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 195void *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
204char *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
223char *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
232char *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
237char *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}