2009-02-08 Vesa Jääskeläinen <chaac@nic.fi>

* kern/mm.c: Add more comments.
This commit is contained in:
chaac 2009-02-08 10:52:03 +00:00
parent e5698dc684
commit 2b40d6bb9f
2 changed files with 79 additions and 22 deletions

View File

@ -1,3 +1,7 @@
2009-02-08 Vesa Jääskeläinen <chaac@nic.fi>
* kern/mm.c: Add more comments.
2009-02-08 Robert Millan <rmh@aybabtu.com>
Patch from Javier Martín.

View File

@ -129,7 +129,7 @@ get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r)
if (! *r)
grub_fatal ("out of range pointer %p", ptr);
*p = (grub_mm_header_t) ptr - 1;
if ((*p)->magic != GRUB_MM_ALLOC_MAGIC)
grub_fatal ("alloc magic is broken at %p", *p);
@ -155,7 +155,7 @@ grub_mm_init_region (void *addr, grub_size_t size)
r = (grub_mm_region_t) (((grub_addr_t) addr + GRUB_MM_ALIGN - 1)
& (~(GRUB_MM_ALIGN - 1)));
size -= (char *) r - (char *) addr + sizeof (*r);
h = (grub_mm_header_t) ((char *) r + GRUB_MM_ALIGN);
h->next = h;
h->magic = GRUB_MM_FREE_MAGIC;
@ -170,22 +170,26 @@ grub_mm_init_region (void *addr, grub_size_t size)
for (p = &base, q = *p; q; p = &(q->next), q = *p)
if (q->size > r->size)
break;
*p = r;
r->next = q;
}
/* Allocate the number of units N with the alignment ALIGN from the ring
buffer starting from *FIRST. ALIGN must be a power of two. Return a
non-NULL if successful, otherwise return NULL. */
buffer starting from *FIRST. ALIGN must be a power of two. Both N and
ALIGN are in units of GRUB_MM_ALIGN. Return a non-NULL if successful,
otherwise return NULL. */
static void *
grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
{
grub_mm_header_t p, q;
/* When everything is allocated side effect is that *first will have alloc
magic marked, meaning that there is no room in this region. */
if ((*first)->magic == GRUB_MM_ALLOC_MAGIC)
return 0;
/* Try to search free slot for allocation in this memory region. */
for (q = *first, p = q->next; ; q = p, p = p->next)
{
grub_off_t extra;
@ -204,11 +208,37 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
{
if (extra == 0 && p->size == n)
{
/* There is no special alignment requirement and memory block
is complete match.
1. Just mark memory block as allocated and remove it from
free list.
Result:
+---------------+ previous block's next
| alloc, size=n | |
+---------------+ v
*/
q->next = p->next;
p->magic = GRUB_MM_ALLOC_MAGIC;
}
else if (extra == 0 || p->size == n + extra)
{
/* There might be alignment requirement, when taking it into
account memory block fits in.
1. Allocate new area at end of memory block.
2. Reduce size of available blocks from original node.
3. Mark new area as allocated and "remove" it from free
list.
Result:
+---------------+
| free, size-=n | next --+
+---------------+ |
| alloc, size=n | |
+---------------+ v
*/
p->size -= n;
p += p->size;
p->size = n;
@ -216,13 +246,32 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
}
else
{
/* There is alignment requirement and there is room in memory
block. Split memory block to three pieces.
1. Create new memory block right after section being
allocated. Mark it as free.
2. Add new memory block to free chain.
3. Mark current memory block having only extra blocks.
4. Advance to aligned block and mark that as allocated and
"remove" it from free list.
Result:
+------------------------------+
| free, size=extra | next --+
+------------------------------+ |
| alloc, size=n | |
+------------------------------+ |
| free, size=orig.size-extra-n | <------+, next --+
+------------------------------+ v
*/
grub_mm_header_t r;
r = p + extra + n;
r->magic = GRUB_MM_FREE_MAGIC;
r->size = p->size - extra - n;
r->next = p->next;
p->size = extra;
p->next = r;
p += extra;
@ -230,11 +279,15 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
p->magic = GRUB_MM_ALLOC_MAGIC;
}
/* Mark find as a start marker for next allocation to fasten it.
This will have side effect of fragmenting memory as small
pieces before this will be un-used. */
*first = q;
return p + 1;
}
/* Search was completed without result. */
if (p == *first)
break;
}
@ -249,17 +302,17 @@ grub_memalign (grub_size_t align, grub_size_t size)
grub_mm_region_t r;
grub_size_t n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + 1;
int count = 0;
align = (align >> GRUB_MM_ALIGN_LOG2);
if (align == 0)
align = 1;
again:
for (r = base; r; r = r->next)
{
void *p;
p = grub_real_malloc (&(r->first), n, align);
if (p)
return p;
@ -273,7 +326,7 @@ grub_memalign (grub_size_t align, grub_size_t size)
grub_disk_cache_invalidate_all ();
count++;
goto again;
case 1:
/* Unload unneeded modules. */
grub_dl_unload_unneeded ();
@ -283,7 +336,7 @@ grub_memalign (grub_size_t align, grub_size_t size)
default:
break;
}
grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
return 0;
}
@ -326,12 +379,12 @@ grub_free (void *ptr)
}
while (q != r->first);
#endif
for (q = r->first; q >= p || q->next <= p; q = q->next)
{
if (q->magic != GRUB_MM_FREE_MAGIC)
grub_fatal ("free magic is broken at %p: 0x%x", q, q->magic);
if (q >= q->next && (q < p || q->next > p))
break;
}
@ -339,7 +392,7 @@ grub_free (void *ptr)
p->magic = GRUB_MM_FREE_MAGIC;
p->next = q->next;
q->next = p;
if (p + p->size == p->next)
{
if (p->next == q)
@ -349,7 +402,7 @@ grub_free (void *ptr)
p->size += p->next->size;
p->next = p->next->next;
}
if (q + q->size == p)
{
p->magic = 0;
@ -370,7 +423,7 @@ grub_realloc (void *ptr, grub_size_t size)
grub_mm_region_t r;
void *q;
grub_size_t n;
if (! ptr)
return grub_malloc (size);
@ -383,14 +436,14 @@ grub_realloc (void *ptr, grub_size_t size)
/* FIXME: Not optimal. */
n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + 1;
get_header_from_pointer (ptr, &p, &r);
if (p->size >= n)
return ptr;
q = grub_malloc (size);
if (! q)
return q;
grub_memcpy (q, ptr, size);
grub_free (ptr);
return q;
@ -434,7 +487,7 @@ grub_mm_dump (unsigned lineno)
for (r = base; r; r = r->next)
{
grub_mm_header_t p;
for (p = (grub_mm_header_t) ((r->addr + GRUB_MM_ALIGN - 1)
& (~(GRUB_MM_ALIGN - 1)));
(grub_addr_t) p < r->addr + r->size;
@ -493,7 +546,7 @@ grub_debug_memalign (const char *file, int line, grub_size_t align,
grub_size_t size)
{
void *ptr;
if (grub_mm_debug)
grub_printf ("%s:%d: memalign (0x%x, 0x%x) = ",
file, line, align, size);