mirror of
https://github.com/apache/nuttx.git
synced 2025-01-13 08:38:38 +08:00
mm/mm_gran: remove allocation size limitation
This patch refactors granule allocator to remove the 32 granules limitation with the help of a gran_range_s structure and related functions, see "mm_grantable.h" for details. Below are the major functions explaining how this works: - The gran_match() checks if a gran range all in the given state. it gives last mismatch position when fails free range matching. - The gran_search() tries to find the position of a free range. It leverages last mismatch position from gran_match() to speed up the search. range size handling is mainly in gran_match() and gran_set_(). Signed-off-by: Yanfeng Liu <yfliu2008@qq.com>
This commit is contained in:
parent
db7c8be61f
commit
102a62c7e3
9 changed files with 560 additions and 475 deletions
|
@ -22,15 +22,9 @@
|
|||
|
||||
if(CONFIG_GRAN)
|
||||
|
||||
set(SRCS
|
||||
mm_graninit.c
|
||||
mm_granrelease.c
|
||||
mm_granreserve.c
|
||||
mm_granalloc.c
|
||||
mm_granmark.c
|
||||
mm_granfree.c
|
||||
mm_graninfo.c
|
||||
mm_grancritical.c)
|
||||
set(SRCS mm_graninit.c mm_granrelease.c mm_graninfo.c mm_grancritical.c)
|
||||
list(APPEND SRCS mm_grantable.c mm_granfree.c mm_granalloc.c)
|
||||
list(APPEND SRCS mm_granreserve.c)
|
||||
|
||||
# A page allocator based on the granule allocator
|
||||
|
||||
|
|
|
@ -21,8 +21,9 @@
|
|||
# An optional granule allocator
|
||||
|
||||
ifeq ($(CONFIG_GRAN),y)
|
||||
CSRCS += mm_graninit.c mm_granrelease.c mm_granreserve.c mm_granalloc.c
|
||||
CSRCS += mm_granmark.c mm_granfree.c mm_graninfo.c mm_grancritical.c
|
||||
|
||||
CSRCS += mm_graninit.c mm_granrelease.c mm_graninfo.c mm_grancritical.c
|
||||
CSRCS += mm_grantable.c mm_granfree.c mm_granalloc.c mm_granreserve.c
|
||||
|
||||
# A page allocator based on the granule allocator
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
|
||||
/* Debug */
|
||||
|
||||
#ifdef CONFIG_DEBUG_GRAM
|
||||
#ifdef CONFIG_DEBUG_GRAN
|
||||
# define granerr _err
|
||||
# define granwarn _warn
|
||||
# define graninfo _info
|
||||
|
|
|
@ -25,10 +25,12 @@
|
|||
#include <nuttx/config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/mm/gran.h>
|
||||
|
||||
#include "mm_gran/mm_gran.h"
|
||||
#include "mm_gran/mm_grantable.h"
|
||||
|
||||
#ifdef CONFIG_GRAN
|
||||
|
||||
|
@ -36,215 +38,45 @@
|
|||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gran_alloc
|
||||
*
|
||||
* Description:
|
||||
* Allocate memory from the granule heap.
|
||||
*
|
||||
* NOTE: The current implementation also restricts the maximum allocation
|
||||
* size to 32 granules. That restriction could be eliminated with some
|
||||
* additional coding effort.
|
||||
*
|
||||
* Input Parameters:
|
||||
* handle - The handle previously returned by gran_initialize
|
||||
* size - The size of the memory region to allocate.
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, a non-NULL pointer to the allocated memory is returned;
|
||||
* NULL is returned on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR void *gran_alloc(GRAN_HANDLE handle, size_t size)
|
||||
{
|
||||
FAR struct gran_s *priv = (FAR struct gran_s *)handle;
|
||||
unsigned int ngranules;
|
||||
size_t tmpmask;
|
||||
uintptr_t alloc;
|
||||
uint32_t curr;
|
||||
uint32_t next;
|
||||
uint32_t mask;
|
||||
int granidx;
|
||||
int gatidx;
|
||||
int bitidx;
|
||||
int shift;
|
||||
int ret;
|
||||
FAR gran_t *gran = (FAR gran_t *)handle;
|
||||
size_t ngran;
|
||||
int posi;
|
||||
int ret;
|
||||
uintptr_t retp;
|
||||
|
||||
DEBUGASSERT(priv != NULL && size <= 32 * (1 << priv->log2gran));
|
||||
|
||||
if (priv != NULL && size > 0)
|
||||
DEBUGASSERT(gran);
|
||||
ngran = NGRANULE(gran, size);
|
||||
if (!ngran || ngran > gran->ngranules)
|
||||
{
|
||||
/* Get exclusive access to the GAT */
|
||||
|
||||
ret = gran_enter_critical(priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* How many contiguous granules we we need to find? */
|
||||
|
||||
tmpmask = (1 << priv->log2gran) - 1;
|
||||
ngranules = (size + tmpmask) >> priv->log2gran;
|
||||
|
||||
/* Then create mask for that number of granules */
|
||||
|
||||
DEBUGASSERT(ngranules <= 32);
|
||||
mask = 0xffffffff >> (32 - ngranules);
|
||||
|
||||
/* Now search the granule allocation table for that number
|
||||
* of contiguous
|
||||
*/
|
||||
|
||||
for (granidx = 0; granidx < priv->ngranules; granidx += 32)
|
||||
{
|
||||
/* Get the GAT index associated with the granule table entry */
|
||||
|
||||
gatidx = granidx >> 5;
|
||||
curr = priv->gat[gatidx];
|
||||
|
||||
/* Handle the case where there are no free granules in the entry */
|
||||
|
||||
if (curr == 0xffffffff)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get the next entry from the GAT to support a 64 bit shift */
|
||||
|
||||
if (granidx + 32 < priv->ngranules)
|
||||
{
|
||||
next = priv->gat[gatidx + 1];
|
||||
}
|
||||
|
||||
/* Use all ones when are at the last entry in the GAT (meaning
|
||||
* nothing can be allocated.
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
next = 0xffffffff;
|
||||
}
|
||||
|
||||
/* Search through the allocations in the 'curr' GAT entry
|
||||
* to see if we can satisfy the allocation starting in that
|
||||
* entry.
|
||||
*
|
||||
* This loop continues until either all of the bits have been
|
||||
* examined (bitidx >= 32), or until there are insufficient
|
||||
* granules left to satisfy the allocation.
|
||||
*/
|
||||
|
||||
alloc = priv->heapstart + (granidx << priv->log2gran);
|
||||
|
||||
for (bitidx = 0;
|
||||
bitidx < 32 &&
|
||||
(granidx + bitidx + ngranules) <= priv->ngranules;
|
||||
)
|
||||
{
|
||||
/* Break out if there are no further free bits in 'curr'.
|
||||
* All of the zero bits might have gotten shifted out.
|
||||
*/
|
||||
|
||||
if (curr == 0xffffffff)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check for the first zero bit in the lower or upper 16-bits.
|
||||
* From the test above, we know that at least one of the 32-
|
||||
* bits in 'curr' is zero.
|
||||
*/
|
||||
|
||||
else if ((curr & 0x0000ffff) == 0x0000ffff)
|
||||
{
|
||||
/* Not in the lower 16 bits. The first free bit must be
|
||||
* in the upper 16 bits.
|
||||
*/
|
||||
|
||||
shift = 16;
|
||||
}
|
||||
|
||||
/* We know that the first free bit is now within the lower 16
|
||||
* bits of 'curr'. Is it in the upper or lower byte?
|
||||
*/
|
||||
|
||||
else if ((curr & 0x0000ff) == 0x000000ff)
|
||||
{
|
||||
/* Not in the lower 8 bits. The first free bit must be in
|
||||
* the upper 8 bits.
|
||||
*/
|
||||
|
||||
shift = 8;
|
||||
}
|
||||
|
||||
/* We know that the first free bit is now within the lower 4
|
||||
* bits of 'curr'. Is it in the upper or lower nibble?
|
||||
*/
|
||||
|
||||
else if ((curr & 0x00000f) == 0x0000000f)
|
||||
{
|
||||
/* Not in the lower 4 bits. The first free bit must be in
|
||||
* the upper 4 bits.
|
||||
*/
|
||||
|
||||
shift = 4;
|
||||
}
|
||||
|
||||
/* We know that the first free bit is now within the lower 4
|
||||
* bits of 'curr'. Is it in the upper or lower pair?
|
||||
*/
|
||||
|
||||
else if ((curr & 0x000003) == 0x00000003)
|
||||
{
|
||||
/* Not in the lower 2 bits. The first free bit must be in
|
||||
* the upper 2 bits.
|
||||
*/
|
||||
|
||||
shift = 2;
|
||||
}
|
||||
|
||||
/* We know that the first free bit is now within the lower 4
|
||||
* bits of 'curr'. Check if we have the allocation at this
|
||||
* bit position.
|
||||
*/
|
||||
|
||||
else if ((curr & mask) == 0)
|
||||
{
|
||||
/* Yes.. mark these granules allocated */
|
||||
|
||||
gran_mark_allocated(priv, alloc, ngranules);
|
||||
|
||||
/* And return the allocation address */
|
||||
|
||||
gran_leave_critical(priv);
|
||||
return (FAR void *)alloc;
|
||||
}
|
||||
|
||||
/* The free allocation does not start at this position */
|
||||
|
||||
else
|
||||
{
|
||||
shift = 1;
|
||||
}
|
||||
|
||||
/* Set up for the next time through the loop. Perform a 64
|
||||
* bit shift to move to the next gran position and increment
|
||||
* to the next candidate allocation address.
|
||||
*/
|
||||
|
||||
alloc += (shift << priv->log2gran);
|
||||
curr = (curr >> shift) | (next << (32 - shift));
|
||||
next >>= shift;
|
||||
bitidx += shift;
|
||||
}
|
||||
}
|
||||
|
||||
gran_leave_critical(priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
ret = gran_enter_critical(gran);
|
||||
if (ret < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
posi = gran_search(gran, ngran);
|
||||
if (posi >= 0)
|
||||
{
|
||||
gran_set(gran, posi, ngran);
|
||||
}
|
||||
|
||||
gran_leave_critical(gran);
|
||||
if (posi < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retp = gran->heapstart + (posi << gran->log2gran);
|
||||
graninfo("heap=%"PRIxPTR" posi=%d retp=%"PRIxPTR" size=%zu n=%zu\n",
|
||||
gran->heapstart, posi, retp, size, ngran);
|
||||
DEBUGASSERT(retp >= gran->heapstart);
|
||||
DEBUGASSERT(retp < gran->heapstart + GRANBYTE(gran));
|
||||
return (FAR void *)retp;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GRAN */
|
||||
|
|
|
@ -25,11 +25,12 @@
|
|||
#include <nuttx/config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/mm/gran.h>
|
||||
|
||||
#include "mm_gran/mm_gran.h"
|
||||
#include "mm_gran/mm_grantable.h"
|
||||
|
||||
#ifdef CONFIG_GRAN
|
||||
|
||||
|
@ -37,100 +38,35 @@
|
|||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gran_free
|
||||
*
|
||||
* Description:
|
||||
* Return memory to the granule heap.
|
||||
*
|
||||
* Input Parameters:
|
||||
* handle - The handle previously returned by gran_initialize
|
||||
* memory - A pointer to memory previoiusly allocated by gran_alloc.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void gran_free(GRAN_HANDLE handle, FAR void *memory, size_t size)
|
||||
{
|
||||
FAR struct gran_s *priv = (FAR struct gran_s *)handle;
|
||||
unsigned int granno;
|
||||
unsigned int gatidx;
|
||||
unsigned int gatbit;
|
||||
unsigned int granmask;
|
||||
unsigned int ngranules;
|
||||
unsigned int avail;
|
||||
uint32_t gatmask;
|
||||
int ret;
|
||||
FAR gran_t *gran = (FAR gran_t *)handle;
|
||||
uint ngran;
|
||||
size_t posi;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(priv != NULL && memory && size <= 32 * (1 << priv->log2gran));
|
||||
DEBUGASSERT(gran && memory && size);
|
||||
DEBUGASSERT(GRAN_PRODUCT(gran, memory));
|
||||
DEBUGASSERT(GRAN_INRANGE(gran, (((uintptr_t)memory) + size - 1)));
|
||||
|
||||
/* Get exclusive access to the GAT */
|
||||
posi = MEM2GRAN(gran, memory);
|
||||
ngran = NGRANULE(gran, size);
|
||||
|
||||
graninfo(" heap=%"PRIxPTR" posi=%zu addr=%zx size=%zu n=%d\n",
|
||||
gran->heapstart, posi, (size_t)memory, size, ngran);
|
||||
|
||||
do
|
||||
{
|
||||
ret = gran_enter_critical(priv);
|
||||
|
||||
/* The only error Should happen on task cancellation. We must
|
||||
* try again in this case to avoid stranding the granule memory.
|
||||
*/
|
||||
|
||||
ret = gran_enter_critical(gran);
|
||||
DEBUGASSERT(ret == OK || ret == -ECANCELED);
|
||||
}
|
||||
while (ret < 0);
|
||||
while (ret < 0); /* Retry upon task cancellation */
|
||||
|
||||
/* Determine the granule number of the first granule in the allocation */
|
||||
/* check double free */
|
||||
|
||||
granno = ((uintptr_t)memory - priv->heapstart) >> priv->log2gran;
|
||||
|
||||
/* Determine the GAT table index and bit number associated with the
|
||||
* allocation.
|
||||
*/
|
||||
|
||||
gatidx = granno >> 5;
|
||||
gatbit = granno & 31;
|
||||
|
||||
/* Determine the number of granules in the allocation */
|
||||
|
||||
granmask = (1 << priv->log2gran) - 1;
|
||||
ngranules = (size + granmask) >> priv->log2gran;
|
||||
|
||||
/* Clear bits in the GAT entry or entries */
|
||||
|
||||
avail = 32 - gatbit;
|
||||
if (ngranules > avail)
|
||||
{
|
||||
/* Clear bits in the first GAT entry */
|
||||
|
||||
gatmask = (0xffffffff << gatbit);
|
||||
DEBUGASSERT((priv->gat[gatidx] & gatmask) == gatmask);
|
||||
|
||||
priv->gat[gatidx] &= ~gatmask;
|
||||
ngranules -= avail;
|
||||
|
||||
/* Clear bits in the second GAT entry */
|
||||
|
||||
gatmask = 0xffffffff >> (32 - ngranules);
|
||||
DEBUGASSERT((priv->gat[gatidx + 1] & gatmask) == gatmask);
|
||||
|
||||
priv->gat[gatidx + 1] &= ~gatmask;
|
||||
}
|
||||
|
||||
/* Handle the case where where all of the granules came from one entry */
|
||||
|
||||
else
|
||||
{
|
||||
/* Clear bits in a single GAT entry */
|
||||
|
||||
gatmask = 0xffffffff >> (32 - ngranules);
|
||||
gatmask <<= gatbit;
|
||||
DEBUGASSERT((priv->gat[gatidx] & gatmask) == gatmask);
|
||||
|
||||
priv->gat[gatidx] &= ~gatmask;
|
||||
}
|
||||
|
||||
gran_leave_critical(priv);
|
||||
DEBUGASSERT(gran_match(gran, posi, ngran, 1, NULL));
|
||||
gran_clear(gran, posi, ngran);
|
||||
gran_leave_critical(gran);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GRAN */
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
/****************************************************************************
|
||||
* mm/mm_gran/mm_granmark.c
|
||||
*
|
||||
* 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 <nuttx/config.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <nuttx/mm/gran.h>
|
||||
|
||||
#include "mm_gran/mm_gran.h"
|
||||
|
||||
#ifdef CONFIG_GRAN
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gran_mark_allocated
|
||||
*
|
||||
* Description:
|
||||
* Mark a range of granules as allocated.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - The granule heap state structure.
|
||||
* alloc - The address of the allocation.
|
||||
* ngranules - The number of granules allocated
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, a non-NULL pointer to the allocated memory is returned;
|
||||
* NULL is returned on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR void *gran_mark_allocated(FAR struct gran_s *priv, uintptr_t alloc,
|
||||
unsigned int ngranules)
|
||||
{
|
||||
unsigned int granno;
|
||||
unsigned int gatidx;
|
||||
unsigned int gatbit;
|
||||
unsigned int avail;
|
||||
uint32_t gatmask;
|
||||
|
||||
/* Determine the granule number of the allocation */
|
||||
|
||||
granno = (alloc - priv->heapstart) >> priv->log2gran;
|
||||
|
||||
/* Determine the GAT table index associated with the allocation */
|
||||
|
||||
gatidx = granno >> 5;
|
||||
gatbit = granno & 31;
|
||||
|
||||
/* Mark bits in the GAT entry or entries */
|
||||
|
||||
avail = 32 - gatbit;
|
||||
if (ngranules > avail)
|
||||
{
|
||||
uint32_t gatmask2;
|
||||
|
||||
gatmask = 0xffffffff << gatbit;
|
||||
ngranules -= avail;
|
||||
gatmask2 = 0xffffffff >> (32 - ngranules);
|
||||
|
||||
/* Check that the area is free, from both mask words */
|
||||
|
||||
if (((priv->gat[gatidx] & gatmask) != 0) ||
|
||||
((priv->gat[gatidx + 1] & gatmask2) != 0))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Mark bits in the first and second GAT entry */
|
||||
|
||||
priv->gat[gatidx] |= gatmask;
|
||||
priv->gat[gatidx + 1] |= gatmask2;
|
||||
}
|
||||
|
||||
/* Handle the case where where all of the granules come from one entry */
|
||||
|
||||
else
|
||||
{
|
||||
gatmask = 0xffffffff >> (32 - ngranules);
|
||||
gatmask <<= gatbit;
|
||||
|
||||
/* Check that the area is free */
|
||||
|
||||
if ((priv->gat[gatidx] & gatmask) != 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Mark bits in a single GAT entry */
|
||||
|
||||
priv->gat[gatidx] |= gatmask;
|
||||
}
|
||||
|
||||
return (FAR void *)alloc;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GRAN */
|
|
@ -25,10 +25,12 @@
|
|||
#include <nuttx/config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/mm/gran.h>
|
||||
|
||||
#include "mm_gran/mm_gran.h"
|
||||
#include "mm_gran/mm_grantable.h"
|
||||
|
||||
#ifdef CONFIG_GRAN
|
||||
|
||||
|
@ -36,67 +38,58 @@
|
|||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gran_reserve
|
||||
*
|
||||
* Description:
|
||||
* Reserve memory in the granule heap. This will reserve the granules
|
||||
* that contain the start and end addresses plus all of the granules
|
||||
* in between. This should be done early in the initialization sequence
|
||||
* before any other allocations are made.
|
||||
*
|
||||
* Reserved memory can never be allocated (it can be freed however which
|
||||
* essentially unreserves the memory).
|
||||
*
|
||||
* Input Parameters:
|
||||
* handle - The handle previously returned by gran_initialize
|
||||
* start - The address of the beginning of the region to be reserved.
|
||||
* size - The size of the region to be reserved
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, a non-NULL pointer to the allocated memory is returned;
|
||||
* NULL is returned on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR void *gran_reserve(GRAN_HANDLE handle, uintptr_t start, size_t size)
|
||||
{
|
||||
FAR struct gran_s *priv = (FAR struct gran_s *)handle;
|
||||
FAR void *ret = NULL;
|
||||
FAR gran_t *gran = (FAR gran_t *)handle;
|
||||
uintptr_t end;
|
||||
size_t ngran;
|
||||
size_t posi;
|
||||
bool avail;
|
||||
|
||||
DEBUGASSERT(priv != NULL);
|
||||
|
||||
if (size > 0)
|
||||
DEBUGASSERT(gran);
|
||||
if (!size || size > GRANBYTE(gran))
|
||||
{
|
||||
uintptr_t mask = (1 << priv->log2gran) - 1;
|
||||
uintptr_t end = start + size - 1;
|
||||
unsigned int ngranules;
|
||||
|
||||
/* Get the aligned (down) start address and the aligned (up) end
|
||||
* address
|
||||
*/
|
||||
|
||||
start &= ~mask;
|
||||
end = (end + mask) & ~mask;
|
||||
|
||||
/* Calculate the new size in granules */
|
||||
|
||||
ngranules = ((end - start) >> priv->log2gran) + 1;
|
||||
|
||||
/* Must lock the granule allocator */
|
||||
|
||||
if (gran_enter_critical(priv) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* And reserve the granules */
|
||||
|
||||
ret = gran_mark_allocated(priv, start, ngranules);
|
||||
gran_leave_critical(priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
/* align down/up start/ending addresses */
|
||||
|
||||
end = END_RSRV(gran, start, size);
|
||||
if (!GRAN_INRANGE(gran, end))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
start = MEM_RSRV(gran, start);
|
||||
if (!GRAN_INRANGE(gran, start))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* convert unit to granule */
|
||||
|
||||
posi = MEM2GRAN(gran, start);
|
||||
ngran = ((end - start) >> gran->log2gran) + 1;
|
||||
|
||||
/* lock the granule allocator */
|
||||
|
||||
if (gran_enter_critical(gran) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
avail = gran_match(gran, posi, ngran, 0, NULL);
|
||||
if (avail)
|
||||
{
|
||||
gran_set(gran, posi, ngran);
|
||||
}
|
||||
|
||||
gran_leave_critical(gran);
|
||||
|
||||
graninfo("%s posi=%zu retp=%zx size=%zu n=%zu\n",
|
||||
avail ? " done" : " error", posi, (size_t)start, size, ngran);
|
||||
|
||||
return avail ? (FAR void *)start : NULL;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GRAN */
|
||||
|
|
291
mm/mm_gran/mm_grantable.c
Normal file
291
mm/mm_gran/mm_grantable.c
Normal file
|
@ -0,0 +1,291 @@
|
|||
/****************************************************************************
|
||||
* mm/mm_gran/mm_grantable.c
|
||||
*
|
||||
* 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 <nuttx/config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <strings.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/bits.h>
|
||||
#include <nuttx/mm/gran.h>
|
||||
|
||||
#include "mm_gran/mm_gran.h"
|
||||
#include "mm_gran/mm_grantable.h"
|
||||
|
||||
#ifdef CONFIG_GRAN
|
||||
|
||||
/****************************************************************************
|
||||
* Preprocessors
|
||||
****************************************************************************/
|
||||
|
||||
#define GATCFULL 0xffffffffu /* a full GAT cell */
|
||||
#define DEBRUJIN_NUM 0x077CB531UL /* the de Bruijn Sequence */
|
||||
|
||||
/****************************************************************************
|
||||
* Private data
|
||||
****************************************************************************/
|
||||
|
||||
#if !defined(CONFIG_HAVE_BUILTIN_CLZ) || !defined(CONFIG_HAVE_BUILTIN_CTZ)
|
||||
|
||||
/* The de Bruijn lookup table to get n from BIT(n). */
|
||||
|
||||
static const uint8_t DEBRUJIN_LUT[32] =
|
||||
{
|
||||
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
|
||||
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/* return BIT(MSB(n)) */
|
||||
|
||||
uint32_t msb_mask(uint32_t n)
|
||||
{
|
||||
/* see https://www.geeksforgeeks.org/find-significant-set-bit-number */
|
||||
|
||||
DEBUGASSERT(n);
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
n |= n >> 16;
|
||||
|
||||
n = ((n + 1) >> 1) | (n & (1 << ((sizeof(n) << 3)-1)));
|
||||
return n;
|
||||
}
|
||||
|
||||
/* return BIT(LSB(n)) */
|
||||
|
||||
uint32_t lsb_mask(uint32_t n)
|
||||
{
|
||||
DEBUGASSERT(n);
|
||||
return (-n & n) & GATCFULL;
|
||||
}
|
||||
|
||||
/* set or clear a GAT cell with given bit mask */
|
||||
|
||||
static void cell_set(gran_t *gran, uint32_t cell, uint32_t mask, bool val)
|
||||
{
|
||||
if (val)
|
||||
{
|
||||
gran->gat[cell] |= mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
gran->gat[cell] &= ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
/* set or clear a range of GAT bits */
|
||||
|
||||
static void gran_set_(gran_t *gran, gatr_t *rang, bool val)
|
||||
{
|
||||
uint32_t c;
|
||||
|
||||
cell_set(gran, rang->sidx, rang->smask, val);
|
||||
if (rang->sidx != rang->eidx)
|
||||
{
|
||||
cell_set(gran, rang->eidx, rang->emask, val);
|
||||
c = rang->sidx + 1;
|
||||
for (; c < rang->eidx; c++)
|
||||
{
|
||||
cell_set(gran, c, GATCFULL, val);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/* prepare given GAT range instance for later use. */
|
||||
|
||||
int gran_range(const gran_t *gran, size_t posi, size_t size,
|
||||
gatr_t *rang)
|
||||
{
|
||||
if (!gran || gran->ngranules < posi + size)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (rang == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rang->width = GATC_BITS(gran);
|
||||
|
||||
rang->sidx = posi / rang->width;
|
||||
rang->soff = posi % rang->width;
|
||||
|
||||
posi += size - 1;
|
||||
rang->eidx = posi / GATC_BITS(gran);
|
||||
rang->eoff = posi % GATC_BITS(gran);
|
||||
|
||||
rang->smask = ~(BIT(rang->soff) - 1);
|
||||
rang->emask = (BIT(rang->eoff) - 1) | BIT(rang->eoff);
|
||||
|
||||
if (rang->sidx == rang->eidx)
|
||||
{
|
||||
rang->smask &= rang->emask; /* combine the masks */
|
||||
rang->emask = rang->smask;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* checks if a range of granule matches the expected status */
|
||||
|
||||
bool gran_match(const gran_t *gran, size_t posi, size_t size, bool used,
|
||||
size_t *mpos)
|
||||
{
|
||||
uint32_t c; /* cell index */
|
||||
uint32_t v; /* masked cell value */
|
||||
uint32_t e; /* expected cell value */
|
||||
gatr_t r; /* range helper */
|
||||
|
||||
gran_range(gran, posi, size, &r);
|
||||
|
||||
/* check the ending cell */
|
||||
|
||||
c = r.eidx;
|
||||
e = used ? r.emask : 0 ;
|
||||
v = gran->gat[c] & r.emask;
|
||||
if (v != e)
|
||||
{
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (r.sidx == r.eidx)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* check cells in between */
|
||||
|
||||
c = r.eidx - 1;
|
||||
e = used ? GATCFULL : 0;
|
||||
for (; c > r.sidx; c--)
|
||||
{
|
||||
v = gran->gat[c];
|
||||
if (v != e)
|
||||
{
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
|
||||
/* check the starting cell */
|
||||
|
||||
c = r.sidx;
|
||||
e = used ? r.smask : 0 ;
|
||||
v = gran->gat[c] & r.smask;
|
||||
if (v != e)
|
||||
{
|
||||
goto failure;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
failure:
|
||||
|
||||
if (mpos && !used)
|
||||
{
|
||||
/* offset of last used when matching for free */
|
||||
|
||||
DEBUGASSERT(v);
|
||||
#ifdef CONFIG_HAVE_BUILTIN_CLZ
|
||||
*mpos = 31 - __builtin_clz(v);
|
||||
#else
|
||||
*mpos = (uint32_t)((msb_mask(v)) * DEBRUJIN_NUM) >> 27;
|
||||
DEBUGASSERT(*mpos < sizeof(DEBRUJIN_LUT));
|
||||
*mpos = DEBRUJIN_LUT[*mpos];
|
||||
#endif
|
||||
*mpos += c * GATC_BITS(gran);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* returns granule number of free range or negative error */
|
||||
|
||||
int gran_search(const gran_t *gran, size_t size)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (gran == NULL || gran->ngranules < size)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = -ENOMEM;
|
||||
for (size_t i = 0; i <= gran->ngranules - size; i++)
|
||||
{
|
||||
if (gran_match(gran, i, size, 0, &i))
|
||||
{
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set a range of granules */
|
||||
|
||||
int gran_set(gran_t *gran, size_t posi, size_t size)
|
||||
{
|
||||
gatr_t rang;
|
||||
int ret = gran_range(gran, posi, size, &rang);
|
||||
|
||||
if (ret == OK)
|
||||
{
|
||||
gran_set_(gran, &rang, true);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* clear a range of granules */
|
||||
|
||||
int gran_clear(gran_t *gran, size_t posi, size_t size)
|
||||
{
|
||||
gatr_t rang;
|
||||
int ret = gran_range(gran, posi, size, &rang);
|
||||
|
||||
if (ret == OK)
|
||||
{
|
||||
gran_set_(gran, &rang, false);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GRAN */
|
159
mm/mm_gran/mm_grantable.h
Normal file
159
mm/mm_gran/mm_grantable.h
Normal file
|
@ -0,0 +1,159 @@
|
|||
/****************************************************************************
|
||||
* mm/mm_gran/mm_grantable.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __MM_MM_GRAN_MM_GRANTABLE_H
|
||||
#define __MM_MM_GRAN_MM_GRANTABLE_H
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Granule arithmetics */
|
||||
|
||||
#define GRANSIZE(g) (1 << g->log2gran)
|
||||
#define GRANMASK(g) (GRANSIZE(g) - 1)
|
||||
#define NGRANULE(g, s) ((s + GRANMASK(g)) >> g->log2gran)
|
||||
|
||||
#define GRANBYTE(g) ((size_t)g->ngranules << g->log2gran)
|
||||
#define GRANENDA(g) (GRANBYTE(g) + g->heapstart)
|
||||
#define MEM2GRAN(g, m) ((((uintptr_t)m) - g->heapstart) >> g->log2gran)
|
||||
#define GRAN2MEM(g, x) ((((uintptr_t)x) << g->log2gran) + g->heapstart)
|
||||
|
||||
#define GRAN_ALIGNED(g, m) ((((uintptr_t)(m)) & GRANMASK(g)) == 0)
|
||||
#define GRAN_INRANGE(g, m) (g->heapstart <= (uintptr_t)(m) && \
|
||||
(uintptr_t)(m) < GRANENDA(g))
|
||||
#define GRAN_PRODUCT(g, m) (GRAN_ALIGNED(g, m) && GRAN_INRANGE(g, m))
|
||||
|
||||
#define ALIGNDN(g, m) (((size_t)m) & ~GRANMASK(g))
|
||||
#define ALIGNUP(g, m) ((((size_t)m) + GRANMASK(g)) & ~GRANMASK(g))
|
||||
|
||||
/* gran_reserve related */
|
||||
|
||||
#define MEM_RSRV(g, m) ALIGNDN(g, m)
|
||||
#define END_RSRV(g, m, s) ALIGNUP(g, (((size_t)m) + s - 1))
|
||||
#define NUM_RSRV(g, m, s) (((END_RSRV(g, m, s) - MEM_RSRV(g, m)) \
|
||||
>> g->log2gran) + 1)
|
||||
#define LEN_RSRV(g, m, s) ((size_t)(NUM_RSRV(g, m, s) << g->log2gran))
|
||||
|
||||
/* GAT table related */
|
||||
|
||||
#define GATC_BITS(g) (sizeof(g->gat[0]) << 3)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* Structure for a range of granules in GAT */
|
||||
|
||||
struct gran_range_s
|
||||
{
|
||||
uint16_t sidx; /* index of the starting GAT cell */
|
||||
uint16_t eidx; /* index of the ending GAT cell */
|
||||
uint8_t soff; /* offset of bit in starting cell */
|
||||
uint8_t eoff; /* offset of bit in ending cell */
|
||||
uint16_t width; /* width of cell in bits */
|
||||
uint32_t smask; /* mask of the starting GAT cell */
|
||||
uint32_t emask; /* mask of the ending GAT cell */
|
||||
};
|
||||
|
||||
typedef struct gran_range_s gatr_t;
|
||||
typedef struct gran_s gran_t;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gran_range
|
||||
*
|
||||
* Description:
|
||||
* populate a gran_range_s instance for later use
|
||||
*
|
||||
* Input Parameters:
|
||||
* gran - Pointer to the gran state
|
||||
* posi - Position of starting granule
|
||||
* size - Length of range
|
||||
*
|
||||
* Output Parameters:
|
||||
* rang - The range instance to be prepared
|
||||
*
|
||||
* Return value:
|
||||
* OK or negative errno
|
||||
****************************************************************************/
|
||||
|
||||
int gran_range(const gran_t *gran, size_t posi, size_t size, gatr_t *rang);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gran_match
|
||||
*
|
||||
* Description:
|
||||
* check if a continuous range of granules all have expected status
|
||||
*
|
||||
* Input Parameters:
|
||||
* gran - Pointer to the gran state
|
||||
* posi - Position of starting granule
|
||||
* size - Length of range
|
||||
* used - Expected state, true for used, false for empty.
|
||||
*
|
||||
* Output Parameters:
|
||||
* mism - Optional last failed position upon free range matching.
|
||||
*
|
||||
* Return value:
|
||||
* true for match, false otherwise.
|
||||
****************************************************************************/
|
||||
|
||||
bool gran_match(const gran_t *gran, size_t posi, size_t size, bool used,
|
||||
size_t *mism);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gran_search
|
||||
*
|
||||
* Description:
|
||||
* search for continuous range of free granules
|
||||
*
|
||||
* Input Parameters:
|
||||
* gran - Pointer to the gran state
|
||||
* size - Length of range
|
||||
*
|
||||
* Return value:
|
||||
* position of negative error number.
|
||||
****************************************************************************/
|
||||
|
||||
int gran_search(const gran_t *gran, size_t size);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: gran_set, gran_clear
|
||||
*
|
||||
* Description:
|
||||
* Set or clear a range of granule in the GAT
|
||||
*
|
||||
* Input Parameters:
|
||||
* gran - Pointer to the gran state
|
||||
* posi - Range starting bit index
|
||||
* size - Range size
|
||||
*
|
||||
* Return value:
|
||||
* OK on success or negative value on error
|
||||
****************************************************************************/
|
||||
|
||||
int gran_set(gran_t *gran, size_t posi, size_t size);
|
||||
int gran_clear(gran_t *gran, size_t posi, size_t size);
|
||||
|
||||
#endif /* __MM_MM_GRAN_MM_GRANTABLE_H */
|
Loading…
Reference in a new issue