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:
Yanfeng Liu 2024-04-08 14:48:17 +08:00 committed by Alan Carvalho de Assis
parent db7c8be61f
commit 102a62c7e3
9 changed files with 560 additions and 475 deletions

View file

@ -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

View file

@ -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

View file

@ -47,7 +47,7 @@
/* Debug */
#ifdef CONFIG_DEBUG_GRAM
#ifdef CONFIG_DEBUG_GRAN
# define granerr _err
# define granwarn _warn
# define graninfo _info

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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
View 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
View 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 */