Re: [uClinux-dev] RE: [UCLINUX] Old kernel, old argument, new (maybe) point(s)

From: David Beckemeyer (david@corp.earthlink.net)
Date: Thu Jul 20 2000 - 13:06:18 EDT


Nice list.  You list multihread as (2).  Does that mean you believe
it's on the easier side?  That would be better than fork() IMHO for
my purposes.


On Thu, Jul 20, 2000 at 05:37:58PM +0200, Vadim Lebedev wrote:
> 1) implement a trivial malloc/free/realloc in libc which does not make mmap
> for each allocation, because mmap allocate stuff in PAGEs so you make
> malloc(12) and you get 1K allocated, very vasteful

I implemented the following hack the other afternoon to solve the
mekory leak problem I mentioned in a separate message.  Perhaps 
this is something like what you describe, but either way I'd like
peer review since I'm now using this in my libc (so far so good and
it did resolve the memory leak for my case).

----------------------------------------------------------------
#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>


struct memblk
  {
    int mb_magic;
    struct memblk *mb_next;
    struct memblk *mb_prev;
    size_t mb_len;
    struct poolblk *mb_pool;
  };


struct poolblk
  {
    struct poolblk *pb_next;
    struct memblk *pb_freelist;
  };

static struct poolblk *poollist;

#define POOLSIZE 8*1024

#define MEM_MAGIC_FREE 0x46524545
#define MEM_MAGIC_USED 0x55534544

static void *
  real_malloc (size_t len)
{
  void *result = mmap ((void *) 0, len, PROT_READ | PROT_WRITE,
		       MAP_SHARED | MAP_ANONYMOUS, 0, 0);
  if (result == (void *) -1)
    return 0;

  return result;


}

/* unlink from the freelist */
static 
  mb_unlink (struct memblk *mb)
{
  if (mb->mb_prev)
    mb->mb_prev->mb_next = mb->mb_next;
  else
    mb->mb_pool->pb_freelist = mb->mb_next;
  if (mb->mb_next)
    mb->mb_next->mb_prev = mb->mb_prev;
  mb->mb_magic = MEM_MAGIC_USED;
}

/* relink onto the end of the freelist */
static 
  mb_link (struct memblk *mb)
{
  struct memblk *lastmb;

  lastmb = mb->mb_pool->pb_freelist;
  if (lastmb)
    {
      while (lastmb->mb_next)
	lastmb = lastmb->mb_next;
      lastmb->mb_next = mb;
    }
  else
    {
      mb->mb_pool->pb_freelist = mb;
    }
  mb->mb_prev = lastmb;
  mb->mb_next = 0;
  mb->mb_magic = MEM_MAGIC_FREE;
}


static char *
  alloc_memblk (struct memblk *mb, size_t len)
{
  size_t newlen;
  struct memblk *newmb;

  newlen = mb->mb_len - len;
  if (newlen > 1023)
    {
      newmb = (struct memblk *) ((char *) mb + len);

      /* re-link the freelist */
      *newmb = *mb;
      if (mb->mb_prev)
	mb->mb_prev->mb_next = newmb;
      else
	mb->mb_pool->pb_freelist = newmb;
      if (mb->mb_next)
	mb->mb_next->mb_prev = newmb;
      newmb->mb_len = newlen;
      mb->mb_len = len;
    }
  else
    {
      mb_unlink (mb);
    }
  mb->mb_prev = mb->mb_next = 0;
  return ((char *) ++mb);
}

#ifdef MEMORY_DEBUG
show_pools ()
{
  struct poolblk *pb;
  struct memblk *mb;

  printf ("====\n");
  for (pb = poollist; pb; pb = pb->pb_next)
    {
      printf ("Pool %x\n", pb);
      for (mb = pb->pb_freelist; mb; mb = mb->mb_next)
	{
	  printf ("  Block: at %x %d bytes\n", mb, mb->mb_len);
	}
    }
  printf ("~~~~\n");
}
#endif

