xref: /aosp_15_r20/system/libufdt/ufdt_node_pool.c (revision 13e8728f0cffde9369df671f7b293a048a99c7ed)
1*13e8728fSAndroid Build Coastguard Worker /*
2*13e8728fSAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*13e8728fSAndroid Build Coastguard Worker  *
4*13e8728fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*13e8728fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*13e8728fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*13e8728fSAndroid Build Coastguard Worker  *
8*13e8728fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*13e8728fSAndroid Build Coastguard Worker  *
10*13e8728fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*13e8728fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*13e8728fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*13e8728fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*13e8728fSAndroid Build Coastguard Worker  * limitations under the License.
15*13e8728fSAndroid Build Coastguard Worker  */
16*13e8728fSAndroid Build Coastguard Worker 
17*13e8728fSAndroid Build Coastguard Worker #include "ufdt_node_pool.h"
18*13e8728fSAndroid Build Coastguard Worker 
19*13e8728fSAndroid Build Coastguard Worker #include "libufdt_sysdeps.h"
20*13e8728fSAndroid Build Coastguard Worker #include "ufdt_types.h"
21*13e8728fSAndroid Build Coastguard Worker 
22*13e8728fSAndroid Build Coastguard Worker /* Define DEBUG_DISABLE_POOL to use dto_malloc and dto_free directly */
23*13e8728fSAndroid Build Coastguard Worker /* #define DEBUG_DISABLE_POOL */
24*13e8728fSAndroid Build Coastguard Worker 
25*13e8728fSAndroid Build Coastguard Worker #define MAX(a, b) ((a) > (b) ? (a) : (b))
26*13e8728fSAndroid Build Coastguard Worker 
27*13e8728fSAndroid Build Coastguard Worker #define UFDT_NODE_POOL_ENTRIES_PER_BLOCK 1024
28*13e8728fSAndroid Build Coastguard Worker /* UFDT_NODE_POOL_ENTRY_SIZE must be equal to or larger than
29*13e8728fSAndroid Build Coastguard Worker    sizeof(struct ufdt_node_fdt_node) and sizeof(struct ufdt_node_fdt_prop) */
30*13e8728fSAndroid Build Coastguard Worker #define UFDT_NODE_POOL_ENTRY_SIZE \
31*13e8728fSAndroid Build Coastguard Worker   MAX(sizeof(struct ufdt_node_fdt_node), sizeof(struct ufdt_node_fdt_prop))
32*13e8728fSAndroid Build Coastguard Worker /* A block is a header appended UFDT_NODE_POOL_ENTRIES_PER_BLOCK entries */
33*13e8728fSAndroid Build Coastguard Worker #define UFDT_NODE_POOL_BLOCK_SIZE               \
34*13e8728fSAndroid Build Coastguard Worker   (sizeof(struct ufdt_node_pool_block_header) + \
35*13e8728fSAndroid Build Coastguard Worker    UFDT_NODE_POOL_ENTRY_SIZE * UFDT_NODE_POOL_ENTRIES_PER_BLOCK)
36*13e8728fSAndroid Build Coastguard Worker 
37*13e8728fSAndroid Build Coastguard Worker /*
38*13e8728fSAndroid Build Coastguard Worker  * The data structure:
39*13e8728fSAndroid Build Coastguard Worker  *
40*13e8728fSAndroid Build Coastguard Worker  *        pool                   block                     block
41*13e8728fSAndroid Build Coastguard Worker  *  +--------------+     +--------------------+     +-----------------+
42*13e8728fSAndroid Build Coastguard Worker  *  | *first_block |---->| block_header:      |     | ...             | ...
43*13e8728fSAndroid Build Coastguard Worker  *  | ...          |     |  *next_block       |---->|                 |---->
44*13e8728fSAndroid Build Coastguard Worker  *  +--------------+     |  *first_free_entry |--\  | ...             |
45*13e8728fSAndroid Build Coastguard Worker  *                       |  ...               |  |
46*13e8728fSAndroid Build Coastguard Worker  *                       +--------------------+  |
47*13e8728fSAndroid Build Coastguard Worker  *                       | entry_header:      |<-/
48*13e8728fSAndroid Build Coastguard Worker  *                       |  *next             |--\
49*13e8728fSAndroid Build Coastguard Worker  *                       +--------------------+  |
50*13e8728fSAndroid Build Coastguard Worker  *                       |  ...               |<-/
51*13e8728fSAndroid Build Coastguard Worker  *                       |                    |--\
52*13e8728fSAndroid Build Coastguard Worker  *                       +--------------------+  |
53*13e8728fSAndroid Build Coastguard Worker  *                       |  ...               |  v
54*13e8728fSAndroid Build Coastguard Worker  */
55*13e8728fSAndroid Build Coastguard Worker 
56*13e8728fSAndroid Build Coastguard Worker struct ufdt_node_pool_entry_header {
57*13e8728fSAndroid Build Coastguard Worker   struct ufdt_node_pool_entry_header *next;
58*13e8728fSAndroid Build Coastguard Worker };
59*13e8728fSAndroid Build Coastguard Worker 
60*13e8728fSAndroid Build Coastguard Worker struct ufdt_node_pool_block_header {
61*13e8728fSAndroid Build Coastguard Worker   struct ufdt_node_pool_block_header *next_block;
62*13e8728fSAndroid Build Coastguard Worker   struct ufdt_node_pool_entry_header *first_free_entry;
63*13e8728fSAndroid Build Coastguard Worker   int alloc_entry_cnt;
64*13e8728fSAndroid Build Coastguard Worker };
65*13e8728fSAndroid Build Coastguard Worker 
ufdt_node_pool_construct(struct ufdt_node_pool * pool)66*13e8728fSAndroid Build Coastguard Worker void ufdt_node_pool_construct(struct ufdt_node_pool *pool) {
67*13e8728fSAndroid Build Coastguard Worker   pool->first_block = NULL;
68*13e8728fSAndroid Build Coastguard Worker   pool->last_block_ptr = &pool->first_block;
69*13e8728fSAndroid Build Coastguard Worker }
70*13e8728fSAndroid Build Coastguard Worker 
ufdt_node_pool_destruct(struct ufdt_node_pool * pool)71*13e8728fSAndroid Build Coastguard Worker void ufdt_node_pool_destruct(struct ufdt_node_pool *pool) {
72*13e8728fSAndroid Build Coastguard Worker   int is_leak = 0;
73*13e8728fSAndroid Build Coastguard Worker   struct ufdt_node_pool_block_header *block = pool->first_block;
74*13e8728fSAndroid Build Coastguard Worker   while (block != NULL) {
75*13e8728fSAndroid Build Coastguard Worker     if (block->alloc_entry_cnt != 0) is_leak = 1;
76*13e8728fSAndroid Build Coastguard Worker 
77*13e8728fSAndroid Build Coastguard Worker     struct ufdt_node_pool_block_header *next_block = block->next_block;
78*13e8728fSAndroid Build Coastguard Worker     dto_free(block);
79*13e8728fSAndroid Build Coastguard Worker     block = next_block;
80*13e8728fSAndroid Build Coastguard Worker   }
81*13e8728fSAndroid Build Coastguard Worker 
82*13e8728fSAndroid Build Coastguard Worker   if (is_leak) {
83*13e8728fSAndroid Build Coastguard Worker     dto_error("Some nodes aren't freed before ufdt_node_pool_destruct().\n");
84*13e8728fSAndroid Build Coastguard Worker   }
85*13e8728fSAndroid Build Coastguard Worker 
86*13e8728fSAndroid Build Coastguard Worker   pool->first_block = NULL;
87*13e8728fSAndroid Build Coastguard Worker   pool->last_block_ptr = NULL;
88*13e8728fSAndroid Build Coastguard Worker }
89*13e8728fSAndroid Build Coastguard Worker 
_ufdt_node_pool_create_block()90*13e8728fSAndroid Build Coastguard Worker static struct ufdt_node_pool_block_header *_ufdt_node_pool_create_block() {
91*13e8728fSAndroid Build Coastguard Worker   char *block_buf = (char *)dto_malloc(UFDT_NODE_POOL_BLOCK_SIZE);
92*13e8728fSAndroid Build Coastguard Worker   char *block_buf_start = block_buf + sizeof(struct ufdt_node_pool_block_header);
93*13e8728fSAndroid Build Coastguard Worker   char *block_buf_end = block_buf + UFDT_NODE_POOL_BLOCK_SIZE;
94*13e8728fSAndroid Build Coastguard Worker 
95*13e8728fSAndroid Build Coastguard Worker   struct ufdt_node_pool_block_header *block =
96*13e8728fSAndroid Build Coastguard Worker       (struct ufdt_node_pool_block_header *)block_buf;
97*13e8728fSAndroid Build Coastguard Worker 
98*13e8728fSAndroid Build Coastguard Worker   // Setup all entries to be a one way link list
99*13e8728fSAndroid Build Coastguard Worker   struct ufdt_node_pool_entry_header **next_ptr = &block->first_free_entry;
100*13e8728fSAndroid Build Coastguard Worker   for (char *entry_buf = block_buf_start; entry_buf < block_buf_end;
101*13e8728fSAndroid Build Coastguard Worker        entry_buf += UFDT_NODE_POOL_ENTRY_SIZE) {
102*13e8728fSAndroid Build Coastguard Worker     struct ufdt_node_pool_entry_header *entry =
103*13e8728fSAndroid Build Coastguard Worker         (struct ufdt_node_pool_entry_header *)entry_buf;
104*13e8728fSAndroid Build Coastguard Worker 
105*13e8728fSAndroid Build Coastguard Worker     *next_ptr = entry;
106*13e8728fSAndroid Build Coastguard Worker 
107*13e8728fSAndroid Build Coastguard Worker     next_ptr = &entry->next;
108*13e8728fSAndroid Build Coastguard Worker   }
109*13e8728fSAndroid Build Coastguard Worker   *next_ptr = NULL;
110*13e8728fSAndroid Build Coastguard Worker 
111*13e8728fSAndroid Build Coastguard Worker   block->next_block = NULL;
112*13e8728fSAndroid Build Coastguard Worker   block->alloc_entry_cnt = 0;
113*13e8728fSAndroid Build Coastguard Worker 
114*13e8728fSAndroid Build Coastguard Worker   return block;
115*13e8728fSAndroid Build Coastguard Worker }
116*13e8728fSAndroid Build Coastguard Worker 
_ufdt_node_pool_destory_block(struct ufdt_node_pool_block_header * block)117*13e8728fSAndroid Build Coastguard Worker static void _ufdt_node_pool_destory_block(
118*13e8728fSAndroid Build Coastguard Worker     struct ufdt_node_pool_block_header *block) {
119*13e8728fSAndroid Build Coastguard Worker   dto_free(block);
120*13e8728fSAndroid Build Coastguard Worker }
121*13e8728fSAndroid Build Coastguard Worker 
_ufdt_node_pool_block_alloc(struct ufdt_node_pool_block_header * block)122*13e8728fSAndroid Build Coastguard Worker static void *_ufdt_node_pool_block_alloc(
123*13e8728fSAndroid Build Coastguard Worker     struct ufdt_node_pool_block_header *block) {
124*13e8728fSAndroid Build Coastguard Worker   // take the first free enrtry
125*13e8728fSAndroid Build Coastguard Worker   struct ufdt_node_pool_entry_header *entry = block->first_free_entry;
126*13e8728fSAndroid Build Coastguard Worker 
127*13e8728fSAndroid Build Coastguard Worker   block->first_free_entry = entry->next;
128*13e8728fSAndroid Build Coastguard Worker   block->alloc_entry_cnt++;
129*13e8728fSAndroid Build Coastguard Worker 
130*13e8728fSAndroid Build Coastguard Worker   return entry;
131*13e8728fSAndroid Build Coastguard Worker }
132*13e8728fSAndroid Build Coastguard Worker 
_ufdt_node_pool_block_free(struct ufdt_node_pool_block_header * block,void * node)133*13e8728fSAndroid Build Coastguard Worker static void _ufdt_node_pool_block_free(struct ufdt_node_pool_block_header *block,
134*13e8728fSAndroid Build Coastguard Worker                                        void *node) {
135*13e8728fSAndroid Build Coastguard Worker   // put the node to the first free enrtry
136*13e8728fSAndroid Build Coastguard Worker   struct ufdt_node_pool_entry_header *entry = node;
137*13e8728fSAndroid Build Coastguard Worker   entry->next = block->first_free_entry;
138*13e8728fSAndroid Build Coastguard Worker 
139*13e8728fSAndroid Build Coastguard Worker   block->first_free_entry = entry;
140*13e8728fSAndroid Build Coastguard Worker   block->alloc_entry_cnt--;
141*13e8728fSAndroid Build Coastguard Worker }
142*13e8728fSAndroid Build Coastguard Worker 
_ufdt_node_pool_preppend_block(struct ufdt_node_pool * pool,struct ufdt_node_pool_block_header * block)143*13e8728fSAndroid Build Coastguard Worker static void _ufdt_node_pool_preppend_block(
144*13e8728fSAndroid Build Coastguard Worker     struct ufdt_node_pool *pool, struct ufdt_node_pool_block_header *block) {
145*13e8728fSAndroid Build Coastguard Worker   struct ufdt_node_pool_block_header *origin_first_block = pool->first_block;
146*13e8728fSAndroid Build Coastguard Worker   block->next_block = origin_first_block;
147*13e8728fSAndroid Build Coastguard Worker 
148*13e8728fSAndroid Build Coastguard Worker   pool->first_block = block;
149*13e8728fSAndroid Build Coastguard Worker   if (origin_first_block == NULL) {
150*13e8728fSAndroid Build Coastguard Worker     pool->last_block_ptr = &block->next_block;
151*13e8728fSAndroid Build Coastguard Worker   }
152*13e8728fSAndroid Build Coastguard Worker }
153*13e8728fSAndroid Build Coastguard Worker 
_ufdt_node_pool_append_block(struct ufdt_node_pool * pool,struct ufdt_node_pool_block_header * block)154*13e8728fSAndroid Build Coastguard Worker static void _ufdt_node_pool_append_block(
155*13e8728fSAndroid Build Coastguard Worker     struct ufdt_node_pool *pool, struct ufdt_node_pool_block_header *block) {
156*13e8728fSAndroid Build Coastguard Worker   block->next_block = NULL;
157*13e8728fSAndroid Build Coastguard Worker 
158*13e8728fSAndroid Build Coastguard Worker   *pool->last_block_ptr = block;
159*13e8728fSAndroid Build Coastguard Worker   pool->last_block_ptr = &block->next_block;
160*13e8728fSAndroid Build Coastguard Worker }
161*13e8728fSAndroid Build Coastguard Worker 
_ufdt_node_pool_remove_block(struct ufdt_node_pool * pool,struct ufdt_node_pool_block_header ** block_ptr)162*13e8728fSAndroid Build Coastguard Worker static void _ufdt_node_pool_remove_block(
163*13e8728fSAndroid Build Coastguard Worker     struct ufdt_node_pool *pool,
164*13e8728fSAndroid Build Coastguard Worker     struct ufdt_node_pool_block_header **block_ptr) {
165*13e8728fSAndroid Build Coastguard Worker   struct ufdt_node_pool_block_header *block = *block_ptr;
166*13e8728fSAndroid Build Coastguard Worker   struct ufdt_node_pool_block_header *next_block = block->next_block;
167*13e8728fSAndroid Build Coastguard Worker 
168*13e8728fSAndroid Build Coastguard Worker   *block_ptr = next_block;
169*13e8728fSAndroid Build Coastguard Worker   if (next_block == NULL) {
170*13e8728fSAndroid Build Coastguard Worker     pool->last_block_ptr = block_ptr;
171*13e8728fSAndroid Build Coastguard Worker   }
172*13e8728fSAndroid Build Coastguard Worker 
173*13e8728fSAndroid Build Coastguard Worker   block->next_block = NULL;
174*13e8728fSAndroid Build Coastguard Worker }
175*13e8728fSAndroid Build Coastguard Worker 
ufdt_node_pool_alloc(struct ufdt_node_pool * pool)176*13e8728fSAndroid Build Coastguard Worker void *ufdt_node_pool_alloc(struct ufdt_node_pool *pool) {
177*13e8728fSAndroid Build Coastguard Worker #ifdef DEBUG_DISABLE_POOL
178*13e8728fSAndroid Build Coastguard Worker   return dto_malloc(UFDT_NODE_POOL_ENTRY_SIZE);
179*13e8728fSAndroid Build Coastguard Worker #endif
180*13e8728fSAndroid Build Coastguard Worker 
181*13e8728fSAndroid Build Coastguard Worker   // return dto_malloc(UFDT_NODE_POOL_ENTRY_SIZE);
182*13e8728fSAndroid Build Coastguard Worker   // If there is no free block, create a new one
183*13e8728fSAndroid Build Coastguard Worker   struct ufdt_node_pool_block_header *block = pool->first_block;
184*13e8728fSAndroid Build Coastguard Worker   if (block == NULL || block->first_free_entry == NULL) {
185*13e8728fSAndroid Build Coastguard Worker     block = _ufdt_node_pool_create_block();
186*13e8728fSAndroid Build Coastguard Worker     _ufdt_node_pool_preppend_block(pool, block);
187*13e8728fSAndroid Build Coastguard Worker   }
188*13e8728fSAndroid Build Coastguard Worker 
189*13e8728fSAndroid Build Coastguard Worker   void *node = _ufdt_node_pool_block_alloc(block);
190*13e8728fSAndroid Build Coastguard Worker 
191*13e8728fSAndroid Build Coastguard Worker   // Move the block to the last if there is no free entry
192*13e8728fSAndroid Build Coastguard Worker   if (block->first_free_entry == NULL && *pool->last_block_ptr != block) {
193*13e8728fSAndroid Build Coastguard Worker     _ufdt_node_pool_remove_block(pool, &pool->first_block);
194*13e8728fSAndroid Build Coastguard Worker     _ufdt_node_pool_append_block(pool, block);
195*13e8728fSAndroid Build Coastguard Worker   }
196*13e8728fSAndroid Build Coastguard Worker 
197*13e8728fSAndroid Build Coastguard Worker   return node;
198*13e8728fSAndroid Build Coastguard Worker }
199*13e8728fSAndroid Build Coastguard Worker 
_ufdt_node_pool_search_block(struct ufdt_node_pool * pool,void * node)200*13e8728fSAndroid Build Coastguard Worker static struct ufdt_node_pool_block_header **_ufdt_node_pool_search_block(
201*13e8728fSAndroid Build Coastguard Worker     struct ufdt_node_pool *pool, void *node) {
202*13e8728fSAndroid Build Coastguard Worker   struct ufdt_node_pool_block_header **block_ptr = &pool->first_block;
203*13e8728fSAndroid Build Coastguard Worker   while (*block_ptr != NULL) {
204*13e8728fSAndroid Build Coastguard Worker     struct ufdt_node_pool_block_header *block = *block_ptr;
205*13e8728fSAndroid Build Coastguard Worker     const char *block_buf_start =
206*13e8728fSAndroid Build Coastguard Worker         (char *)block + sizeof(struct ufdt_node_pool_block_header);
207*13e8728fSAndroid Build Coastguard Worker     const char *block_buf_end = (char *)block + UFDT_NODE_POOL_BLOCK_SIZE;
208*13e8728fSAndroid Build Coastguard Worker 
209*13e8728fSAndroid Build Coastguard Worker     if ((char *)node >= block_buf_start && (char *)node < block_buf_end) {
210*13e8728fSAndroid Build Coastguard Worker       break;
211*13e8728fSAndroid Build Coastguard Worker     }
212*13e8728fSAndroid Build Coastguard Worker 
213*13e8728fSAndroid Build Coastguard Worker     block_ptr = &block->next_block;
214*13e8728fSAndroid Build Coastguard Worker   }
215*13e8728fSAndroid Build Coastguard Worker   return block_ptr;
216*13e8728fSAndroid Build Coastguard Worker }
217*13e8728fSAndroid Build Coastguard Worker 
ufdt_node_pool_free(struct ufdt_node_pool * pool,void * node)218*13e8728fSAndroid Build Coastguard Worker void ufdt_node_pool_free(struct ufdt_node_pool *pool, void *node) {
219*13e8728fSAndroid Build Coastguard Worker #ifdef DEBUG_DISABLE_POOL
220*13e8728fSAndroid Build Coastguard Worker   return dto_free(node);
221*13e8728fSAndroid Build Coastguard Worker #endif
222*13e8728fSAndroid Build Coastguard Worker 
223*13e8728fSAndroid Build Coastguard Worker   struct ufdt_node_pool_block_header **block_ptr =
224*13e8728fSAndroid Build Coastguard Worker       _ufdt_node_pool_search_block(pool, node);
225*13e8728fSAndroid Build Coastguard Worker   if (*block_ptr == NULL) {
226*13e8728fSAndroid Build Coastguard Worker     dto_error("Given node is not in the pool.\n");
227*13e8728fSAndroid Build Coastguard Worker     return;
228*13e8728fSAndroid Build Coastguard Worker   }
229*13e8728fSAndroid Build Coastguard Worker 
230*13e8728fSAndroid Build Coastguard Worker   struct ufdt_node_pool_block_header *block = *block_ptr;
231*13e8728fSAndroid Build Coastguard Worker   _ufdt_node_pool_block_free(block, node);
232*13e8728fSAndroid Build Coastguard Worker   _ufdt_node_pool_remove_block(pool, block_ptr);
233*13e8728fSAndroid Build Coastguard Worker 
234*13e8728fSAndroid Build Coastguard Worker   /* Delay free block: free the block only if the block is all freed and
235*13e8728fSAndroid Build Coastguard Worker       there has at least one another free block */
236*13e8728fSAndroid Build Coastguard Worker   if (block->alloc_entry_cnt == 0 && pool->first_block != NULL &&
237*13e8728fSAndroid Build Coastguard Worker       pool->first_block->first_free_entry != NULL) {
238*13e8728fSAndroid Build Coastguard Worker     _ufdt_node_pool_destory_block(block);
239*13e8728fSAndroid Build Coastguard Worker     return;
240*13e8728fSAndroid Build Coastguard Worker   }
241*13e8728fSAndroid Build Coastguard Worker 
242*13e8728fSAndroid Build Coastguard Worker   _ufdt_node_pool_preppend_block(pool, block);
243*13e8728fSAndroid Build Coastguard Worker }
244