1 /***************************************************************************
2 * Copyright (C) 2012~2012 by CSSlayer *
3 * wengxt@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
20
21 #include "fcitx/fcitx.h"
22 #include "fcitx-utils/memory.h"
23 #include "utarray.h"
24 #include "utils.h"
25
26 /* use 8k as pagesize */
27 #define FCITX_MEMORY_POOL_PAGE_SIZE (8*1024)
28 #define FCITX_MEMORY_CHUNK_FULL_SIZE (16)
29
30 typedef struct _FcitxMemoryChunk {
31 void *cur;
32 void *end;
33 void *memory;
34 } FcitxMemoryChunk;
35
36 struct _FcitxMemoryPool {
37 UT_array* fullchunks;
38 UT_array* chunks;
39 };
40
41 static void fcitx_memory_chunk_free(void* c);
42 static const UT_icd chunk_icd = {
43 sizeof(FcitxMemoryChunk), NULL, NULL, fcitx_memory_chunk_free
44 };
45
fcitx_memory_chunk_free(void * c)46 void fcitx_memory_chunk_free(void* c) {
47 FcitxMemoryChunk* chunk = (FcitxMemoryChunk*) c;
48 if (chunk->memory) {
49 free(chunk->memory);
50 chunk->memory = NULL;
51 }
52 }
53
54 FCITX_EXPORT_API
fcitx_memory_pool_create()55 FcitxMemoryPool* fcitx_memory_pool_create()
56 {
57 FcitxMemoryPool* pool = fcitx_utils_malloc0(sizeof(FcitxMemoryPool));
58 utarray_new(pool->fullchunks, &chunk_icd);
59 utarray_new(pool->chunks, &chunk_icd);
60 return pool;
61 }
62
63 static inline void*
memory_align_ptr(void * p)64 memory_align_ptr(void *p)
65 {
66 return (void*)fcitx_utils_align_to((uintptr_t)p, sizeof(int));
67 }
68
69 FCITX_EXPORT_API
fcitx_memory_pool_alloc_align(FcitxMemoryPool * pool,size_t size,int align)70 void* fcitx_memory_pool_alloc_align(FcitxMemoryPool* pool, size_t size, int align)
71 {
72 FcitxMemoryChunk* chunk;
73 void *result;
74 for(chunk = (FcitxMemoryChunk*) utarray_front(pool->chunks);
75 chunk != NULL;
76 chunk = (FcitxMemoryChunk*) utarray_next(pool->chunks, chunk)) {
77 result = align ? memory_align_ptr(chunk->cur) : chunk->cur;
78 void *new = result + size;
79 if (new <= chunk->end) {
80 chunk->cur = new;
81 break;
82 }
83 }
84
85 if (chunk == NULL) {
86 size_t chunkSize = ((size + FCITX_MEMORY_POOL_PAGE_SIZE - 1) / FCITX_MEMORY_POOL_PAGE_SIZE) * FCITX_MEMORY_POOL_PAGE_SIZE;
87 FcitxMemoryChunk c;
88 /* should be properly aligned already */
89 result = fcitx_utils_malloc0(chunkSize);
90 c.end = result + chunkSize;
91 c.memory = result;
92 c.cur = result + size;
93
94 utarray_push_back(pool->chunks, &c);
95 chunk = (FcitxMemoryChunk*)utarray_back(pool->chunks);
96 }
97
98 if (chunk->end - chunk->cur <= FCITX_MEMORY_CHUNK_FULL_SIZE) {
99 utarray_push_back(pool->fullchunks, chunk);
100 unsigned int idx = utarray_eltidx(pool->chunks, chunk);
101 utarray_remove_quick(pool->chunks, idx);
102 }
103
104 return result;
105 }
106
107 #undef fcitx_memory_pool_alloc
108
109 FCITX_EXPORT_API
fcitx_memory_pool_alloc(FcitxMemoryPool * pool,size_t size)110 void* fcitx_memory_pool_alloc(FcitxMemoryPool* pool, size_t size)
111 {
112 return fcitx_memory_pool_alloc_align(pool, size, 0);
113 }
114
115 FCITX_EXPORT_API
fcitx_memory_pool_destroy(FcitxMemoryPool * pool)116 void fcitx_memory_pool_destroy(FcitxMemoryPool* pool)
117 {
118 utarray_free(pool->fullchunks);
119 utarray_free(pool->chunks);
120 free(pool);
121 }
122
123 FCITX_EXPORT_API
124 void
fcitx_memory_pool_clear(FcitxMemoryPool * pool)125 fcitx_memory_pool_clear(FcitxMemoryPool *pool)
126 {
127 utarray_clear(pool->fullchunks);
128 utarray_clear(pool->chunks);
129 }
130