~ubuntu-branches/ubuntu/breezy/avr-libc/breezy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <stdlib.h>

#define XSIZE(x) ((*x)>>1)
#define FREE_P(x) (!((*x)&1))
#define MARK_BUSY(x) ((*x)|=1)
#define MARK_FREE(x) ((*x)&=0xfffe)

extern size_t __bss_end;
#define GET_HEAP_BOTTOM(h) asm volatile ("in %A0, __SP_L__\n\t"		   \
					 "in %B0, __SP_H__" : "=r" (h) :)

void *malloc (size_t size)
{
  static char once;
  size_t * heap_bottom;
  size_t * heap_top = &__bss_end;
  char f = 0;

  if (!once) {
    once = 1;
    *heap_top = 0xFFFE;
  }
  GET_HEAP_BOTTOM (heap_bottom);
  heap_bottom -= 20;
  size = (size+1) >> 1;	/* round to 2 */
  do
    {
      size_t xsize = XSIZE (heap_top);
      size_t * heap_next = &heap_top[xsize + 1];
      if ((xsize<<1)+2 == 0)
	{
	  f = 1;
	}
      if (FREE_P (heap_top))
	{
	  if (f)
	    {
	      xsize = heap_bottom - heap_top - 1;
	    }
	  else if (FREE_P(heap_next))
	    {
	      *heap_top = ( (XSIZE(heap_next)<<1) + 2 == 0
			    ? 0xfffe
			    : (xsize + XSIZE(heap_next) + 1)<<1);
	      continue;
	    }
	  if (xsize >= size)
	    {
	      if (f)
		heap_top[size + 1] = 0xfffe;
	      else if (xsize != size)
		heap_top[size + 1] = (xsize - size - 1) << 1;
	      *heap_top = size << 1;
	      MARK_BUSY (heap_top);
	      return heap_top+1;
	    }
	}
      heap_top += xsize + 1;
    } while (!f);
  return NULL;
}

void free (void *p)
{
  size_t *t = (size_t*)p - 1;
  MARK_FREE (t);
}