HI ,all

I am working on a research project relate to rtlinux . I write a simple
buddy memory allocator,and it works very well under rtlinux-2.0. I alloc a
big junk of memory , and use
buddy algorithm to alloc/free it when need. It is really simple and maybe
stupid,
but it fullfill my need.
Now I want to port it to rtlinux-2.2, but it cause system crash.

Below is my poor code .
Anybody can point out the where the problems are? Thanks.



#include <linux/module.h>
#include <asm/smplock.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <rtl_sync.h>

#ifdef __DEBUG
  static unsigned long alloc_addr[100]; /* hope it enough */
  static unsigned long alloc_map[100]; /* 32*MIN_UNIT */
  static int alloc_size[100];
  static int alloc_i[100];
  static int pointer;
  static int count;
#endif

#define RTL_BUDDY_POOL_ORDER 5 /*32 pages pool, hope it enough*/
#define BUDDY_UNIT_MIN  4
#define BUDDY_UNIT_MAX  10 /*Can alloc 16 - 1K byte, is it ok?*/
#define BUDDY_ORDER  (BUDDY_UNIT_MAX - BUDDY_UNIT_MIN + 1)

/*for the buddy system*/
void * rtl_buddy_pool = NULL;
void * rtl_buddy_map  = NULL;
unsigned long buddy_header[BUDDY_ORDER];
int buddy_map_size;
spinlock_t rtl_buddy_lock = SPIN_LOCK_UNLOCKED;


/*
 * a simple version buddy system, _no_ priority(need it?)
 */
#define BUDDY_NEXT(x) (*((unsigned long *) (x)))
#define BUDDY_PREV(x) (*((unsigned long *) (x) + 1))

#define         delete(x) \
        do {\
  BUDDY_NEXT( BUDDY_PREV(x) ) = BUDDY_NEXT(x);\
  if( BUDDY_NEXT(x) != 0 )\
  BUDDY_PREV( BUDDY_NEXT(x) ) = BUDDY_PREV(x);\
        } while(0)

#define insert( head , addr)\
 do { \
  BUDDY_NEXT( addr ) = BUDDY_NEXT( head );\
  BUDDY_PREV( addr ) = head; \
  if( BUDDY_NEXT(addr) != 0 )  \
   BUDDY_PREV( BUDDY_NEXT( addr ) ) = addr;\
  BUDDY_NEXT( head ) = addr;\
 } while (0)

#define clear_str( st_addr, idx, size) \
 do { int i ;\
  for ( i = 0; i < size ; i ++)\
     clear_bit( idx + i , st_addr); \
 } while (0)

#define set_str( st_addr, idx, size) \
 do {\
  int i;\
  for ( i = 0; i < size ; i ++) \
   set_bit( idx + i , st_addr);\
 } while (0)

int test_empty(unsigned long st_addr, unsigned long idx, unsigned long size)
{
 int i;

 for( i = 0; i < size ; i ++)
  if ( test_bit(idx + i, ( void * ) st_addr)) {
   return 0;
  }
 return 1;
}

int test_full(unsigned long st_addr, unsigned long idx, unsigned long size)
{
 int i;

 for( i = 0; i < size ; i ++)
  if ( !test_bit(idx + i, ( void * ) st_addr)) {
   return 0;
  }
 return 1;
}

#define TEMP_DEBUG 1
#ifdef __DEBUG
unsigned long get_map(unsigned long addr)
{

  unsigned long ret;
  int i;
  int map_index = (addr - (unsigned long )rtl_buddy_pool) >> BUDDY_UNIT_MIN
;

  for ( i = 0 ; i < sizeof(unsigned long)*8 ; i ++ )
 if (test_bit(map_index + i, rtl_buddy_map) )
  set_bit(i, &ret);
  return ret ;
}

void output_map(void)
{ 
  int i = 0;

  while( alloc_addr[i] != 0 ) {
 rtl_printf("address %x, map %x, size %x, i %d", alloc_addr[i],\
   alloc_map[i],alloc_size[i], alloc_i[i]);
 i ++;
  }
  rtl_printf("\ntotal %d alloc , %d free",i, count);
}
#endif

