1#include <errno.h>2#include <stdint.h>3#include <stdlib.h>4#include <string.h>56#include "malloc.h"7#include "../syscall.h"8#include "../libc.h"910#undef malloc11#undef free1213#define MAXADDR ((char *)-1)14#define ERRADDR ((char *)-1)1516static Header base = { .h.next = &base };17Header *_freep = &base;1819/*20 * Run over the free list looking for the nearest previous21 * block. There are two possible results: end of the list22 * or an intermediary block.23 */24void *25_prevchunk(Header *hp)26{27 Header *p;2829 for (p = _freep; ;p = p->h.next) {30 /* hp between p and p->h.next? */31 if (p < hp && hp < p->h.next)32 break;3334 /* p before hp and hp at the end of list? */35 if (p->h.next <= p && (hp < p->h.next || hp > p))36 break;37 }38 return p;39}4041/*42 * Get the previous block and try to merge43 * with next and previous blocks44 */45void46free(void *mem)47{48 Header *hp, *prev, *next;4950 if (!mem)51 return;5253 hp = (Header *) mem - 1;54 prev = _prevchunk(hp);55 next = prev->h.next;5657 /* join to next */58 if (hp + hp->h.size == next) {59 hp->h.size += next->h.size;60 hp->h.next = next->h.next;61 } else {62 hp->h.next = next;63 }6465 /* join to previous */66 if (prev + prev->h.size == hp) {67 prev->h.size += hp->h.size;68 prev->h.next = hp->h.next;69 } else {70 prev->h.next = hp;71 }7273 _freep = prev;74}7576static void *77sbrk(uintptr_t inc)78{79 char *new, *old;80 static void *heap;8182 if (!heap)83 heap = _getheap();8485 old = heap;86 if (old >= MAXADDR - inc)87 return ERRADDR;8889 new = old + inc;90 if (_brk(new) < 0)91 return ERRADDR;92 heap = new;9394 return old;95}9697static Header *98morecore(size_t nunits)99{100 void *rawmem;101 Header *hp;102103 if (nunits < NALLOC)104 nunits = NALLOC;105106 rawmem = sbrk(nunits * sizeof(Header));107 if (rawmem == ERRADDR)108 return NULL;109110 hp = (Header *) rawmem;111 hp->h.size = nunits;112113 /* integrate new memory into the list */114 free(hp + 1);115116 return _freep;117}118119/*120 * Run over the list of free blocks trying to find a block121 * big enough for nbytes. If the block fits perfectly with122 * the required size then we only have to unlink123 * the block. Otherwise we have to split the block and124 * return the right part. If we run over the full list125 * without a fit then we have to acquire more memory126 *127 * ______________________________________128 * ___________./______________________________________\_____129 * ...| in | | | in | |.....| in | | | |....130 * ...| use | | | use | |.....| use | | | |....131 * ___|______|___|.____|_____|._|_____|______|._|.___|.|____132 * \__/ \_________/ \_____________/ \/ \__/133 */134void *135malloc(size_t nbytes)136{137 Header *cur, *prev;138 size_t nunits;139140 if (nbytes > SIZE_MAX - sizeof(Header)-1) {141 errno = ENOMEM;142 return NULL;143 }144145 /* 1 unit for header plus enough units to fit nbytes */146 nunits = (nbytes+sizeof(Header)-1)/sizeof(Header) + 1;147148 for (prev = _freep; ; prev = cur) {149 cur = prev->h.next;150 if (cur->h.size >= nunits) {151 if (cur->h.size == nunits) {152 prev->h.next = cur->h.next;153 } else {154 cur->h.size -= nunits;155 cur += cur->h.size;156 cur->h.size = nunits;157 }158159 cur->h.next = NULL;160 _freep = prev;161162 return cur + 1;163 }164165 if (cur == _freep) {166 if ((cur = morecore(nunits)) == NULL)167 return NULL;168 }169 }170}