]>
git.proxmox.com Git - libgit2.git/blob - src/pool.c
10 char data
[GIT_FLEX_ARRAY
];
13 struct pool_freelist
{
14 struct pool_freelist
*next
;
17 #define GIT_POOL_MIN_USABLE 4
18 #define GIT_POOL_MIN_PAGESZ 2 * sizeof(void*)
20 static void *pool_alloc_page(git_pool
*pool
, uint32_t size
);
21 static void pool_insert_page(git_pool
*pool
, git_pool_page
*page
);
24 git_pool
*pool
, uint32_t item_size
, uint32_t items_per_page
)
30 /* round up item_size for decent object alignment */
32 item_size
= (item_size
+ 7) & ~7;
33 else if (item_size
== 3)
37 items_per_page
= git_pool__suggest_items_per_page(item_size
);
38 if (item_size
* items_per_page
< GIT_POOL_MIN_PAGESZ
)
39 items_per_page
= (GIT_POOL_MIN_PAGESZ
+ item_size
- 1) / item_size
;
41 memset(pool
, 0, sizeof(git_pool
));
42 pool
->item_size
= item_size
;
43 pool
->page_size
= item_size
* items_per_page
;
48 void git_pool_clear(git_pool
*pool
)
50 git_pool_page
*scan
, *next
;
52 for (scan
= pool
->open
; scan
!= NULL
; scan
= next
) {
58 for (scan
= pool
->full
; scan
!= NULL
; scan
= next
) {
64 pool
->free_list
= NULL
;
68 pool
->has_string_alloc
= 0;
69 pool
->has_multi_item_alloc
= 0;
70 pool
->has_large_page_alloc
= 0;
73 void git_pool_swap(git_pool
*a
, git_pool
*b
)
80 memcpy(&temp
, a
, sizeof(temp
));
81 memcpy(a
, b
, sizeof(temp
));
82 memcpy(b
, &temp
, sizeof(temp
));
85 static void pool_insert_page(git_pool
*pool
, git_pool_page
*page
)
89 /* If there are no open pages or this page has the most open space,
90 * insert it at the beginning of the list. This is the common case.
92 if (pool
->open
== NULL
|| pool
->open
->avail
< page
->avail
) {
93 page
->next
= pool
->open
;
98 /* Otherwise insert into sorted position. */
99 for (scan
= pool
->open
;
100 scan
->next
&& scan
->next
->avail
> page
->avail
;
102 page
->next
= scan
->next
;
106 static void *pool_alloc_page(git_pool
*pool
, uint32_t size
)
111 if (size
<= pool
->page_size
)
112 alloc_size
= pool
->page_size
;
115 pool
->has_large_page_alloc
= 1;
118 page
= git__calloc(1, alloc_size
+ sizeof(git_pool_page
));
122 page
->size
= alloc_size
;
123 page
->avail
= alloc_size
- size
;
126 pool_insert_page(pool
, page
);
128 page
->next
= pool
->full
;
137 GIT_INLINE(void) pool_remove_page(
138 git_pool
*pool
, git_pool_page
*page
, git_pool_page
*prev
)
141 pool
->open
= page
->next
;
143 prev
->next
= page
->next
;
146 void *git_pool_malloc(git_pool
*pool
, uint32_t items
)
148 git_pool_page
*scan
= pool
->open
, *prev
;
149 uint32_t size
= items
* pool
->item_size
;
152 pool
->has_string_alloc
= 0;
154 pool
->has_multi_item_alloc
= 1;
155 else if (pool
->free_list
!= NULL
) {
156 ptr
= pool
->free_list
;
157 pool
->free_list
= ((struct pool_freelist
*)pool
->free_list
)->next
;
161 /* just add a block if there is no open one to accomodate this */
162 if (size
>= pool
->page_size
|| !scan
|| scan
->avail
< size
)
163 return pool_alloc_page(pool
, size
);
167 /* find smallest block in free list with space */
168 for (scan
= pool
->open
, prev
= NULL
;
169 scan
->next
&& scan
->next
->avail
>= size
;
170 prev
= scan
, scan
= scan
->next
);
172 /* allocate space from the block */
173 ptr
= &scan
->data
[scan
->size
- scan
->avail
];
176 /* move to full list if there is almost no space left */
177 if (scan
->avail
< pool
->item_size
|| scan
->avail
< GIT_POOL_MIN_USABLE
) {
178 pool_remove_page(pool
, scan
, prev
);
179 scan
->next
= pool
->full
;
182 /* reorder list if block is now smaller than the one after it */
183 else if (scan
->next
!= NULL
&& scan
->next
->avail
> scan
->avail
) {
184 pool_remove_page(pool
, scan
, prev
);
185 pool_insert_page(pool
, scan
);
191 char *git_pool_strndup(git_pool
*pool
, const char *str
, size_t n
)
195 assert(pool
&& str
&& pool
->item_size
== sizeof(char));
202 if ((ptr
= git_pool_malloc(pool
, (uint32_t)(n
+ 1))) != NULL
) {
204 *(((char *)ptr
) + n
) = '\0';
206 pool
->has_string_alloc
= 1;
211 char *git_pool_strdup(git_pool
*pool
, const char *str
)
213 assert(pool
&& str
&& pool
->item_size
== sizeof(char));
215 return git_pool_strndup(pool
, str
, strlen(str
));
218 char *git_pool_strdup_safe(git_pool
*pool
, const char *str
)
220 return str
? git_pool_strdup(pool
, str
) : NULL
;
223 char *git_pool_strcat(git_pool
*pool
, const char *a
, const char *b
)
228 assert(pool
&& a
&& b
&& pool
->item_size
== sizeof(char));
230 len_a
= a
? strlen(a
) : 0;
231 len_b
= b
? strlen(b
) : 0;
233 if ((ptr
= git_pool_malloc(pool
, (uint32_t)(len_a
+ len_b
+ 1))) != NULL
) {
235 memcpy(ptr
, a
, len_a
);
237 memcpy(((char *)ptr
) + len_a
, b
, len_b
);
238 *(((char *)ptr
) + len_a
+ len_b
) = '\0';
240 pool
->has_string_alloc
= 1;
245 void git_pool_free(git_pool
*pool
, void *ptr
)
247 struct pool_freelist
*item
= ptr
;
249 assert(pool
&& pool
->item_size
>= sizeof(void*));
252 item
->next
= pool
->free_list
;
253 pool
->free_list
= item
;
257 void git_pool_free_array(git_pool
*pool
, size_t count
, void **ptrs
)
259 struct pool_freelist
**items
= (struct pool_freelist
**)ptrs
;
262 assert(pool
&& ptrs
&& pool
->item_size
>= sizeof(void*));
267 for (i
= count
- 1; i
> 0; --i
)
268 items
[i
]->next
= items
[i
- 1];
270 items
[i
]->next
= pool
->free_list
;
271 pool
->free_list
= items
[count
- 1];
274 uint32_t git_pool__open_pages(git_pool
*pool
)
278 for (scan
= pool
->open
; scan
!= NULL
; scan
= scan
->next
) ct
++;
282 uint32_t git_pool__full_pages(git_pool
*pool
)
286 for (scan
= pool
->full
; scan
!= NULL
; scan
= scan
->next
) ct
++;
290 bool git_pool__ptr_in_pool(git_pool
*pool
, void *ptr
)
293 for (scan
= pool
->open
; scan
!= NULL
; scan
= scan
->next
)
294 if ((void *)scan
->data
<= ptr
&&
295 (void *)(((char *)scan
->data
) + scan
->size
) > ptr
)
297 for (scan
= pool
->full
; scan
!= NULL
; scan
= scan
->next
)
298 if ((void *)scan
->data
<= ptr
&&
299 (void *)(((char *)scan
->data
) + scan
->size
) > ptr
)
304 uint32_t git_pool__system_page_size(void)
306 static uint32_t size
= 0;
311 GetSystemInfo(&info
);
312 size
= (uint32_t)info
.dwPageSize
;
313 #elif defined(__amigaos4__)
314 size
= (uint32_t)4096; /* 4K as there is no global value we can query */
316 size
= (uint32_t)sysconf(_SC_PAGE_SIZE
);
319 size
-= 2 * sizeof(void *); /* allow space for malloc overhead */
325 uint32_t git_pool__suggest_items_per_page(uint32_t item_size
)
327 uint32_t page_bytes
=
328 git_pool__system_page_size() - sizeof(git_pool_page
);
329 return page_bytes
/ item_size
;