1
0
Fork 0
forked from len0rd/rockbox
foxbox/firmware/test/memory/memory-page.c
Alan Korr c25510f944 Now memory-page and memory-misc compile fine (others are in stage-development)
Conventions :
* Public headers :
    memory.h,config.h,defines.h,inlines.h,types.h,functions.h

* Private headers :
    memory-page.h,memory-slab.h (here you can find
    prototypes functions or structures we want to share
    only between memory-page.c, memory-slab.c,
    memory-block.c, memory-misc.c).

* Public or private codes in :
    memory-page.c,memory-slab.c,memory-block.c,memory-misc.c


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@126 a1c6a512-1295-4272-9138-f99709370657
2002-04-17 15:00:28 +00:00

408 lines
12 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Alan Korr
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <memory.h>
#include "memory-page.h"
#if 0
#include "memory-slab.h"
#endif
#ifdef TEST
// IA32 has no problem with shift operation
static inline unsigned int __memory_get_size (int order)
{
return (MEMORY_PAGE_MINIMAL_SIZE << order);
}
// Arghhhh ! I cannot align 'free_page' on 512-byte boundary (max is 16-byte for Cygwin)
static inline struct memory_free_page *__memory_get_neighbour (struct memory_free_page *node,unsigned int size)
{
return ((struct memory_free_page *)((unsigned)__memory_free_page + (((unsigned)node - (unsigned)__memory_free_page) ^ size)));
}
#else
// SH1 has very poor shift instructions (only <<1,>>1,<<2,>>2,<<8,>>8,<<16 and >>16).
// so we should use a lookup table to speedup.
static inline unsigned int __memory_get_size (int order)
{
static unsigned short size [MEMORY_TOTAL_ORDERS] =
{
1<<MEMORY_PAGE_MINIMAL_ORDER,
2<<MEMORY_PAGE_MINIMAL_ORDER,
4<<MEMORY_PAGE_MINIMAL_ORDER,
8<<MEMORY_PAGE_MINIMAL_ORDER,
16<<MEMORY_PAGE_MINIMAL_ORDER,
32<<MEMORY_PAGE_MINIMAL_ORDER,
64<<MEMORY_PAGE_MINIMAL_ORDER,
128<<MEMORY_PAGE_MINIMAL_ORDER,
256<<MEMORY_PAGE_MINIMAL_ORDER,
512<<MEMORY_PAGE_MINIMAL_ORDER,
1024<<MEMORY_PAGE_MINIMAL_ORDER,
2048<<MEMORY_PAGE_MINIMAL_ORDER,
4096<<MEMORY_PAGE_MINIMAL_ORDER
};
return size[order];
}
static inline struct memory_free_page *__memory_get_neighbour (struct memory_free_page *node,unsigned int size)
{
return ((struct memory_free_page *)((unsigned)node ^ size));
}
#endif
static inline int __memory_get_order (struct memory_free_page *node)
{
return __memory_free_page_order[node - __memory_free_page];
}
static inline void __memory_set_order (struct memory_free_page *node,int order)
{
__memory_free_page_order[node - __memory_free_page] = order;
}
#if MEMORY_PAGE_USE_SPLAY_TREE
static struct memory_free_page *__memory_splay_page (struct memory_free_page *root,struct memory_free_page *node)
{
struct memory_free_page *down;
struct memory_free_page *less;
struct memory_free_page *more;
struct memory_free_page head;
head.less =
head.more = 0;
less =
more = &head;
while (1)
{
if (node < root)
{
if ((down = root->less))
{
if (node < down)
{
root->less = down->more;
down->more = root;
root = down;
if (!root->less)
break;
}
more->less = root;
more = root;
root = root->less;
continue;
}
break;
}
if (root < node)
{
if ((down = root->more))
{
if (root < node)
{
root->more = down->less;
down->less = root;
root = down;
if (!root->more)
break;
}
less->more = root;
less = root;
root = root->more;
continue;
}
}
break;
}
less->more = root->less;
more->less = root->more;
root->less = head.more;
root->more = head.less;
return root;
}
static inline void __memory_insert_page (int order,struct memory_free_page *node)
{
struct memory_free_page *root = __memory_free_page_bin[order];
if (!root)
{
node->less =
node->more = 0;
}
else if (node < (root = __memory_splay_page (root,node)))
{
node->less = root->less;
node->more = root;
root->less = 0;
}
else if (node > root)
{
node->less = root;
node->more = root->more;
node->more = 0;
}
__memory_free_page_bin[order] = node;
__memory_set_order (node,order);
return;
}
static inline struct memory_free_page *__memory_pop_page (int order,int want)
{
struct memory_free_page *root = __memory_free_page_bin[order];
if (root)
{
root = __memory_splay_page (root,__memory_free_page);
__memory_free_page_bin[order] = root->more;
__memory_set_order (root,~want);
}
return root;
}
static inline void __memory_remove_page (int order,struct memory_free_page *node)
{
struct memory_free_page *root = __memory_free_page_bin[order];
root = __memory_splay_page (root,node);
if (root->less)
{
node = __memory_splay_page (root->less,node);
node->more = root->more;
}
else
node = root->more;
__memory_free_page_bin[order] = node;
}
#else
static inline void __memory_insert_page (int order,struct memory_free_page *node)
{
struct memory_free_page *head = __memory_free_page_bin[order];
node->less = 0;
node->more = head;
if (head)
head->less = node;
__memory_free_page_bin[order] = node;
__memory_set_order (node,order);
}
static inline struct memory_free_page *pop_page (int order,int want)
{
struct memory_free_page *node = __memory_free_page_bin[order];
if (node)
{
__memory_free_page_bin[order] = node->more;
if (node->more)
node->more->less = 0;
__memory_set_order (node,~want);
}
return node;
}
static inline void __memory_remove_page (int order,struct memory_free_page *node)
{
if (node->less)
node->less->more = node->more;
else
__memory_free_page_bin[order] = node->more;
if (node->more)
node->more->less = node->less;
}
#endif
static inline void __memory_push_page (int order,struct memory_free_page *node)
{
node->less = 0;
node->more = 0;
__memory_free_page_bin[order] = node;
__memory_set_order (node,order);
}
static struct memory_free_page *__memory_allocate_page (unsigned int size,int order)
{
struct memory_free_page *node;
int min = order;
while ((unsigned)order <= (MEMORY_TOTAL_ORDERS - 1))
// order is valid ?
{
if (!(node = __memory_pop_page (order,min)))
// no free page of this order ?
{
++order; size <<= 1;
continue;
}
while (order > min)
// split our larger page in smaller pages
{
--order; size >>= 1;
__memory_push_page (order,(struct memory_free_page *)((unsigned int)node + size));
}
return node;
}
return MEMORY_RETURN_FAILURE;
}
static inline void __memory_release_page (struct memory_free_page *node,unsigned int size,int order)
{
struct memory_free_page *neighbour;
while ((order <= (MEMORY_TOTAL_ORDERS - 1)) &&
((neighbour = __memory_get_neighbour (node,size)),
(__memory_get_order (neighbour) == order)))
// merge our released page with its contiguous page into a larger page
{
__memory_remove_page (order,neighbour);
++order; size <<= 1;
if (neighbour < node)
node = neighbour;
}
__memory_insert_page (order,node);
}
/*****************************************************************************/
/* PUBLIC FUNCTIONS */
/*****************************************************************************/
void *memory_allocate_page (int order)
{
if (order < 0)
return MEMORY_RETURN_FAILURE;
return __memory_allocate_page (__memory_get_size (order),order);
}
// release a page :
// when called, 'address' MUST be a valid address pointing
// to &dram[i], where i ranges from 0 to MEMORY_TOTAL_PAGES - 1.
// FAILURE if block is already freed.
int memory_release_page (void *address)
{
struct memory_free_page *node = (struct memory_free_page *)address;
int order = ~__memory_get_order (node);
if (order < 0)
return MEMORY_RETURN_FAILURE;
__memory_release_page (node,__memory_get_size (order),order);
return MEMORY_RETURN_SUCCESS;
}
#ifdef TEST
# include <stdio.h>
# include <stdlib.h>
# if MEMORY_PAGE_USE_SPLAY_TREE
void __memory_dump_splay_node (struct memory_free_page *node,int level)
{
if (!node)
return;
__memory_dump_splay_node (node->less,level+1);
printf ("\n%*s[%d-%d]",level,"",(node - __memory_free_page),(node - __memory_free_page) + (1 << __memory_get_order (node)) - 1);
__memory_dump_splay_node (node->more,level+1);
}
void __memory_dump_splay_tree (struct memory_free_page *root)
{
__memory_dump_splay_node (root,2); fflush (stdout);
}
# endif
void __memory_spy_page (void *address)
{
struct memory_free_page *node = (struct memory_free_page *)address;
int order,used;
if (node)
{
order = __memory_get_order (node);
used = order < 0;
if (used)
order = ~order;
printf("\n(%s,%2d,%7d)",(used ? "used" : "free"),order,__memory_get_size (order));
}
}
void __memory_dump (int order)
{
struct memory_free_page *node = __memory_free_page_bin[order];
printf("\n(%s,%2d,%7d)",node ? "free" : "none",order,__memory_get_size (order));
# if MEMORY_PAGE_USE_SPLAY_TREE
__memory_dump_splay_tree (node);
# else
while (node)
{
printf("[%d-%d]",(node - __memory_free_page),(node - __memory_free_page) + (1<<order) - 1);
node = node->more;
}
# endif
}
void __memory_check (int order)
{
struct memory_free_page *node[4096],*swap;
unsigned int i = 0,j = 0;
while (i <= 12)
__memory_dump (i++);
i = 0;
printf ("\nallocating...\n");
while (order >= 0)
{
j = order;
while ((swap = memory_allocate_page (j)))
{
node[i++] = swap;
printf("[%d-%d]",(swap - __memory_free_page),(swap - __memory_free_page) + ((1 << j)-1));
for (j += (rand () & 15); j > (unsigned int)order; j -= order);
}
--order;
}
node[i] = 0;
while (j <= 12)
__memory_dump (j++);
j = 0;
printf ("\nreleasing...");
--i;
while (i > 0)
{
unsigned int k = 0;
# if 0
printf ("\n");
# endif
swap = node[k++];
# if 0
while (swap)
{
printf("[%d-%d]",(swap - __memory_free_page),(swap - __memory_free_page) + ((1 << ~__memory_get_order (swap))-1));
swap = node[k++];
}
# endif
for (j += 1 + (rand () & 15); j >= i; j -= i);
swap = node[j];
node[j] = node[i];
memory_release_page (swap);
node[i] = 0;
--i;
}
memory_release_page (node[0]);
i = 0;
while (i <= 12)
__memory_dump (i++);
printf("\n\n%s !",(__memory_get_order (__memory_free_page) == 12) ? "SUCCESS" : "FAILURE");
}
#endif