[hackers] [scc] [libc] add malloc, calloc, realloc, free || Quentin Rameau
commit 2d7dbef0b37f4db68657273979cbbb95bb823abd
Author: Quentin Rameau <quinq_AT_fifth.space>
AuthorDate: Fri Mar 3 18:24:41 2017 +0100
Commit: Quentin Rameau <quinq_AT_fifth.space>
CommitDate: Tue Mar 7 10:43:43 2017 +0100
[libc] add malloc, calloc, realloc, free
diff --git a/libc/include/bits/amd64-sysv/arch/stdlib.h b/libc/include/bits/amd64-sysv/arch/stdlib.h
index 0708580..4394db9 100644
--- a/libc/include/bits/amd64-sysv/arch/stdlib.h
+++ b/libc/include/bits/amd64-sysv/arch/stdlib.h
_AT_@ -12,3 +12,5 @@ typedef unsigned long size_t;
typedef int wchar_t;
#define _WCHAR_T
#endif
+
+#define _ALIGNTYPE long double
diff --git a/libc/include/bits/i386-sysv/arch/stdlib.h b/libc/include/bits/i386-sysv/arch/stdlib.h
index 0708580..4394db9 100644
--- a/libc/include/bits/i386-sysv/arch/stdlib.h
+++ b/libc/include/bits/i386-sysv/arch/stdlib.h
_AT_@ -12,3 +12,5 @@ typedef unsigned long size_t;
typedef int wchar_t;
#define _WCHAR_T
#endif
+
+#define _ALIGNTYPE long double
diff --git a/libc/include/bits/qbe/arch/stdlib.h b/libc/include/bits/qbe/arch/stdlib.h
index 0708580..4394db9 100644
--- a/libc/include/bits/qbe/arch/stdlib.h
+++ b/libc/include/bits/qbe/arch/stdlib.h
_AT_@ -12,3 +12,5 @@ typedef unsigned long size_t;
typedef int wchar_t;
#define _WCHAR_T
#endif
+
+#define _ALIGNTYPE long double
diff --git a/libc/include/bits/z80/arch/stdlib.h b/libc/include/bits/z80/arch/stdlib.h
index 931c68f..23f1644 100644
--- a/libc/include/bits/z80/arch/stdlib.h
+++ b/libc/include/bits/z80/arch/stdlib.h
_AT_@ -12,3 +12,5 @@ typedef unsigned size_t;
typedef long wchar_t;
#define _WCHAR_T
#endif
+
+#define _ALIGNTYPE int
diff --git a/libc/src/Makefile b/libc/src/Makefile
index 8399312..01e6a7c 100644
--- a/libc/src/Makefile
+++ b/libc/src/Makefile
_AT_@ -11,7 +11,8 @@ LIBCOBJ = assert.o strcpy.o strcmp.o strlen.o strchr.o \
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
diff --git a/libc/src/calloc.c b/libc/src/calloc.c
new file mode 100644
index 0000000..192f313
--- /dev/null
+++ b/libc/src/calloc.c
_AT_@ -0,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);
+}
diff --git a/libc/src/malloc.c b/libc/src/malloc.c
new file mode 100644
index 0000000..e9f9f91
--- /dev/null
+++ b/libc/src/malloc.c
_AT_@ -0,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;
+ }
+ }
+}
diff --git a/libc/src/malloc.h b/libc/src/malloc.h
new file mode 100644
index 0000000..9de01da
--- /dev/null
+++ b/libc/src/malloc.h
_AT_@ -0,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);
diff --git a/libc/src/realloc.c b/libc/src/realloc.c
new file mode 100644
index 0000000..54db73d
--- /dev/null
+++ b/libc/src/realloc.c
_AT_@ -0,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;
+}
Received on Tue Mar 07 2017 - 10:54:00 CET
This archive was generated by hypermail 2.3.0
: Tue Mar 07 2017 - 11:00:18 CET