123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- /*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "ufdt_node_pool.h"
- #include "libufdt_sysdeps.h"
- #include "ufdt_types.h"
- /* Define DEBUG_DISABLE_POOL to use dto_malloc and dto_free directly */
- /* #define DEBUG_DISABLE_POOL */
- #define MAX(a, b) ((a) > (b) ? (a) : (b))
- #define UFDT_NODE_POOL_ENTRIES_PER_BLOCK 1024
- /* UFDT_NODE_POOL_ENTRY_SIZE must be equal to or larger than
- sizeof(struct ufdt_node_fdt_node) and sizeof(struct ufdt_node_fdt_prop) */
- #define UFDT_NODE_POOL_ENTRY_SIZE \
- MAX(sizeof(struct ufdt_node_fdt_node), sizeof(struct ufdt_node_fdt_prop))
- /* A block is a header appended UFDT_NODE_POOL_ENTRIES_PER_BLOCK entries */
- #define UFDT_NODE_POOL_BLOCK_SIZE \
- (sizeof(struct ufdt_node_pool_block_header) + \
- UFDT_NODE_POOL_ENTRY_SIZE * UFDT_NODE_POOL_ENTRIES_PER_BLOCK)
- /*
- * The data structure:
- *
- * pool block block
- * +--------------+ +--------------------+ +-----------------+
- * | *first_block |---->| block_header: | | ... | ...
- * | ... | | *next_block |---->| |---->
- * +--------------+ | *first_free_entry |--\ | ... |
- * | ... | |
- * +--------------------+ |
- * | entry_header: |<-/
- * | *next |--\
- * +--------------------+ |
- * | ... |<-/
- * | |--\
- * +--------------------+ |
- * | ... | v
- */
- struct ufdt_node_pool_entry_header {
- struct ufdt_node_pool_entry_header *next;
- };
- struct ufdt_node_pool_block_header {
- struct ufdt_node_pool_block_header *next_block;
- struct ufdt_node_pool_entry_header *first_free_entry;
- int alloc_entry_cnt;
- };
- void ufdt_node_pool_construct(struct ufdt_node_pool *pool) {
- pool->first_block = NULL;
- pool->last_block_ptr = &pool->first_block;
- }
- void ufdt_node_pool_destruct(struct ufdt_node_pool *pool) {
- int is_leak = 0;
- struct ufdt_node_pool_block_header *block = pool->first_block;
- while (block != NULL) {
- if (block->alloc_entry_cnt != 0) is_leak = 1;
- struct ufdt_node_pool_block_header *next_block = block->next_block;
- dto_free(block);
- block = next_block;
- }
- if (is_leak) {
- dto_error("Some nodes aren't freed before ufdt_node_pool_destruct().\n");
- }
- pool->first_block = NULL;
- pool->last_block_ptr = NULL;
- }
- static struct ufdt_node_pool_block_header *_ufdt_node_pool_create_block() {
- char *block_buf = (char *)dto_malloc(UFDT_NODE_POOL_BLOCK_SIZE);
- char *block_buf_start = block_buf + sizeof(struct ufdt_node_pool_block_header);
- char *block_buf_end = block_buf + UFDT_NODE_POOL_BLOCK_SIZE;
- struct ufdt_node_pool_block_header *block =
- (struct ufdt_node_pool_block_header *)block_buf;
- // Setup all entries to be a one way link list
- struct ufdt_node_pool_entry_header **next_ptr = &block->first_free_entry;
- for (char *entry_buf = block_buf_start; entry_buf < block_buf_end;
- entry_buf += UFDT_NODE_POOL_ENTRY_SIZE) {
- struct ufdt_node_pool_entry_header *entry =
- (struct ufdt_node_pool_entry_header *)entry_buf;
- *next_ptr = entry;
- next_ptr = &entry->next;
- }
- *next_ptr = NULL;
- block->next_block = NULL;
- block->alloc_entry_cnt = 0;
- return block;
- }
- static void _ufdt_node_pool_destory_block(
- struct ufdt_node_pool_block_header *block) {
- dto_free(block);
- }
- static void *_ufdt_node_pool_block_alloc(
- struct ufdt_node_pool_block_header *block) {
- // take the first free enrtry
- struct ufdt_node_pool_entry_header *entry = block->first_free_entry;
- block->first_free_entry = entry->next;
- block->alloc_entry_cnt++;
- return entry;
- }
- static void _ufdt_node_pool_block_free(struct ufdt_node_pool_block_header *block,
- void *node) {
- // put the node to the first free enrtry
- struct ufdt_node_pool_entry_header *entry = node;
- entry->next = block->first_free_entry;
- block->first_free_entry = entry;
- block->alloc_entry_cnt--;
- }
- static void _ufdt_node_pool_preppend_block(
- struct ufdt_node_pool *pool, struct ufdt_node_pool_block_header *block) {
- struct ufdt_node_pool_block_header *origin_first_block = pool->first_block;
- block->next_block = origin_first_block;
- pool->first_block = block;
- if (origin_first_block == NULL) {
- pool->last_block_ptr = &block->next_block;
- }
- }
- static void _ufdt_node_pool_append_block(
- struct ufdt_node_pool *pool, struct ufdt_node_pool_block_header *block) {
- block->next_block = NULL;
- *pool->last_block_ptr = block;
- pool->last_block_ptr = &block->next_block;
- }
- static void _ufdt_node_pool_remove_block(
- struct ufdt_node_pool *pool,
- struct ufdt_node_pool_block_header **block_ptr) {
- struct ufdt_node_pool_block_header *block = *block_ptr;
- struct ufdt_node_pool_block_header *next_block = block->next_block;
- *block_ptr = next_block;
- if (next_block == NULL) {
- pool->last_block_ptr = block_ptr;
- }
- block->next_block = NULL;
- }
- void *ufdt_node_pool_alloc(struct ufdt_node_pool *pool) {
- #ifdef DEBUG_DISABLE_POOL
- return dto_malloc(UFDT_NODE_POOL_ENTRY_SIZE);
- #endif
- // return dto_malloc(UFDT_NODE_POOL_ENTRY_SIZE);
- // If there is no free block, create a new one
- struct ufdt_node_pool_block_header *block = pool->first_block;
- if (block == NULL || block->first_free_entry == NULL) {
- block = _ufdt_node_pool_create_block();
- _ufdt_node_pool_preppend_block(pool, block);
- }
- void *node = _ufdt_node_pool_block_alloc(block);
- // Move the block to the last if there is no free entry
- if (block->first_free_entry == NULL && *pool->last_block_ptr != block) {
- _ufdt_node_pool_remove_block(pool, &pool->first_block);
- _ufdt_node_pool_append_block(pool, block);
- }
- return node;
- }
- static struct ufdt_node_pool_block_header **_ufdt_node_pool_search_block(
- struct ufdt_node_pool *pool, void *node) {
- struct ufdt_node_pool_block_header **block_ptr = &pool->first_block;
- while (*block_ptr != NULL) {
- struct ufdt_node_pool_block_header *block = *block_ptr;
- const char *block_buf_start =
- (char *)block + sizeof(struct ufdt_node_pool_block_header);
- const char *block_buf_end = (char *)block + UFDT_NODE_POOL_BLOCK_SIZE;
- if ((char *)node >= block_buf_start && (char *)node < block_buf_end) {
- break;
- }
- block_ptr = &block->next_block;
- }
- return block_ptr;
- }
- void ufdt_node_pool_free(struct ufdt_node_pool *pool, void *node) {
- #ifdef DEBUG_DISABLE_POOL
- return dto_free(node);
- #endif
- struct ufdt_node_pool_block_header **block_ptr =
- _ufdt_node_pool_search_block(pool, node);
- if (*block_ptr == NULL) {
- dto_error("Given node is not in the pool.\n");
- return;
- }
- struct ufdt_node_pool_block_header *block = *block_ptr;
- _ufdt_node_pool_block_free(block, node);
- _ufdt_node_pool_remove_block(pool, block_ptr);
- /* Delay free block: free the block only if the block is all freed and
- there has at least one another free block */
- if (block->alloc_entry_cnt == 0 && pool->first_block != NULL &&
- pool->first_block->first_free_entry != NULL) {
- _ufdt_node_pool_destory_block(block);
- return;
- }
- _ufdt_node_pool_preppend_block(pool, block);
- }
|