unsigned long rtl_kmalloc(int size)
{
  int index , cur_index, i, result = 1;
  unsigned long area, intr_flag;
  int map_index;
  
  
  /* Sanity check first*/
  if ( size <= 0 ) return 0;

  for ( i = BUDDY_UNIT_MIN; i <= BUDDY_UNIT_MAX; i ++ ) 
 if ( (result = (size >> i)) == 0) { size = (1 << i); break; }
  if ( result != 0 ) { rtl_error("size mismatch\n"); return 0;}
  cur_index = index = i - BUDDY_UNIT_MIN;
  
  rtl_spin_lock_irqsave(&rtl_buddy_lock, intr_flag); 

  while ( buddy_header[index] == 0 && index < BUDDY_ORDER) 
 index ++;
  if ( index == BUDDY_ORDER) 
 { rtl_error("kmalloc out of memory\n"); goto error_out; }
  
  area = buddy_header[index];
  delete(area); 

  while ( index > cur_index ) {
 insert( (unsigned long)&buddy_header[ index - 1 ], area);
 area += 1 << ( ( -- index ) + BUDDY_UNIT_MIN);

  }

  map_index = (area - (unsigned long )rtl_buddy_pool) >> BUDDY_UNIT_MIN ;
  set_str(rtl_buddy_map, map_index, 1 << index);
  #ifdef __DEBUG
  rtl_printf(test_full( (unsigned long )rtl_buddy_map, map_index, 1 <<
index)?"full":"not full");
  #endif
  rtl_spin_unlock_irqrestore(&rtl_buddy_lock, intr_flag);

  #ifdef __DEBUG
  alloc_addr[pointer] = area;
  alloc_size[pointer] = size;
  alloc_map[pointer] = get_map(area);
  alloc_i[pointer] = i;
  pointer ++;
  #endif

  return area;

error_out:
  rtl_spin_unlock_irqrestore(&rtl_buddy_lock, intr_flag);

  return 0;
}

int rtl_kfree( void * ptr, int size)
{
  unsigned long addr = (unsigned long ) ptr;
  int result, order, map_index, i;
  unsigned long buddy, intr_flag;
#ifdef __DEBUG
  count ++;
#endif

  if ( size <= 0 || addr == 0 ) return -1;

  for( i = BUDDY_UNIT_MIN; i <= BUDDY_UNIT_MAX; i ++ )
 if ( (result = (size >> i)) == 0) { size = 1 << i; break;}
  if ( result != 0 ) { rtl_error("size mismatch\n"); return -1;}

  if( (addr & (~((~0) << i) ) ) != 0)
 { rtl_printf("buggy address %x ", addr); return -1;}

  order = i - BUDDY_UNIT_MIN;

  map_index = (addr - (unsigned long )rtl_buddy_pool) >> BUDDY_UNIT_MIN ;

  #ifdef __DEBUG
  rtl_printf("about to clear str index %d, order%d\n", map_index, order);
  if (!test_full((unsigned long)rtl_buddy_map, map_index, 1 << order ))
 rtl_printf("!!!!Bit map error! addr =%x 1<<order = %d\n",addr,1<< order);
  #endif

  rtl_spin_lock_irqsave(&rtl_buddy_lock, intr_flag);
  clear_str( rtl_buddy_map , map_index, 1 << order );
  while( i < BUDDY_UNIT_MAX )

 buddy = addr ^ ( 1 << i );

 map_index = (buddy - (unsigned long)rtl_buddy_pool) >> BUDDY_UNIT_MIN;
 if (! test_empty((unsigned long)rtl_buddy_map, map_index, 1 << order ))
  break;
  #ifdef __DEBUG
  rtl_printf(test_empty((unsigned long)rtl_buddy_map, map_index, 1 <<
(order) )?"empty":"!empty");
  rtl_printf("buddy is %x prev %x, next %x\n", buddy, BUDDY_PREV(buddy),
BUDDY_NEXT(buddy));
  #endif
 delete(buddy);
 order ++; i ++;
 addr &= (~0) << i;
  #ifdef __DEBUG
  rtl_printf("merge to %d\n", i);
  #endif
  }

  insert( (unsigned long)&buddy_header[order], addr );

  rtl_spin_unlock_irqrestore(&rtl_buddy_lock, intr_flag);
  return 0;
}


#if TEMP_DEBUG

