blob: 8fccaf6ae9b5490f6c1ba30afae90ad507645b1d [file] [log] [blame]
/*
* An implementation of malloc as described in the K&R C programming book
*
* Copyright 2014, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <allocman/mspace/k_r_malloc.h>
#include <stddef.h> /* For NULL */
#include <stdlib.h>
#include <string.h> /* For memcpy */
void mspace_k_r_malloc_init(mspace_k_r_malloc_t *k_r_malloc, size_t cookie, k_r_malloc_header_t * (*morecore)(size_t cookie, mspace_k_r_malloc_t *k_r_malloc, size_t new_units))
{
k_r_malloc->freep = NULL;
k_r_malloc->cookie = cookie;
k_r_malloc->morecore = morecore;
}
void *mspace_k_r_malloc_alloc(mspace_k_r_malloc_t *k_r_malloc, size_t nbytes)
{
k_r_malloc_header_t *p, *prevp;
size_t nunits;
nunits = (nbytes + sizeof(k_r_malloc_header_t) - 1) / sizeof(k_r_malloc_header_t) + 1;
if ((prevp = k_r_malloc->freep) == NULL) { /* no free list yet */
k_r_malloc->base.s.ptr = k_r_malloc->freep = prevp = &k_r_malloc->base;
k_r_malloc->base.s.size = 0;
}
for (p = prevp->s.ptr;; prevp = p, p = p->s.ptr) {
if (p->s.size >= nunits) { /* big enough */
if (p->s.size == nunits) { /* exactly */
prevp->s.ptr = p->s.ptr;
} else { /* allocate tail end */
p->s.size -= nunits;
p += p->s.size;
p->s.size = nunits;
}
k_r_malloc->freep = prevp;
return (void *) (p + 1);
}
if (p == k_r_malloc->freep) { /* wrapped around free list */
if ((p = (k_r_malloc_header_t *) k_r_malloc->morecore(k_r_malloc->cookie, k_r_malloc, nunits)) == NULL) {
return NULL; /* none left */
} else {
/* Put the thing in */
p->s.size = nunits;
mspace_k_r_malloc_free(k_r_malloc, p + 1);
p = k_r_malloc->freep;
}
}
}
}
void mspace_k_r_malloc_free(mspace_k_r_malloc_t *k_r_malloc, void *ap)
{
k_r_malloc_header_t *bp, *p;
if (ap == NULL) {
return;
}
bp = (k_r_malloc_header_t *) ap - 1; /* point to block header */
for (p = k_r_malloc->freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
if (p >= p->s.ptr && (bp > p || bp < p->s.ptr)) {
break; /* freed block at start or end of area */
}
if (bp + bp->s.size == p->s.ptr) { /* join to upper nbr */
bp->s.size += p->s.ptr->s.size;
bp->s.ptr = p->s.ptr->s.ptr;
} else {
bp->s.ptr = p->s.ptr;
}
if (p + p->s.size == bp) { /* join to lower nbr */
p->s.size += bp->s.size;
p->s.ptr = bp->s.ptr;
} else {
p->s.ptr = bp;
}
k_r_malloc->freep = p;
}