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