void output_buddy( void )
{
   int i , header ;

   for ( i = 0; i < BUDDY_ORDER; i ++) {
 int t = 0;

 header = buddy_header[i] ;
 rtl_printf("order  %d", i + BUDDY_UNIT_MIN );
 while ( header != 0) {
  t ++;
  rtl_printf( " %x", header);
  header = BUDDY_NEXT(header);
 }
 rtl_printf("\ntotal: %d\n", t);
   }
/*
   for ( i = 0; i < BUDDY_ORDER; i ++) {
 int t = 0;

 header = buddy_header[i] ;
 printk("order  %x", i + BUDDY_UNIT_MIN );
 while ( header != 0) {
  t ++;
  printk( " %x", header);
  printk( " next %x", BUDDY_NEXT(header) );
  printk( " prev %x", BUDDY_PREV(header) );
  header = BUDDY_NEXT(header);
 }
 printk("\ntotal: %d\n", t);
   }
*/
}
#endif
void test_mf(void)
{
  unsigned long addr1, addr2;

  addr1 = rtl_kmalloc(500);
  addr2 = rtl_kmalloc(10);
  rtl_kfree(addr1, 500);
  rtl_kfree(addr2, 10);
  addr1 = rtl_kmalloc(500);
  addr2 = rtl_kmalloc(10);
  rtl_kfree(addr1, 500);
  rtl_kfree(addr2, 10);
  addr1 = rtl_kmalloc(500);
  addr2 = rtl_kmalloc(10);
  rtl_kfree(addr1, 500);
  rtl_kfree(addr2, 10);
  addr1 = rtl_kmalloc(500);
  addr2 = rtl_kmalloc(10);
  rtl_kfree(addr1, 500);
  rtl_kfree(addr2, 10);
  addr1 = rtl_kmalloc(500);
  addr2 = rtl_kmalloc(10);
  rtl_kfree(addr1, 500);
  rtl_kfree(addr2, 10);
  addr1 = rtl_kmalloc(500);
  addr2 = rtl_kmalloc(10);
  rtl_kfree(addr1, 500);
  rtl_kfree(addr2, 10);
  output_buddy();
  output_map();

}

int init_module(void)
{
  int i;
  unsigned long addr;

  rtl_buddy_pool =(void *) __get_free_pages(GFP_KERNEL|GFP_DMA,
RTL_BUDDY_POOL_ORDER);

  rtl_buddy_start_addr = ( unsigned long )rtl_buddy_pool;
  rtl_buddy_end_addr = rtl_buddy_start_addr + \
 (1 << ( RTL_BUDDY_POOL_ORDER + PAGE_SHIFT ));

  if ( rtl_buddy_pool == NULL) {
 rtl_error("buddy memory allocate failed \n");
 goto alloc_fail_out;
  }

  memset(rtl_buddy_pool, 0 , PAGE_SIZE << RTL_BUDDY_POOL_ORDER);
  rtl_printf("buddy pool %p\n",rtl_buddy_pool);

  buddy_map_size = (PAGE_SIZE << RTL_BUDDY_POOL_ORDER) >> BUDDY_UNIT_MIN;
  buddy_map_size = (buddy_map_size + 7)/ 8;
  buddy_map_size = ((buddy_map_size + 3)/4) * 4; /*4 byte aligned*/

  rtl_printf("the result of map size now is %d",buddy_map_size);
  rtl_buddy_map = kmalloc(buddy_map_size, GFP_KERNEL);

  if (rtl_buddy_map == NULL) {
 rtl_error("buddy map allocate fail");
 goto map_fail_out;
  }

  rtl_printf("map pointer %p",rtl_buddy_map);
  memset(rtl_buddy_map, 0 , buddy_map_size); /*all free now*/

  addr = (unsigned long)rtl_buddy_pool;

  for( i = 0 ; i < BUDDY_ORDER - 1; i ++)
 buddy_header[i] = 0;

 /* chain all of them on the link of biggest chunk*/
  while((void *)addr < rtl_buddy_pool + \
 (PAGE_SIZE << RTL_BUDDY_POOL_ORDER) ) {
 insert( (unsigned long) &buddy_header[BUDDY_ORDER - 1], addr);
 addr += 1 << BUDDY_UNIT_MAX;
  }

  test_mf();
  return 0;

map_fail_out :
  free_pages( (int) rtl_buddy_pool, RTL_BUDDY_POOL_ORDER);

alloc_fail_out:
  return 0;
}


void cleanup_module( void )
{

   if ( rtl_buddy_map != NULL)
 kfree( rtl_buddy_map );
   if ( rtl_buddy_pool != NULL )
 free_pages( (int) rtl_buddy_pool, RTL_BUDDY_POOL_ORDER);
}



-- [rtl] ---
To unsubscribe:
echo "unsubscribe rtl" | mail [EMAIL PROTECTED] OR
echo "unsubscribe rtl <Your_email>" | mail [EMAIL PROTECTED]
---
For more information on Real-Time Linux see:
http://www.rtlinux.org/rtlinux/

Reply via email to