/**************************************************************************** * mm/mm_heap/mm_shrinkchunk.c * * SPDX-License-Identifier: Apache-2.0 * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you 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. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include "mm_heap/mm.h" /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: mm_shrinkchunk * * Description: * Reduce the size of the chunk specified by the node structure to the * specified size. this internal logic is used both from memalign to * dispose of any trailing memory in the aligned allocation and also by * realloc when there is a request to reduce the size of an allocation. * * NOTES: * (1) size is the whole chunk size (payload and header) * (2) the caller must hold the MM mutex. * ****************************************************************************/ void mm_shrinkchunk(FAR struct mm_heap_s *heap, FAR struct mm_allocnode_s *node, size_t size) { FAR struct mm_freenode_s *next; size_t nodesize = MM_SIZEOF_NODE(node); DEBUGASSERT((size & MM_GRAN_MASK) == 0); /* Get a reference to the next node */ next = (FAR struct mm_freenode_s *)((FAR char *)node + nodesize); /* Check if it is free */ if (MM_NODE_IS_FREE(next)) { FAR struct mm_allocnode_s *andbeyond; FAR struct mm_freenode_s *newnode; size_t nextsize = MM_SIZEOF_NODE(next); /* Get the chunk next the next node (which could be the tail chunk) */ andbeyond = (FAR struct mm_allocnode_s *)((FAR char *)next + nextsize); DEBUGASSERT(MM_PREVNODE_IS_FREE(andbeyond)); /* Remove the next node. There must be a predecessor, but there may * not be a successor node. */ DEBUGASSERT(next->blink); next->blink->flink = next->flink; if (next->flink) { next->flink->blink = next->blink; } /* Create a new chunk that will hold both the next chunk and the * tailing memory from the aligned chunk. */ newnode = (FAR struct mm_freenode_s *)((FAR char *)node + size); /* Set up the size of the new node */ newnode->size = nextsize + nodesize - size; node->size = size | (node->size & MM_MASK_BIT); andbeyond->preceding = newnode->size; /* Add the new node to the freenodelist */ mm_addfreechunk(heap, newnode); } /* The next chunk is allocated. Try to free the end portion at the end * chunk to be shrunk. */ else if (nodesize >= size + MM_MIN_CHUNK) { FAR struct mm_freenode_s *newnode; /* Create a new chunk that will hold both the next chunk and the * tailing memory from the aligned chunk. */ newnode = (FAR struct mm_freenode_s *)((FAR char *)node + size); /* Set up the size of the new node */ newnode->size = nodesize - size; node->size = size | (node->size & MM_MASK_BIT); next->size |= MM_PREVFREE_BIT; next->preceding = newnode->size; /* Add the new node to the freenodelist */ mm_addfreechunk(heap, newnode); } }