static struct memblk *
  m_search_pool (size_t len)
{
  struct poolblk *pb;
  struct memblk *mb;

  for (pb = poollist; pb; pb = pb->pb_next)
    {
      for (mb = pb->pb_freelist; mb; mb = mb->mb_next)
	if (mb->mb_len >= len)
	  {
#ifdef MEMORY_DEBUG
	    printf ("found free segment at %x\n", mb);
#endif
	    return (mb);
	  }
    }
  return ((struct memblk *) 0);
}

static 
  defrag_heap ()
{
  struct poolblk *pb;
  struct memblk *mb, *mb2, *mbend;

#ifdef MEMORY_DEBUG
  printf ("Before defrag: ");
  show_pools ();
#endif

  for (pb = poollist; pb; pb = pb->pb_next)
    {
    mb_again:
      for (mb = pb->pb_freelist; mb; mb = mb->mb_next)
	{
	  mbend = (struct memblk *) ((char *) mb + mb->mb_len);
	  for (mb2 = pb->pb_freelist; mb2; mb2 = mb2->mb_next)
	    {
	      if (mb2 == mbend)
		{
		  /* unlink mb2 */
		  mb_unlink (mb2);
		  mb->mb_len += mb2->mb_len;
		  goto mb_again;
		}
	    }
	}
    }

#ifdef MEMORY_DEBUG
  printf ("After defrag: ");
  show_pools ();
#endif
}


void *
  malloc (size_t len)
{
  struct poolblk *pb, *newpb;
  struct memblk *mb;
  size_t lenadj, poolsz;
  char *end;

  lenadj = (len + sizeof (struct memblk) + 1023) & ~1023;
#ifdef MEMORY_DEBUG
  printf ("searching for segment of %d bytes\n", lenadj);
#endif

  if (poollist)
    {
      mb = m_search_pool (lenadj);
      if (mb)
	return (alloc_memblk (mb, lenadj));
#ifdef MEMORY_DEBUG
      printf ("cleaning the heap\n");
#endif
      defrag_heap ();
      mb = m_search_pool (lenadj);
      if (mb)
	return (alloc_memblk (mb, lenadj));
    }
#ifdef MEMORY_DEBUG
  printf ("allocating new pool\n");
#endif
  if (lenadj + sizeof (struct poolblk) > POOLSIZE)
    poolsz = (lenadj + sizeof (struct poolblk) + 1023) & ~1023;
  else
    poolsz = POOLSIZE;
  newpb = (struct poolblk *) real_malloc (poolsz);
  if (!newpb)
    return ((char *) 0);
  if (poollist)
    {
      for (pb = poollist; pb->pb_next; pb = pb->pb_next)
	;
      pb->pb_next = newpb;
    }
  else
    {
      poollist = newpb;
    }
  newpb->pb_next = 0;
  end = (char *) newpb + poolsz;
  mb = newpb->pb_freelist = (struct memblk *) (newpb + 1);
  mb->mb_next = 0;
  mb->mb_prev = 0;
  mb->mb_pool = newpb;
  mb->mb_len = end - (char *) mb;
  mb->mb_magic = MEM_MAGIC_FREE;
#ifdef MEMORY_DEBUG
  printf ("newpb=%x\n", newpb);
  printf ("newpb->pb_freelist=%x\n", newpb->pb_freelist);
  printf ("newpb->pb_freelist->mb_len=%x\n", newpb->pb_freelist->mb_len);
  show_pools ();
#endif
  mb = m_search_pool (lenadj);
  if (mb)
    return (alloc_memblk (mb, lenadj));
#ifdef MEMORY_DEBUG
  printf ("huh? m_search_pool failed?");
#endif
  return ((char *) 0);
}

void 
  free (void *p)
{
  struct memblk *mb;

  mb = (struct memblk *) p;
  --mb;
  if (mb->mb_magic != MEM_MAGIC_USED) {
    assert("attempted to free block with corrupt MAGIC");
    kill(getpid(), 11);
  }
  mb_link (mb);
}
This message resent by the uclinux-dev@uclinux.org list server http://www.uClinux.org/


This archive was generated by hypermail 2.1.4 : Thu Sep 19 2002 - 13:19:15 EDT