shithub: scc

Download patch

ref: 5cc018714cb7131b460b69dc52d2813d5fa68af0
parent: 916a4ec745ac099b0747c94c0def75c54e6a005f
author: Quentin Rameau <quinq@fifth.space>
date: Fri Mar 3 13:24:41 EST 2017

[libc] add malloc, calloc, realloc, free

--- a/libc/include/bits/amd64-sysv/arch/stdlib.h
+++ b/libc/include/bits/amd64-sysv/arch/stdlib.h
@@ -12,3 +12,5 @@
 typedef int wchar_t;
 #define _WCHAR_T
 #endif
+
+#define _ALIGNTYPE long double
--- a/libc/include/bits/i386-sysv/arch/stdlib.h
+++ b/libc/include/bits/i386-sysv/arch/stdlib.h
@@ -12,3 +12,5 @@
 typedef int wchar_t;
 #define _WCHAR_T
 #endif
+
+#define _ALIGNTYPE long double
--- a/libc/include/bits/qbe/arch/stdlib.h
+++ b/libc/include/bits/qbe/arch/stdlib.h
@@ -12,3 +12,5 @@
 typedef int wchar_t;
 #define _WCHAR_T
 #endif
+
+#define _ALIGNTYPE long double
--- a/libc/include/bits/z80/arch/stdlib.h
+++ b/libc/include/bits/z80/arch/stdlib.h
@@ -12,3 +12,5 @@
 typedef long wchar_t;
 #define _WCHAR_T
 #endif
+
+#define _ALIGNTYPE int
--- a/libc/src/Makefile
+++ b/libc/src/Makefile
@@ -11,7 +11,8 @@
           isgraph.o islower.o isprint.o ispunct.o isspace.o isupper.o \
           isxdigit.o toupper.o tolower.o ctype.o setlocale.o \
           localeconv.o atoi.o atexit.o exit.o \
-          printf.o fprintf.o vfprintf.o
+          printf.o fprintf.o vfprintf.o \
+          realloc.o calloc.o malloc.o
 
 all: libc.a
 
