}
/* Allocate the number of units N with the alignment ALIGN from the ring
- 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. */
+ * buffer given in *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.
+ *
+ * Note: because in certain circumstances we need to adjust the ->next
+ * pointer of the previous block, we iterate over the singly linked
+ * list with the pair (prev, cur). *FIRST is our initial previous, and
+ * *FIRST->next is our initial current pointer. So we will actually
+ * allocate from *FIRST->next first and *FIRST itself last.
+ */
static void *
grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align)
{
- grub_mm_header_t p, q;
+ grub_mm_header_t cur, prev;
/* When everything is allocated side effect is that *first will have alloc
magic marked, meaning that there is no room in this region. */
return 0;
/* Try to search free slot for allocation in this memory region. */
- for (q = *first, p = q->next; ; q = p, p = p->next)
+ for (prev = *first, cur = prev->next; ; prev = cur, cur = cur->next)
{
grub_off_t extra;
- extra = ((grub_addr_t) (p + 1) >> GRUB_MM_ALIGN_LOG2) & (align - 1);
+ extra = ((grub_addr_t) (cur + 1) >> GRUB_MM_ALIGN_LOG2) & (align - 1);
if (extra)
extra = align - extra;
- if (! p)
+ if (! cur)
grub_fatal ("null in the ring");
- if (p->magic != GRUB_MM_FREE_MAGIC)
- grub_fatal ("free magic is broken at %p: 0x%x", p, p->magic);
+ if (cur->magic != GRUB_MM_FREE_MAGIC)
+ grub_fatal ("free magic is broken at %p: 0x%x", cur, cur->magic);
- if (p->size >= n + extra)
+ if (cur->size >= n + extra)
{
- extra += (p->size - extra - n) & (~(align - 1));
- if (extra == 0 && p->size == n)
+ extra += (cur->size - extra - n) & (~(align - 1));
+ if (extra == 0 && cur->size == n)
{
/* There is no special alignment requirement and memory block
is complete match.
| alloc, size=n | |
+---------------+ v
*/
- q->next = p->next;
+ prev->next = cur->next;
}
- else if (align == 1 || p->size == n + extra)
+ else if (align == 1 || cur->size == n + extra)
{
/* There might be alignment requirement, when taking it into
account memory block fits in.
| alloc, size=n | |
+---------------+ v
*/
-
- p->size -= n;
- p += p->size;
+ cur->size -= n;
+ cur += cur->size;
}
else if (extra == 0)
{
grub_mm_header_t r;
- r = p + extra + n;
+ r = cur + extra + n;
r->magic = GRUB_MM_FREE_MAGIC;
- r->size = p->size - extra - n;
- r->next = p->next;
- q->next = r;
+ r->size = cur->size - extra - n;
+ r->next = cur->next;
+ prev->next = r;
- if (q == p)
+ if (prev == cur)
{
- q = r;
+ prev = r;
r->next = r;
}
}
*/
grub_mm_header_t r;
- r = p + extra + n;
+ r = cur + extra + n;
r->magic = GRUB_MM_FREE_MAGIC;
- r->size = p->size - extra - n;
- r->next = p;
+ r->size = cur->size - extra - n;
+ r->next = cur;
- p->size = extra;
- q->next = r;
- p += extra;
+ cur->size = extra;
+ prev->next = r;
+ cur += extra;
}
- p->magic = GRUB_MM_ALLOC_MAGIC;
- p->size = n;
+ cur->magic = GRUB_MM_ALLOC_MAGIC;
+ cur->size = n;
/* 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. */
/* So do it only for chunks under 64K. */
if (n < (0x8000 >> GRUB_MM_ALIGN_LOG2)
- || *first == p)
- *first = q;
+ || *first == cur)
+ *first = prev;
- return p + 1;
+ return cur + 1;
}
/* Search was completed without result. */
- if (p == *first)
+ if (cur == *first)
break;
}