|
Packit Service |
20376f |
#include "pool.h"
|
|
Packit Service |
20376f |
#include "posix.h"
|
|
Packit Service |
20376f |
#ifndef GIT_WIN32
|
|
Packit Service |
20376f |
#include <unistd.h>
|
|
Packit Service |
20376f |
#endif
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
struct git_pool_page {
|
|
Packit Service |
20376f |
git_pool_page *next;
|
|
Packit Service |
20376f |
uint32_t size;
|
|
Packit Service |
20376f |
uint32_t avail;
|
|
Packit Service |
20376f |
GIT_ALIGN(char data[GIT_FLEX_ARRAY], 8);
|
|
Packit Service |
20376f |
};
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static void *pool_alloc_page(git_pool *pool, uint32_t size);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
uint32_t git_pool__system_page_size(void)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
static uint32_t size = 0;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (!size) {
|
|
Packit Service |
20376f |
size_t page_size;
|
|
Packit Service |
20376f |
if (git__page_size(&page_size) < 0)
|
|
Packit Service |
20376f |
page_size = 4096;
|
|
Packit Service |
20376f |
/* allow space for malloc overhead */
|
|
Packit Service |
20376f |
size = page_size - (2 * sizeof(void *)) - sizeof(git_pool_page);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return size;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
#ifndef GIT_DEBUG_POOL
|
|
Packit Service |
20376f |
void git_pool_init(git_pool *pool, uint32_t item_size)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
assert(pool);
|
|
Packit Service |
20376f |
assert(item_size >= 1);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
memset(pool, 0, sizeof(git_pool));
|
|
Packit Service |
20376f |
pool->item_size = item_size;
|
|
Packit Service |
20376f |
pool->page_size = git_pool__system_page_size();
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
void git_pool_clear(git_pool *pool)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
git_pool_page *scan, *next;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
for (scan = pool->pages; scan != NULL; scan = next) {
|
|
Packit Service |
20376f |
next = scan->next;
|
|
Packit Service |
20376f |
git__free(scan);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
pool->pages = NULL;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static void *pool_alloc_page(git_pool *pool, uint32_t size)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
git_pool_page *page;
|
|
Packit Service |
20376f |
const uint32_t new_page_size = (size <= pool->page_size) ? pool->page_size : size;
|
|
Packit Service |
20376f |
size_t alloc_size;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, new_page_size, sizeof(git_pool_page)) ||
|
|
Packit Service |
20376f |
!(page = git__malloc(alloc_size)))
|
|
Packit Service |
20376f |
return NULL;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
page->size = new_page_size;
|
|
Packit Service |
20376f |
page->avail = new_page_size - size;
|
|
Packit Service |
20376f |
page->next = pool->pages;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
pool->pages = page;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return page->data;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static void *pool_alloc(git_pool *pool, uint32_t size)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
git_pool_page *page = pool->pages;
|
|
Packit Service |
20376f |
void *ptr = NULL;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (!page || page->avail < size)
|
|
Packit Service |
20376f |
return pool_alloc_page(pool, size);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
ptr = &page->data[page->size - page->avail];
|
|
Packit Service |
20376f |
page->avail -= size;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return ptr;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
uint32_t git_pool__open_pages(git_pool *pool)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
uint32_t ct = 0;
|
|
Packit Service |
20376f |
git_pool_page *scan;
|
|
Packit Service |
20376f |
for (scan = pool->pages; scan != NULL; scan = scan->next) ct++;
|
|
Packit Service |
20376f |
return ct;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
bool git_pool__ptr_in_pool(git_pool *pool, void *ptr)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
git_pool_page *scan;
|
|
Packit Service |
20376f |
for (scan = pool->pages; scan != NULL; scan = scan->next)
|
|
Packit Service |
20376f |
if ((void *)scan->data <= ptr &&
|
|
Packit Service |
20376f |
(void *)(((char *)scan->data) + scan->size) > ptr)
|
|
Packit Service |
20376f |
return true;
|
|
Packit Service |
20376f |
return false;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
#else
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int git_pool__ptr_cmp(const void * a, const void * b)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
if(a > b) {
|
|
Packit Service |
20376f |
return 1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
if(a < b) {
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
else {
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
void git_pool_init(git_pool *pool, uint32_t item_size)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
assert(pool);
|
|
Packit Service |
20376f |
assert(item_size >= 1);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
memset(pool, 0, sizeof(git_pool));
|
|
Packit Service |
20376f |
pool->item_size = item_size;
|
|
Packit Service |
20376f |
pool->page_size = git_pool__system_page_size();
|
|
Packit Service |
20376f |
git_vector_init(&pool->allocations, 100, git_pool__ptr_cmp);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
void git_pool_clear(git_pool *pool)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
git_vector_free_deep(&pool->allocations);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static void *pool_alloc(git_pool *pool, uint32_t size) {
|
|
Packit Service |
20376f |
void *ptr = NULL;
|
|
Packit Service |
20376f |
if((ptr = git__malloc(size)) == NULL) {
|
|
Packit Service |
20376f |
return NULL;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
git_vector_insert_sorted(&pool->allocations, ptr, NULL);
|
|
Packit Service |
20376f |
return ptr;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
bool git_pool__ptr_in_pool(git_pool *pool, void *ptr)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
size_t pos;
|
|
Packit Service |
20376f |
return git_vector_bsearch(&pos, &pool->allocations, ptr) != GIT_ENOTFOUND;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
#endif
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
void git_pool_swap(git_pool *a, git_pool *b)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
git_pool temp;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (a == b)
|
|
Packit Service |
20376f |
return;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
memcpy(&temp, a, sizeof(temp));
|
|
Packit Service |
20376f |
memcpy(a, b, sizeof(temp));
|
|
Packit Service |
20376f |
memcpy(b, &temp, sizeof(temp));
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static uint32_t alloc_size(git_pool *pool, uint32_t count)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
const uint32_t align = sizeof(void *) - 1;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (pool->item_size > 1) {
|
|
Packit Service |
20376f |
const uint32_t item_size = (pool->item_size + align) & ~align;
|
|
Packit Service |
20376f |
return item_size * count;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return (count + align) & ~align;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
void *git_pool_malloc(git_pool *pool, uint32_t items)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
return pool_alloc(pool, alloc_size(pool, items));
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
void *git_pool_mallocz(git_pool *pool, uint32_t items)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
const uint32_t size = alloc_size(pool, items);
|
|
Packit Service |
20376f |
void *ptr = pool_alloc(pool, size);
|
|
Packit Service |
20376f |
if (ptr)
|
|
Packit Service |
20376f |
memset(ptr, 0x0, size);
|
|
Packit Service |
20376f |
return ptr;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
char *git_pool_strndup(git_pool *pool, const char *str, size_t n)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
char *ptr = NULL;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
assert(pool && str && pool->item_size == sizeof(char));
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((uint32_t)(n + 1) < n)
|
|
Packit Service |
20376f |
return NULL;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((ptr = git_pool_malloc(pool, (uint32_t)(n + 1))) != NULL) {
|
|
Packit Service |
20376f |
memcpy(ptr, str, n);
|
|
Packit Service |
20376f |
ptr[n] = '\0';
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return ptr;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
char *git_pool_strdup(git_pool *pool, const char *str)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
assert(pool && str && pool->item_size == sizeof(char));
|
|
Packit Service |
20376f |
return git_pool_strndup(pool, str, strlen(str));
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
char *git_pool_strdup_safe(git_pool *pool, const char *str)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
return str ? git_pool_strdup(pool, str) : NULL;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
char *git_pool_strcat(git_pool *pool, const char *a, const char *b)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
void *ptr;
|
|
Packit Service |
20376f |
size_t len_a, len_b;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
assert(pool && pool->item_size == sizeof(char));
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
len_a = a ? strlen(a) : 0;
|
|
Packit Service |
20376f |
len_b = b ? strlen(b) : 0;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((ptr = git_pool_malloc(pool, (uint32_t)(len_a + len_b + 1))) != NULL) {
|
|
Packit Service |
20376f |
if (len_a)
|
|
Packit Service |
20376f |
memcpy(ptr, a, len_a);
|
|
Packit Service |
20376f |
if (len_b)
|
|
Packit Service |
20376f |
memcpy(((char *)ptr) + len_a, b, len_b);
|
|
Packit Service |
20376f |
*(((char *)ptr) + len_a + len_b) = '\0';
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
return ptr;
|
|
Packit Service |
20376f |
}
|