--- /dev/null
+++ b/libc/src/calloc.c
@@ -1,0 +1,19 @@
+/* See LICENSE file for copyright and license details. */
+
+#include <stdlib.h>
+#include <string.h>
+
+void *
+calloc(size_t nmemb, size_t size)
+{
+	size_t nbytes;
+	void *mem;
+
+	if (!nmemb || !size || nmemb > (size_t)-1/size)
+                return NULL;
+
+	nbytes = nmemb * size;
+	if ((mem = malloc(nbytes)) == NULL)
+		return NULL;
+	return memset(mem, 0, nbytes);
+}
--- /dev/null
+++ b/libc/src/malloc.c
@@ -1,0 +1,134 @@
+/* See LICENSE file for copyright and license details. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "malloc.h"
+
+extern void *_sbrk(intptr_t increment);
+
+static Header base = { .h.next = &base };
+static Header *freep = &base;
+
+/*
+ * Run over the free list looking for the nearest previous
+ * block. There are two possible results: end of the list
+ * or an intermediary block.
+ */
+void *
+_prevchunk(Header *hp)
+{
+	Header *p;
+
+	for (p = freep; ;p = p->h.next) {
+		/* hp between p and p->h.next? */
+		if (p < hp && hp < p->h.next)
+			break;
+		/* p before hp and hp at the end of list? */
+		if (p->h.next <= p && (hp < p->h.next || hp > p))
+			break;
+	}
+	return p;
+}
+
+/*
+ * Get the previous block and try to merge
+ * with next and previous blocks
+ */
+void
+free(void *mem)
+{
+	Header *hp, *prev;
+
+	if (!mem)
+		return;
+
+	hp = (Header *) mem - 1;
+	prev = _prevchunk(hp);
+
+	/* join to next */
+	if (hp + hp->h.size == prev->h.next) {
+		hp->h.size += prev->h.next->h.size;
+		hp->h.next = prev->h.next->h.next;
+	} else {
+		hp->h.next = prev->h.next;
+	}
+
+	/* join to previous */
+	if (prev + prev->h.size == hp) {
+		prev->h.size += hp->h.size;
+		prev->h.next = hp->h.next;
+	} else {
+		prev->h.next = hp;
+	}
+
+	freep = prev;
+}
+
+static Header *
+morecore(size_t nunits)
+{
+	char *rawmem;
+	Header *hp;
+
+	if (nunits < NALLOC)
+		nunits = NALLOC;
+
+	rawmem = _sbrk(nunits * sizeof(Header));
+	if (rawmem == (void *)-1)
+		return NULL;
+
+	hp = (Header*)rawmem;
+	hp->h.size = nunits;
+
+	/* integrate new memory into the list */
+	free(hp + 1);
+
+	return freep;
+}
+
+/*
+ * Run over the list of free blocks trying to find a block
+ * big enough for nbytes. If the block fit perfectly with
+ * the required size then we only have to unlink
+ * the block. Otherwise we have to split the block and
+ * return the right part. If we run over the full list
+ * without a fit then we have to require more memory
+ *
+ *              ______________________________________
+ * ___________./______________________________________\_____
+ * ...| in   |   |     | in  |  |.....| in   |  |    | |....
+ * ...| use  |   |     | use |  |.....| use  |  |    | |....
+ * ___|______|___|.____|_____|._|_____|______|._|.___|.|____
+ *            \__/ \_________/ \_____________/ \/ \__/
+ */
+void *
+malloc(size_t nbytes)
+{
+	Header *cur, *prev;
+	size_t nunits;
+
+	/* 1 unit for header plus enough units to fit nbytes */
+	nunits = (nbytes+sizeof(Header)-1) / sizeof(Header) + 1;
+
+	for (prev = freep; ; prev = cur) {
+		cur = prev->h.next;
+		if (cur->h.size >= nunits) {
+			if (cur->h.size == nunits) {
+				prev->h.next = cur->h.next;
+			} else {
+				cur->h.size -= nunits;
+				cur += cur->h.size;
+				cur->h.size = nunits;
+			}
+			freep = prev;
+			return cur + 1;
+		}
+
+		if (cur == freep) {
+			if ((cur = morecore(nunits)) == NULL)
+				return NULL;
+		}
+	}
+}
--- /dev/null
+++ b/libc/src/malloc.h
@@ -1,0 +1,18 @@
+/* See LICENSE file for copyright and license details. */
+
+#include <stdlib.h>
+
+/* minimum amount of required units */
+#define NALLOC 10000
+
+typedef union header Header;
+union header {
+	struct hdr {
+		Header *next;
+		size_t size;
+	} h;
+	/* most restrictive type fixes the union size for alignment */
+	_ALIGNTYPE most;
+};
+
+extern void *_prevchunk(Header *hp);
--- /dev/null
+++ b/libc/src/realloc.c
@@ -1,0 +1,69 @@
+/* See LICENSE file for copyright and license details. */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "malloc.h"
+
+void *
+realloc(void *ptr, size_t nbytes)
+{
+	Header *oh, *prev, *next, *new;
+	size_t nunits, avail, onbytes, n;
+
+	if (!nbytes)
+		return NULL;
+
+	if (!ptr)
+		return malloc(nbytes);
+
+	nunits = (nbytes + sizeof(Header) - 1) / sizeof(Header) + 1;
+	oh = (Header*)ptr - 1;
+
+	if (oh->h.size == nunits)
+		return ptr;
+
+	new = oh + nunits;
+
+	if (nunits < oh->h.size - 1) {
+		new->h.size = oh->h.size - nunits;
+		oh->h.size = nunits;
+		free(new + 1);
+		return oh;
+	}
+
+	prev = _prevchunk(oh);
+
+	if (oh + oh->h.size == prev->h.next) {
+		/*
+		 * if there is free space adjacent
+		 * to the current memory
+		 */
+		next = prev->h.next;
+		avail = oh->h.size + next->h.size;
+
+		if (avail == nunits) {
+			oh->h.size = nunits;
+			prev->h.next = next->h.next;
+			return oh;
+		}
+
+		if (avail > nunits) {
+			oh->h.size = nunits;
+			prev->h.next = new;
+			new->h.next = next;
+			new->h.size = avail - nunits;
+			return oh;
+		}
+	}
+
+	onbytes = (oh->h.size - 1) * sizeof(Header);
+	if ((new = malloc(nbytes)) == NULL)
+		return NULL;
+
+	n = (onbytes > nbytes) ? nbytes : onbytes;
+	memcpy(new, ptr, n);
+	free(ptr);
+
+	return new;
+}