summaryrefslogtreecommitdiff
path: root/src/user
diff options
context:
space:
mode:
Diffstat (limited to 'src/user')
-rw-r--r--src/user/app/drawmouse/drawmouse.c87
-rw-r--r--src/user/app/dvd/dvd.c43
m---------src/user/app/ext2fs/ext20
-rw-r--r--src/user/app/ext2fs/main.c243
-rw-r--r--src/user/app/find/find.c55
-rw-r--r--src/user/app/httpd/httpd.c77
-rw-r--r--src/user/app/init/driver/driver.h8
-rw-r--r--src/user/app/init/driver/initctl.c44
-rw-r--r--src/user/app/init/driver/ps2.c129
-rw-r--r--src/user/app/init/driver/termcook.c103
-rw-r--r--src/user/app/init/init.c151
-rw-r--r--src/user/app/iochk/iochk.c97
-rw-r--r--src/user/app/iostress/iostress.c43
-rw-r--r--src/user/app/logfs/logfs.c34
-rw-r--r--src/user/app/login/login.c89
-rw-r--r--src/user/app/netdog/nd.c48
-rw-r--r--src/user/app/netstack/arp.c151
-rw-r--r--src/user/app/netstack/ether.c59
-rw-r--r--src/user/app/netstack/fs.c320
-rw-r--r--src/user/app/netstack/icmp.c34
-rw-r--r--src/user/app/netstack/ipv4.c216
-rw-r--r--src/user/app/netstack/netstack.c53
-rw-r--r--src/user/app/netstack/proto.h107
-rw-r--r--src/user/app/netstack/tcp.c268
-rw-r--r--src/user/app/netstack/udp.c124
-rw-r--r--src/user/app/netstack/util.c60
-rw-r--r--src/user/app/netstack/util.h44
-rw-r--r--src/user/app/ps/ps.c54
-rw-r--r--src/user/app/shell/builtins.c254
-rw-r--r--src/user/app/shell/builtins.h10
-rw-r--r--src/user/app/shell/parser.c76
-rw-r--r--src/user/app/shell/shell.c178
-rw-r--r--src/user/app/shell/shell.h11
-rw-r--r--src/user/app/testelf/main.c26
-rw-r--r--src/user/app/tests/kernel/fdlimit.c49
-rw-r--r--src/user/app/tests/kernel/fs.c79
-rw-r--r--src/user/app/tests/kernel/misc.c66
-rw-r--r--src/user/app/tests/kernel/miscsyscall.c315
-rw-r--r--src/user/app/tests/kernel/path.c108
-rw-r--r--src/user/app/tests/kernel/threads.c55
-rw-r--r--src/user/app/tests/libc/esemaphore.c95
-rw-r--r--src/user/app/tests/libc/setjmp.c31
-rw-r--r--src/user/app/tests/libc/string.c124
-rw-r--r--src/user/app/tests/shared/printf.c55
-rw-r--r--src/user/app/tests/shared/ringbuf.c49
-rw-r--r--src/user/app/tests/stress.c28
-rw-r--r--src/user/app/tests/tests.c68
-rw-r--r--src/user/app/tests/tests.h37
-rw-r--r--src/user/app/tmpfs/tmpfs.c198
-rw-r--r--src/user/app/vterm/draw.c17
-rw-r--r--src/user/app/vterm/font.c76
-rw-r--r--src/user/app/vterm/vterm.c72
-rw-r--r--src/user/app/vterm/vterm.h39
-rw-r--r--src/user/bootstrap/entry.S27
-rw-r--r--src/user/bootstrap/linker.ld31
-rw-r--r--src/user/bootstrap/main.c43
-rw-r--r--src/user/bootstrap/tar.c155
-rw-r--r--src/user/bootstrap/tar.h6
-rw-r--r--src/user/lib/_start.s17
-rw-r--r--src/user/lib/_start2.c42
-rw-r--r--src/user/lib/assert.c8
-rw-r--r--src/user/lib/camellia.c30
-rw-r--r--src/user/lib/compat.c20
-rw-r--r--src/user/lib/ctype.c65
-rw-r--r--src/user/lib/dirent.c55
-rw-r--r--src/user/lib/draw/draw.c83
-rw-r--r--src/user/lib/draw/flush.c43
-rw-r--r--src/user/lib/elf.h188
-rw-r--r--src/user/lib/elfload.S20
-rw-r--r--src/user/lib/elfload.c182
-rw-r--r--src/user/lib/elfreloc.c39
-rw-r--r--src/user/lib/err.c50
-rw-r--r--src/user/lib/esemaphore.c56
-rw-r--r--src/user/lib/fcntl.c28
-rw-r--r--src/user/lib/fs/dir.c84
-rw-r--r--src/user/lib/fs/dirinject.c129
-rw-r--r--src/user/lib/fs/misc.c160
-rw-r--r--src/user/lib/fs/whitelist.c114
-rw-r--r--src/user/lib/include/__errno.h26
-rw-r--r--src/user/lib/include/__errno.h.awk20
-rw-r--r--src/user/lib/include/_proc.h14
-rw-r--r--src/user/lib/include/alloca.h3
-rw-r--r--src/user/lib/include/bits/file.h2
-rw-r--r--src/user/lib/include/bits/panic.h5
-rw-r--r--src/user/lib/include/camellia.h5
-rw-r--r--src/user/lib/include/camellia/compat.h6
-rw-r--r--src/user/lib/include/camellia/fs/dir.h17
-rw-r--r--src/user/lib/include/camellia/fs/misc.h22
-rw-r--r--src/user/lib/include/ctype.h16
-rw-r--r--src/user/lib/include/dirent.h16
-rw-r--r--src/user/lib/include/draw.h24
-rw-r--r--src/user/lib/include/elfload.h14
-rw-r--r--src/user/lib/include/err.h10
-rw-r--r--src/user/lib/include/errno.h3
-rw-r--r--src/user/lib/include/esemaphore.h12
-rw-r--r--src/user/lib/include/fcntl.h25
-rw-r--r--src/user/lib/include/ftw.h6
l---------src/user/lib/include/getopt.h1
-rw-r--r--src/user/lib/include/grp.h11
-rw-r--r--src/user/lib/include/inttypes.h1
-rw-r--r--src/user/lib/include/limits.h6
-rw-r--r--src/user/lib/include/locale.h73
l---------src/user/lib/include/malloc.h1
-rw-r--r--src/user/lib/include/math.h27
-rw-r--r--src/user/lib/include/pwd.h14
-rw-r--r--src/user/lib/include/setjmp.h18
-rw-r--r--src/user/lib/include/signal.h54
-rw-r--r--src/user/lib/include/stdio.h84
-rw-r--r--src/user/lib/include/stdlib.h34
-rw-r--r--src/user/lib/include/string.h25
-rw-r--r--src/user/lib/include/strings.h5
-rw-r--r--src/user/lib/include/sys/ioctl.h13
-rw-r--r--src/user/lib/include/sys/mman.h18
-rw-r--r--src/user/lib/include/sys/param.h2
-rw-r--r--src/user/lib/include/sys/resource.h2
-rw-r--r--src/user/lib/include/sys/stat.h70
-rw-r--r--src/user/lib/include/sys/sysmacros.h3
-rw-r--r--src/user/lib/include/sys/time.h0
-rw-r--r--src/user/lib/include/sys/times.h13
-rw-r--r--src/user/lib/include/sys/types.h18
-rw-r--r--src/user/lib/include/sys/wait.h13
-rw-r--r--src/user/lib/include/termios.h0
-rw-r--r--src/user/lib/include/thread.h9
-rw-r--r--src/user/lib/include/time.h34
-rw-r--r--src/user/lib/include/unistd.h64
-rw-r--r--src/user/lib/intr.s20
-rw-r--r--src/user/lib/math.c27
-rw-r--r--src/user/lib/mman.c24
-rw-r--r--src/user/lib/printf.c56
-rw-r--r--src/user/lib/pwd.c23
-rw-r--r--src/user/lib/setjmp.s39
-rw-r--r--src/user/lib/signal.c100
-rw-r--r--src/user/lib/stdio/file.c359
-rw-r--r--src/user/lib/stdio/file.h14
-rw-r--r--src/user/lib/stdio/misc.c52
-rw-r--r--src/user/lib/stdlib.c148
-rw-r--r--src/user/lib/string/strerror.c13
-rw-r--r--src/user/lib/string/string.c122
-rw-r--r--src/user/lib/syscall.c104
-rw-r--r--src/user/lib/syscall.c.awk51
-rw-r--r--src/user/lib/syscall.s9
-rw-r--r--src/user/lib/sysstat.c50
-rw-r--r--src/user/lib/syswait.c22
-rw-r--r--src/user/lib/thread.S40
-rw-r--r--src/user/lib/time.c43
-rw-r--r--src/user/lib/unistd.c267
-rw-r--r--src/user/lib/vendor/dlmalloc/malloc.c6280
-rw-r--r--src/user/lib/vendor/dlmalloc/malloc.h620
-rw-r--r--src/user/lib/vendor/getopt/getopt.c75
-rw-r--r--src/user/lib/vendor/getopt/getopt.h21
-rw-r--r--src/user/linker.ld23
151 files changed, 0 insertions, 15993 deletions
diff --git a/src/user/app/drawmouse/drawmouse.c b/src/user/app/drawmouse/drawmouse.c
deleted file mode 100644
index 31a1255..0000000
--- a/src/user/app/drawmouse/drawmouse.c
+++ /dev/null
@@ -1,87 +0,0 @@
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <shared/ring.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <draw.h>
-
-#define MOUSE_SIZE 10
-
-#define eprintf(fmt, ...) fprintf(stderr, "drawmouse: "fmt"\n" __VA_OPT__(,) __VA_ARGS__)
-
-struct framebuf fb, lastbehind;
-struct rect dirty;
-
-static uint8_t r_buf[64];
-static ring_t r = {(void*)r_buf, sizeof r_buf, 0, 0};
-static struct {uint32_t x, y;} cursor, lastcur;
-
-
-static void draw_mouse(void) {
- static bool drawn = false;
- if (drawn)
- fb_cpy(&fb, &lastbehind, lastcur.x, lastcur.y, 0, 0, MOUSE_SIZE, MOUSE_SIZE);
- drawn = true;
- dirty_mark(&dirty, lastcur.x, lastcur.y);
- dirty_mark(&dirty, lastcur.x + MOUSE_SIZE, lastcur.y + MOUSE_SIZE);
- fb_cpy(&lastbehind, &fb, 0, 0, cursor.x, cursor.y, MOUSE_SIZE, MOUSE_SIZE);
- for (int i = 0; i < MOUSE_SIZE; i++) {
- for (int j = 0; j < MOUSE_SIZE - i; j++) {
- uint32_t *px = fb_pixel(&fb, cursor.x + i, cursor.y + j);
- if (px) {
- *px ^= 0x808080;
- dirty_mark(&dirty, cursor.x + i, cursor.y + j);
- }
- }
- }
- lastcur = cursor;
-}
-
-
-struct packet {
- uint8_t left : 1;
- uint8_t right : 1;
- uint8_t middle : 1;
- uint8_t _useless : 5;
- int8_t dx, dy;
-} __attribute__((packed));
-
-int main(void) {
- char buf[64];
- hid_t fd = camellia_open("/kdev/ps2/mouse", OPEN_READ);
- if (fd < 0) {
- eprintf("couldn't open mouse");
- return 1;
- }
-
- if (fb_setup(&fb, "/kdev/video/") < 0) {
- eprintf("fb_setup error");
- return 1;
- }
- fb_anon(&lastbehind, MOUSE_SIZE, MOUSE_SIZE);
-
-
- for (;;) {
- int len = _sys_read(fd, buf, sizeof buf, 0);
- if (len == 0) break;
- ring_put(&r, buf, len);
- while (ring_used(&r) >= 3) {
- struct packet p;
- ring_get(&r, &p, sizeof p);
- p.dy *= -1;
- // TODO check mouse click
- if (-p.dx > (int)cursor.x) p.dx = -cursor.x;
- if (-p.dy > (int)cursor.y) p.dy = -cursor.y;
- cursor.x += p.dx;
- cursor.y += p.dy;
- if (cursor.x >= fb.width) cursor.x = fb.width - 1;
- if (cursor.y >= fb.height) cursor.y = fb.height - 1;
- draw_mouse();
- if (p.left && p.right) return 0;
- }
- dirty_flush(&dirty, &fb);
- }
- return 0;
-}
diff --git a/src/user/app/dvd/dvd.c b/src/user/app/dvd/dvd.c
deleted file mode 100644
index a15b440..0000000
--- a/src/user/app/dvd/dvd.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <camellia/execbuf.h>
-#include <camellia/syscalls.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <draw.h>
-
-#define eprintf(fmt, ...) fprintf(stderr, "vterm: "fmt"\n" __VA_OPT__(,) __VA_ARGS__)
-
-struct framebuf fb;
-struct rect dirty;
-
-void draw_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t col) {
- for (uint32_t i = 0; i < w; i++) {
- for (uint32_t j = 0; j < h; j++) {
- *((uint32_t*)(fb.b + fb.pitch * (y+j) + 4 * (x+i))) = col;
- }
- }
- dirty_mark(&dirty, x, y);
- dirty_mark(&dirty, x + w, y + h);
-}
-
-int main(void) {
- if (fb_setup(&fb, "/kdev/video/") < 0) {
- eprintf("fb_setup error");
- return 1;
- }
- int dx = 2, dy = 2, x = 100, y = 100, w = 150, h = 70;
- uint32_t col = 0x800000;
-
- for (;;) {
- if (x + dx < 0 || (size_t)(x + dx + w) >= fb.width) dx *= -1;
- if (y + dy < 0 || (size_t)(y + dy + h) >= fb.height) dy *= -1;
- x += dx;
- y += dy;
- draw_rect(x, y, w, h, col++);
- dirty_flush(&dirty, &fb);
- _sys_sleep(1000 / 60);
- }
-
- return 1;
-}
diff --git a/src/user/app/ext2fs/ext2 b/src/user/app/ext2fs/ext2
deleted file mode 160000
-Subproject 8db7b4fbb2429b504d7c711dae89d917de16bed
diff --git a/src/user/app/ext2fs/main.c b/src/user/app/ext2fs/main.c
deleted file mode 100644
index 12ef3bc..0000000
--- a/src/user/app/ext2fs/main.c
+++ /dev/null
@@ -1,243 +0,0 @@
-#include "ext2/ex_cache.h"
-#include "ext2/ext2.h"
-#include <assert.h>
-#include <camellia/flags.h>
-#include <camellia/fs/dir.h>
-#include <camellia/fs/misc.h>
-#include <camellia/fsutil.h>
-#include <camellia/syscalls.h>
-#include <err.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-struct handle {
- uint32_t n;
- bool dir;
-};
-
-static int my_read(void *fp, void *buf, size_t len, size_t off);
-static int my_write(void *fp, const void *buf, size_t len, size_t off);
-static void do_open(struct ext2 *fs, hid_t reqh, struct ufs_request *req, char *buf);
-static void do_read(struct ext2 *fs, hid_t reqh, struct ufs_request *req, char *buf, size_t buflen);
-static void do_write(struct ext2 *fs, hid_t reqh, struct ufs_request *req, char *buf);
-static void do_getsize(struct ext2 *fs, hid_t reqh, struct ufs_request *req);
-
-static int
-my_read(void *fp, void *buf, size_t len, size_t off)
-{
- if (fseek(fp, off, SEEK_SET) < 0) {
- return -1;
- } else if (fread(buf, len, 1, fp) == 1) {
- return 0;
- } else {
- return -1;
- }
-}
-
-static int
-my_write(void *fp, const void *buf, size_t len, size_t off)
-{
- if (fseek(fp, off, SEEK_SET) < 0) {
- return -1;
- } else if (fwrite(buf, len, 1, fp) == 1) {
- return 0;
- } else {
- return -1;
- }
-}
-
-static void
-do_open(struct ext2 *fs, hid_t reqh, struct ufs_request *req, char *buf)
-{
- bool is_dir = req->len == 0 || buf[req->len-1] == '/';
- uint32_t n = ext2c_walk(fs, buf, req->len);
- if (n == 0) {
- if (is_dir) {
- _sys_fs_respond(reqh, NULL, -ENOSYS, 0);
- return;
- }
- /* buf[0] == '/', strrchr != NULL */
- char *name = strrchr(buf, '/') + 1;
- uint32_t dir_n = ext2c_walk(fs, buf, name - buf);
- if (dir_n == 0) {
- _sys_fs_respond(reqh, NULL, -ENOENT, 0);
- return;
- }
- n = ext2_alloc_inode(fs, 0100700);
- if (n == 0) {
- _sys_fs_respond(reqh, NULL, -1, 0);
- return;
- }
- if (ext2_link(fs, dir_n, name, n, 1) < 0) {
- _sys_fs_respond(reqh, NULL, -1, 0);
- return;
- }
- } else {
- struct ext2d_inode *inode = ext2_req_inode(fs, n);
- if (!inode) {
- _sys_fs_respond(reqh, NULL, -ENOENT, 0);
- return;
- }
- int type = (inode->perms >> 12) & 0xF;
- ext2_dropreq(fs, inode, false);
-
- if ((type == 0x8 && is_dir) || (type == 0x4 && !is_dir)) {
- _sys_fs_respond(reqh, NULL, -ENOENT, 0);
- return;
- } else if (type != 0x8 && type != 0x4) {
- _sys_fs_respond(reqh, NULL, -ENOSYS, 0);
- return;
- }
- }
-
- struct handle *h = malloc(sizeof *h);
- if (!h) {
- _sys_fs_respond(reqh, NULL, -1, 0);
- return;
- }
- h->n = n;
- h->dir = is_dir;
- _sys_fs_respond(reqh, h, 0, 0);
-}
-
-static void
-do_read(struct ext2 *fs, hid_t reqh, struct ufs_request *req, char *buf, size_t buflen)
-{
- struct handle *h = req->id;
- if (!h->dir) {
- struct ext2d_inode *inode = ext2_req_inode(fs, h->n);
- if (!inode) goto err;
- fs_normslice(&req->offset, &req->capacity, inode->size_lower, false);
- ext2_dropreq(fs, inode, false);
-
- void *b = ext2_req_file(fs, h->n, &req->capacity, req->offset);
- if (b) {
- _sys_fs_respond(reqh, b, req->capacity, 0);
- ext2_dropreq(fs, b, false);
- } else if (req->capacity == 0) {
- /* set by ext2_req_file on EOF */
- _sys_fs_respond(reqh, b, 0, 0);
- } else goto err;
- } else {
- struct dirbuild db;
- char namebuf[257];
- if (req->capacity > buflen)
- req->capacity = buflen;
- dir_start(&db, req->offset, buf, buflen);
- for (struct ext2_diriter iter = {0}; ext2_diriter(&iter, fs, h->n); ) {
- if (iter.ent->namelen_lower == 1 && iter.ent->name[0] == '.') {
- continue;
- }
- if (iter.ent->namelen_lower == 2
- && iter.ent->name[0] == '.'
- && iter.ent->name[1] == '.')
- {
- continue;
- }
- if (iter.ent->type == 2) { /* dir */
- memcpy(namebuf, iter.ent->name, iter.ent->namelen_lower);
- namebuf[iter.ent->namelen_lower] = '/';
- dir_appendl(&db, namebuf, iter.ent->namelen_lower + 1);
- } else {
- dir_appendl(&db, iter.ent->name, iter.ent->namelen_lower);
- }
- }
- _sys_fs_respond(reqh, buf, dir_finish(&db), 0);
- }
- return;
-err:
- _sys_fs_respond(reqh, NULL, -1, 0);
-}
-
-static void
-do_write(struct ext2 *fs, hid_t reqh, struct ufs_request *req, char *buf)
-{
- struct handle *h = req->id;
- if (h->dir) goto err;
-
- struct ext2d_inode *inode = ext2_req_inode(fs, h->n);
- if (!inode) goto err;
- fs_normslice(&req->offset, &req->len, inode->size_lower, true);
- if ((req->flags & WRITE_TRUNCATE) || inode->size_lower < req->offset + req->len) {
- inode->size_lower = req->offset + req->len;
- if (ext2_dropreq(fs, inode, true) < 0) {
- goto err;
- }
- } else {
- ext2_dropreq(fs, inode, false);
- }
- inode = NULL;
-
- int ret = ext2_write(fs, h->n, buf, req->len, req->offset);
- _sys_fs_respond(reqh, NULL, ret, 0);
- return;
-err:
- _sys_fs_respond(reqh, NULL, -1, 0);
-}
-
-static void
-do_getsize(struct ext2 *fs, hid_t reqh, struct ufs_request *req) {
- struct handle *h = req->id;
- if (h->dir) goto err;
-
- struct ext2d_inode *inode = ext2_req_inode(fs, h->n);
- if (!inode) goto err;
- _sys_fs_respond(reqh, NULL, inode->size_lower, 0);
- ext2_dropreq(fs, inode, false);
- return;
-err:
- _sys_fs_respond(reqh, NULL, -1, 0);
-}
-
-int
-main(int argc, char **argv)
-{
- intr_set(NULL);
-
- if (argc < 2) errx(1, "bad usage");
- // TODO pread/pwrite for normal handles
- FILE *disk = fopen(argv[1], "r+");
- if (!disk) err(1, "couldn't open '%s'", argv[1]);
-
- struct e2device *dev = exc_init(my_read, my_write, (void*)disk);
- if (!dev) errx(1, "exc_init failed");
- struct ext2 *fs = ext2_opendev(dev, exc_req, exc_drop);
- if (!fs) errx(1, "ext2_opendev failed");
-
- const size_t buflen = 4096;
- char *buf = malloc(buflen);
- struct ufs_request req;
- for (;;) {
- hid_t reqh = ufs_wait(buf, buflen, &req);
- struct handle *h = req.id;
- if (reqh < 0) break;
- switch (req.op) {
- case VFSOP_OPEN:
- do_open(fs, reqh, &req, buf);
- break;
- case VFSOP_READ:
- do_read(fs, reqh, &req, buf, buflen);
- break;
- case VFSOP_WRITE:
- do_write(fs, reqh, &req, buf);
- break;
- case VFSOP_GETSIZE:
- do_getsize(fs, reqh, &req);
- break;
- case VFSOP_CLOSE:
- free(h);
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- default:
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
- }
- warnx("cleaning up");
-
- return 1;
-}
diff --git a/src/user/app/find/find.c b/src/user/app/find/find.c
deleted file mode 100644
index d473b82..0000000
--- a/src/user/app/find/find.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <camellia/path.h>
-#include <dirent.h>
-#include <err.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-void recurse(char *path) {
- DIR *d = opendir(path);
- if (!d) {
- warn("couldn't open %s", path);
- return;
- }
- for (;;) {
- struct dirent *dent;
- errno = 0;
- dent = readdir(d);
- if (!dent) {
- if (errno) {
- warn("when reading %s", path);
- }
- break;
- }
- printf("%s%s\n", path, dent->d_name);
- /* if the string ends with '/' */
- if (strchr(dent->d_name, '\0')[-1] == '/') {
- // TODO no overflow check
- char *pend = strchr(path, '\0');
- strcpy(pend, dent->d_name);
- recurse(path);
- *pend = '\0';
- }
- }
- closedir(d);
-}
-
-void find(const char *path) {
- // TODO bound checking
- // TODO or just implement asprintf()
- char *buf = malloc(PATH_MAX);
- memcpy(buf, path, strlen(path)+1);
- recurse(buf);
- free(buf);
-}
-
-int main(int argc, char **argv) {
- if (argc < 2) {
- find("/");
- } else {
- for (int i = 1; i < argc; i++)
- find(argv[i]);
- }
- return 0;
-}
diff --git a/src/user/app/httpd/httpd.c b/src/user/app/httpd/httpd.c
deleted file mode 100644
index 668e534..0000000
--- a/src/user/app/httpd/httpd.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* garbage httpd, just to see if it works
- * easily DoSable (like the rest of the network stack), vulnerable to path traversal, etc */
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <err.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-static void handle(FILE *c) {
- char buf[2048];
- fgets(buf, sizeof buf, c);
- printf("%s", buf);
-
- if (memcmp(buf, "GET /", 5) != 0) {
- fprintf(c, "HTTP/1.1 400 Bad Request\r\n\r\n");
- return;
- }
- char *path = buf + 4;
- char *end = strchr(path, ' ');
- if (end) *end = '\0';
-
- hid_t h = _sys_open(path, strlen(path), OPEN_READ);
- if (h < 0) {
- fprintf(c, "HTTP/1.1 404 Not Found\r\n\r\n");
- return;
- }
- FILE *f = fdopen(h, "r");
- if (!f) {
- fprintf(c, "HTTP/1.1 500 Internal Server Error\r\n\r\n");
- return;
- }
-
- if (path[strlen(path) - 1] != '/') {
- /* regular file */
- fprintf(c, "HTTP/1.1 200 OK\r\n");
- fprintf(c, "\r\n");
- for (;;) {
- int len = fread(buf, 1, sizeof buf, f);
- if (len <= 0) break;
- fwrite(buf, 1, len, c);
- }
- } else {
- /* directory listing */
- fprintf(c, "HTTP/1.1 200 OK\r\n");
- fprintf(c, "Content-Type: text/html; charset=UTF-8\r\n");
- fprintf(c, "\r\n");
- fprintf(c, "<h1>directory listing for %s</h1><hr><ul><li><a href=..>..</a></li>", path);
- for (;;) {
- int len = fread(buf, 1, sizeof buf, f);
- if (len <= 0) break;
- // TODO directory library
- // based on find.c
- for (int pos = 0; pos < len; ) {
- if (buf[pos] == '\0') break;
- const char *end = memchr(buf + pos, 0, len - pos);
- if (!end) break;
- fprintf(c, "<li><a href=\"%s\">%s</a></li>", buf + pos, buf + pos);
- pos += end - (buf + pos) + 1;
- }
- }
- }
- fclose(f);
-}
-
-int main(int argc, char **argv) {
- const char *path = (argc > 1) ? argv[1] : "/net/listen/0.0.0.0/tcp/80";
- hid_t conn;
- for (;;) {
- conn = _sys_open(path, strlen(path), OPEN_RW);
- if (conn < 0)
- errx(1, "open('%s') failed, errno %d", path, -conn);
- FILE *f = fdopen(conn, "a+");
- handle(f);
- fclose(f);
- }
-}
diff --git a/src/user/app/init/driver/driver.h b/src/user/app/init/driver/driver.h
deleted file mode 100644
index 98c18f1..0000000
--- a/src/user/app/init/driver/driver.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#pragma once
-#include <camellia/types.h>
-
-void initctl_drv(hid_t killswitch);
-void ps2_drv(void);
-void tmpfs_drv(void);
-
-void termcook(void);
diff --git a/src/user/app/init/driver/initctl.c b/src/user/app/init/driver/initctl.c
deleted file mode 100644
index fed71b7..0000000
--- a/src/user/app/init/driver/initctl.c
+++ /dev/null
@@ -1,44 +0,0 @@
-#include "driver.h"
-#include <camellia/syscalls.h>
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <camellia/compat.h>
-
-void initctl_drv(hid_t killswitch) {
- struct ufs_request res;
- char buf[64];
- const size_t buflen = sizeof buf;
- while (!c0_fs_wait(buf, buflen, &res)) {
- switch (res.op) {
- case VFSOP_OPEN:
- c0_fs_respond(NULL, res.len == 0 ? 0 : -1, 0);
- break;
- case VFSOP_WRITE:
- /* null terminate */
- if (res.len > buflen - 1)
- res.len = buflen - 1;
- buf[res.len] = '\0';
- /* cut at first whitespace */
- for (size_t i = 0; buf[i]; i++) {
- if (isspace(buf[i])) {
- buf[i] = '\0';
- break;
- }
- }
- if (!strcmp(buf, "halt")) {
- _sys_write(killswitch, "halt", 4, 0, 0);
- }
- if (!strcmp(buf, "intr")) {
- _sys_write(killswitch, "intr", 4, 0, 0);
- }
- c0_fs_respond(NULL, res.len, 0);
- break;
- default:
- c0_fs_respond(NULL, -ENOSYS, 0);
- break;
- }
- }
- exit(1);
-}
diff --git a/src/user/app/init/driver/ps2.c b/src/user/app/init/driver/ps2.c
deleted file mode 100644
index 5470249..0000000
--- a/src/user/app/init/driver/ps2.c
+++ /dev/null
@@ -1,129 +0,0 @@
-#include "driver.h"
-#include <assert.h>
-#include <camellia/compat.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <shared/ring.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <thread.h>
-
-
-static const char keymap_lower[] = {
- '\0', '\0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t',
- 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\r', '\0', 'a', 's',
- 'd', 'f', 'g', 'h', 'j', 'k', 'l', '\0', '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v',
- 'b', 'n', 'm', ',', '.', '/', '\0', '*', '\0', ' ', '\0', '\0', '\0', '\0', '\0', '\0',
- '\0', '\0', '\0', '\0', '\0', '\0', '\0', '7', '8', '9', '-', '4', '5', '6', '+', '1',
- '2', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
- '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
- '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
-};
-
-static const char keymap_upper[] = {
- '\0', '\0', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', '\t',
- 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\r', '\0', 'A', 'S',
- 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', '\0', '|', 'Z', 'X', 'C', 'V',
- 'B', 'N', 'M', '<', '>', '?', '\0', '*', '\0', ' ', '\0', '\0', '\0', '\0', '\0', '\0',
- '\0', '\0', '\0', '\0', '\0', '\0', '\0', '7', '8', '9', '-', '4', '5', '6', '+', '1',
- '2', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
- '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
- '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
-};
-
-
-static volatile uint8_t backlog_buf[16];
-static volatile ring_t backlog = {(void*)backlog_buf, sizeof backlog_buf, 0, 0};
-
-static hid_t fd;
-
-static bool keys[0x80] = {0};
-
-static void parse_scancode(uint8_t s) {
- bool ctrl = keys[0x1D];
- bool shift = keys[0x2A] || keys[0x36];
- bool down = !(s & 0x80);
- char c;
- s &= 0x7f;
- keys[s] = down;
-
- c = shift ? keymap_upper[s] : keymap_lower[s];
- if (ctrl && keymap_upper[s] >= 'A' && keymap_upper[s] <= 'Z')
- c = keymap_upper[s] - 'A' + 1;
- if (down && c) ring_put1b((void*)&backlog, c);
-}
-
-
-/** Is a thread waiting for /kdev/ps2/kb? */
-static volatile bool blocked = false;
-/* for use in read_thread */
-static hid_t rt_reqh;
-static size_t rt_cap;
-
-static void read_thread(void *unused) {
- char buf[512];
- (void)unused;
-
- assert(blocked);
- while (ring_used((void*)&backlog) == 0) {
- /* read raw input until we have something to output */
- int len = _sys_read(fd, buf, sizeof buf, 0);
- if (len == 0) break;
- for (int i = 0; i < len; i++)
- parse_scancode(buf[i]);
- }
- if (ring_used((void*)&backlog) > 0) {
- int ret = ring_get((void*)&backlog, buf, rt_cap);
- _sys_fs_respond(rt_reqh, buf, ret, 0);
- } else {
- _sys_fs_respond(rt_reqh, 0, -EGENERIC, 0);
- }
- blocked = false;
-}
-
-static void fs_loop(void) {
- static char buf[512];
- int ret;
- for (;;) {
- struct ufs_request res;
- hid_t reqh = _sys_fs_wait(buf, sizeof buf, &res);
- if (reqh < 0) return;
-
- switch (res.op) {
- case VFSOP_OPEN:
- if (res.len == 0) {
- _sys_fs_respond(reqh, NULL, 1, 0);
- } else {
- _sys_fs_respond(reqh, NULL, -ENOENT, 0);
- }
- break;
-
- case VFSOP_READ:
- if (blocked) {
- _sys_fs_respond(reqh, NULL, -EAGAIN, 0);
- break;
- } else if (ring_used((void*)&backlog) > 0) {
- ret = ring_get((void*)&backlog, buf, res.capacity);
- _sys_fs_respond(reqh, buf, ret, 0);
- } else {
- blocked = true;
- rt_reqh = reqh;
- rt_cap = res.capacity;
- thread_create(0, read_thread, 0);
- }
- break;
-
- default:
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
- }
-}
-
-void ps2_drv(void) {
- fd = _sys_open("/kdev/ps2/kb", 12, 0);
- if (fd < 0) exit(1);
-
- fs_loop();
- exit(0);
-}
diff --git a/src/user/app/init/driver/termcook.c b/src/user/app/init/driver/termcook.c
deleted file mode 100644
index a76f3a8..0000000
--- a/src/user/app/init/driver/termcook.c
+++ /dev/null
@@ -1,103 +0,0 @@
-#include "driver.h"
-#include <camellia/syscalls.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-enum tstate {
- Normal,
- Esc,
- CSI,
-};
-
-static void w_output(hid_t output, const char *buf, size_t len) {
- size_t pos = 0;
- while (pos < len) {
- int ret = _sys_write(output, buf + pos, len - pos, pos, 0);
- if (ret < 0) break;
- pos += ret;
- }
-}
-
-static void line_editor(hid_t input, hid_t output) {
- char readbuf[16], linebuf[256];
- size_t linepos = 0;
- enum tstate state = Normal;
- for (;;) {
- int readlen = _sys_read(input, readbuf, sizeof readbuf, -1);
- if (readlen < 0) return;
- for (int i = 0; i < readlen; i++) {
- char c = readbuf[i];
- switch (state) {
- case Normal:
- switch (c) {
- case '\b':
- case 0x7f:
- if (linepos != 0) {
- printf("\b \b");
- linepos--;
- }
- break;
- case 3: /* C-c */
- _sys_exit(1);
- case 4: /* EOT, C-d */
- if (linepos > 0) {
- w_output(output, linebuf, linepos);
- linepos = 0;
- } else {
- _sys_write(output, NULL, 0, 0, 0); /* EOF */
- }
- break;
- case '\n':
- case '\r':
- printf("\n");
- if (linepos < sizeof linebuf)
- linebuf[linepos++] = '\n';
- w_output(output, linebuf, linepos);
- linepos = 0;
- break;
- case '\e':
- state = Esc;
- break;
- case '\t':
- break;
- default:
- if (linepos < sizeof linebuf) {
- linebuf[linepos++] = c;
- printf("%c", c);
- }
- break;
- }
- break;
- case Esc:
- if (c == '[') state = CSI;
- else state = Normal;
- break;
- case CSI:
- if (0x40 <= c && c <= 0x7E) state = Normal;
- break;
- }
- }
- }
-}
-
-void termcook(void) {
- hid_t stdin_pipe[2] = {-1, -1};
- if (_sys_pipe(stdin_pipe, 0) < 0)
- return;
-
- if (!fork()) {
- /* the caller continues in a child process,
- * so it can be killed when the line editor quits */
- _sys_dup(stdin_pipe[0], 0, 0);
- close(stdin_pipe[0]);
- close(stdin_pipe[1]);
- return;
- }
- if (!fork()) {
- close(stdin_pipe[0]);
- line_editor(0, stdin_pipe[1]);
- exit(0);
- }
- exit(_sys_await());
-}
diff --git a/src/user/app/init/init.c b/src/user/app/init/init.c
deleted file mode 100644
index fcebfc7..0000000
--- a/src/user/app/init/init.c
+++ /dev/null
@@ -1,151 +0,0 @@
-#include "driver/driver.h"
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <camellia/fs/misc.h>
-
-#define die(fmt, ...) do { fprintf(stderr, "init: " fmt, __VA_ARGS__); exit(1); } while (0)
-
-static char title[128];
-
-void redirect(const char *exe, const char *out, const char *in) {
- if (!fork()) {
- snprintf(title, sizeof title, "sh >%s", out);
- setproctitle(title);
-
- if (!freopen(out, "a+", stderr)) {
- fprintf(stdout, "couldn't open %s\n", out);
- exit(1);
- }
- if (!freopen(out, "a+", stdout))
- die("couldn't open %s\n", out);
- if (!freopen(in, "r", stdin))
- die(" couldn't open %s\n", in);
-
- for (;;) {
- if (!fork()) {
- const char *argv[] = {exe, NULL};
- termcook();
- execv(exe, (void*)argv);
- fprintf(stderr, "init: couldn't start %s\n", exe);
- _sys_sleep(5000);
- exit(1);
- }
- _sys_await();
- _sys_intr();
- }
- }
-}
-
-int main(void) {
- const char *teststr = "I am teststr.\n";
- hid_t killswitch_pipe[2];
-
- freopen("/kdev/com1", "a+", stdout);
- freopen("/kdev/com1", "a+", stderr);
- printf("[init] stage 2, main at %p, teststr at %p\n", &main, teststr);
-
- MOUNT_AT("/") {
- fs_dirinject2((const char*[]){
- "/keyboard/",
- "/usr/",
- "/bin/",
- "/Users/",
- "/tmp/",
- "/vtty",
- "/net/",
- "/initctl",
- NULL
- });
- }
-
- MOUNT_AT("/keyboard") {
- MOUNT_AT("/") { fs_whitelist((const char*[]){"/kdev/ps2/kb", NULL}); }
- ps2_drv();
- }
- MOUNT_AT("/usr/") {
- fs_union((const char*[]){
- "/init/usr/",
- NULL
- });
- }
- MOUNT_AT("/bin/") {
- fs_union((const char*[]){
- "/init/bin/amd64/",
- "/init/bin/sh/",
- "/init/usr/bin/",
- "/init/usr/local/bin/",
- NULL
- });
- }
- MOUNT_AT("/Users/") {
- MOUNT_AT("/tmp/") {
- const char *argv[] = {"/bin/tmpfs", NULL};
- execv(argv[0], (void*)argv);
- }
- // TODO a simple union isn't enough here
- fs_union((const char*[]){
- "/tmp/",
- "/init/Users/",
- NULL
- });
- }
- MOUNT_AT("/tmp/") {
- const char *allow[] = {"/bin/tmpfs", NULL};
- const char *argv[] = {"/bin/tmpfs", NULL};
- MOUNT_AT("/") { fs_whitelist(allow); }
- execv(argv[0], (void*)argv);
- }
- MOUNT_AT("/vtty") {
- const char *allow[] = {"/bin/vterm", "/kdev/video/", "/keyboard", "/init/usr/share/fonts/", NULL};
- const char *argv[] = {"/bin/vterm", NULL};
- MOUNT_AT("/") { fs_whitelist(allow); }
- execv(argv[0], (void*)argv);
- }
- MOUNT_AT("/net/") {
- const char *allow[] = {"/bin/netstack", "/kdev/eth", NULL};
- const char *argv[] = {"/bin/netstack", "/kdev/eth", "192.168.0.11", "192.168.0.2", NULL};
- MOUNT_AT("/") { fs_whitelist(allow); }
- execv(argv[0], (void*)argv);
- }
-
- if (_sys_pipe(killswitch_pipe, 0) < 0) {
- printf("couldn't create the killswitch pipe, quitting...\n");
- return 1;
- }
- MOUNT_AT("/initctl") {
- close(killswitch_pipe[0]);
- initctl_drv(killswitch_pipe[1]);
- }
- close(killswitch_pipe[1]);
-
- if (!fork()) {
- // TODO close on exec
- close(killswitch_pipe[0]);
- redirect("/bin/shell", "/kdev/com1", "/kdev/com1");
- redirect("/bin/shell", "/vtty", "/keyboard");
- exit(1);
- }
-
- char buf[128];
- for (;;) {
- if (_sys_read(killswitch_pipe[0], buf, 128, 0) != 4) {
- break;
- }
- if (memcmp(buf, "intr", 4) == 0) {
- _sys_intr();
- } else if (memcmp(buf, "halt", 4) == 0) {
- break;
- }
- }
- printf("[init] intr\n");
- _sys_intr();
- _sys_sleep(1000);
- printf("[init] filicide\n");
- _sys_filicide();
- printf("[init] goodbye\n");
- return 0;
-}
diff --git a/src/user/app/iochk/iochk.c b/src/user/app/iochk/iochk.c
deleted file mode 100644
index 0850821..0000000
--- a/src/user/app/iochk/iochk.c
+++ /dev/null
@@ -1,97 +0,0 @@
-#include <assert.h>
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-static bool verbose = false;
-
-#define verbosef(...) do { if (verbose) printf(__VA_ARGS__); } while (0)
-#define eprintf(fmt, ...) fprintf(stderr, "iochk: "fmt"\n" __VA_OPT__(,) __VA_ARGS__)
-
-
-void check(hid_t h) {
- const size_t buflen = 4096;
- const size_t offsets[] = {
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 16, 32, 64, 128, 256,
- 512, 1024, 2048,
- };
- char *buflast = malloc(buflen);
- char *bufcur = malloc(buflen);
- if (!buflast || !bufcur) {
- eprintf("out of memory");
- goto end;
- }
-
- long offlast = 0;
- long retlast = _sys_read(h, buflast, buflen, offlast);
- if (retlast < 0) {
- eprintf("error %ld when reading at offset %ld", retlast, offlast);
- goto end;
- }
-
- for (size_t i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
- char *tmp;
- long offcur = offsets[i];
- long diff = offcur - offlast;
- assert(diff >= 0);
- if (retlast < diff) break;
-
- long retcur = _sys_read(h, bufcur, buflen, offcur);
- if (retcur < 0) {
- eprintf("error %ld when reading at offset %ld", retlast, offcur);
- break;
- }
- if (retcur < retlast + offlast - offcur) {
- verbosef("warn: unexpected ret %ld < %ld + %ld - %ld\n", retcur, retlast, offlast, offcur);
- }
- if (memcmp(buflast + diff, bufcur, retlast - diff)) {
- eprintf("inconsistent read from offsets %ld and %ld", offlast, offcur);
- }
-
- offlast = offcur;
- retlast = retcur;
- tmp = bufcur;
- bufcur = buflast;
- buflast = tmp;
- }
-
- // TODO check negative offsets
-
-end:
- free(buflast);
- free(bufcur);
-}
-
-int main(int argc, char **argv) {
- int c;
- while ((c = getopt(argc, argv, "v")) != -1) {
- switch (c) {
- case 'v':
- verbose = true;
- break;
- default:
- return 1;
- }
- }
- if (optind >= argc) {
- eprintf("no files given");
- return 1;
- }
- for (; optind < argc; optind++) {
- const char *path = argv[optind];
- verbosef("checking %s...\n", path);
- hid_t h = camellia_open(path, OPEN_READ);
- if (h < 0) {
- eprintf("couldn't open %s", path);
- continue;
- }
- check(h);
- close(h);
- }
- return 0;
-}
diff --git a/src/user/app/iostress/iostress.c b/src/user/app/iostress/iostress.c
deleted file mode 100644
index ac555de..0000000
--- a/src/user/app/iostress/iostress.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <x86intrin.h>
-
-int main(int argc, char **argv) {
- long num_runs = 4;
- long num_calls = 512;
- long num_bytes = 1;
- uint64_t *results;
- char *inbuf;
-
- if (argc > 1) num_runs = strtol(argv[1], NULL, 0);
- if (argc > 2) num_calls = strtol(argv[2], NULL, 0);
- if (argc > 3) num_bytes = strtol(argv[3], NULL, 0);
- if (argc > 4 || num_runs == 0 || num_calls == 0) {
- fprintf(stderr, "usage: %s [num_runs] [num_calls] [num_bytes]\n", argv[0]);
- return 1;
- }
-
- results = malloc(sizeof(*results) * num_runs);
- inbuf = malloc(num_bytes);
- memset(inbuf, '.', num_bytes);
-
- for (long i = 0; i < num_runs; i++) {
- uint64_t time = __rdtsc();
- for (long j = 0; j < num_calls; j++)
- _sys_write(1, inbuf, num_bytes, -1, 0);
- results[i] = __rdtsc() - time;
- _sys_write(1, "\n", 1, -1, 0);
- }
-
- uint64_t total = 0;
- for (long i = 0; i < num_runs; i++) {
- uint64_t scaled = results[i] / 3000;
- total += scaled;
- fprintf(stderr, "run %ld: %lu\n", i, scaled);
- }
- fprintf(stderr, "%lu calls, %lu bytes. avg %lu\n", num_calls, num_bytes, total / num_runs);
-
- return 0;
-}
diff --git a/src/user/app/logfs/logfs.c b/src/user/app/logfs/logfs.c
deleted file mode 100644
index a50d530..0000000
--- a/src/user/app/logfs/logfs.c
+++ /dev/null
@@ -1,34 +0,0 @@
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <camellia/fs/misc.h>
-
-_Noreturn void fs(void) {
- const size_t buflen = 1024;
- char *buf = malloc(buflen);
- if (!buf) err(1, "malloc");
- for (;;) {
- struct ufs_request req;
- hid_t reqh = ufs_wait(buf, buflen, &req);
- if (reqh < 0) errx(1, "ufs_wait error");
-
- switch (req.op) {
- case VFSOP_OPEN:
- printf("[logfs] open(\"%s\", 0x%x)\n", buf, req.flags);
- forward_open(reqh, buf, req.len, req.flags);
- break;
- default:
- /* Unsupported vfs operation.
- * Currently if you never create your own file descriptors you won't receive
- * anything but VFSOP_OPEN, but it's idiomatic to handle this anyways. */
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
- }
-}
-
-int main(void) {
- fs();
-}
diff --git a/src/user/app/login/login.c b/src/user/app/login/login.c
deleted file mode 100644
index 0f9e8b7..0000000
--- a/src/user/app/login/login.c
+++ /dev/null
@@ -1,89 +0,0 @@
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <camellia/fs/misc.h>
-
-static const char *shell = "/bin/shell";
-
-static void cutspace(char *s) {
- for (; *s; s++) {
- if (isspace(*s)) {
- *s = '\0';
- break;
- }
- }
-}
-
-static bool segcmp(const char *path, int idx, const char *s2) {
- if (idx < 0) return false;
- while (idx > 0) {
- if (*path == '\0') return false;
- if (*path == '/') idx--;
- path++;
- }
- /* path is at the start of the selected segment */
- while (*s2 && *path++ == *s2++);
- return (*path == '\0' || *path == '/') && *s2 == '\0';
-}
-
-static void drv(const char *user) {
- char *buf = malloc(PATH_MAX);
- for (;;) {
- struct ufs_request req;
- hid_t reqh = ufs_wait(buf, PATH_MAX, &req);
- if (reqh < 0) break;
- switch (req.op) {
- case VFSOP_OPEN:
- if (segcmp(buf, 1, "Users") && segcmp(buf, 2, user)) { // /Users/$user/**
- forward_open(reqh, buf, req.len, req.flags);
- } else if (segcmp(buf, 1, "Users") && segcmp(buf, 3, "private")) { // /Users/*/private/**
- _sys_fs_respond(reqh, NULL, -EACCES, 0);
- } else if (!OPEN_WRITEABLE(req.flags)) {
- forward_open(reqh, buf, req.len, req.flags);
- } else {
- _sys_fs_respond(reqh, NULL, -EACCES, 0);
- }
- break;
-
- default:
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
- }
- free(buf);
-}
-
-static void trylogin(const char *user) {
- if (strcmp(user, "root") != 0) {
- char buf[128];
- snprintf(buf, sizeof buf, "/Users/%s/", user);
- if (chdir(buf) < 0) {
- printf("no such user: %s\n", user);
- return;
- }
- MOUNT_AT("/") { drv(user); }
- }
-
- execv(shell, NULL);
- fprintf(stderr, "login: couldn't launch %s\n", shell);
- exit(1);
-}
-
-int main(void) {
- char user[64];
- printf("\nCamellia\n");
- for (;;) {
- printf("login: ");
- fgets(user, sizeof user, stdin);
- if (ferror(stdin)) return -1;
-
- cutspace(user);
- if (user[0]) trylogin(user);
- }
-}
diff --git a/src/user/app/netdog/nd.c b/src/user/app/netdog/nd.c
deleted file mode 100644
index af5c264..0000000
--- a/src/user/app/netdog/nd.c
+++ /dev/null
@@ -1,48 +0,0 @@
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <stdio.h>
-#include <string.h>
-#include <thread.h>
-
-#define eprintf(fmt, ...) fprintf(stderr, "netdog: "fmt"\n" __VA_OPT__(,) __VA_ARGS__)
-
-hid_t conn;
-
-void send_stdin(void *arg) { (void)arg;
- static char buf[4096];
- for (;;) {
- // TODO define STDIN_FILENO
- long ret = _sys_read(0, buf, sizeof buf, -1);
- if (ret <= 0) return; /* instead of sending an empty packet, quit. */
- ret = _sys_write(conn, buf, ret, -1, 0);
- if (ret < 0) return;
- }
-}
-
-void recv_stdout(void *arg) { (void)arg;
- static char buf[4096];
- for (;;) {
- long ret = _sys_read(conn, buf, sizeof buf, -1);
- if (ret < 0) return;
- ret = _sys_write(1, buf, ret, -1, 0);
- if (ret < 0) return;
- }
-}
-
-int main(int argc, char **argv) {
- if (argc < 2) {
- eprintf("no argument");
- return 1;
- }
-
- conn = camellia_open(argv[1], OPEN_RW);
- if (conn < 0) {
- eprintf("couldn't open '%s', err %u", argv[1], -conn);
- return -conn;
- }
-
- thread_create(0, send_stdin, NULL);
- thread_create(0, recv_stdout, NULL);
- _sys_await();
- return 0;
-}
diff --git a/src/user/app/netstack/arp.c b/src/user/app/netstack/arp.c
deleted file mode 100644
index 3a1c8da..0000000
--- a/src/user/app/netstack/arp.c
+++ /dev/null
@@ -1,151 +0,0 @@
-#include "proto.h"
-#include "util.h"
-#include <assert.h>
-#include <camellia/syscalls.h>
-#include <string.h>
-
-enum {
- HdrType = 0,
- HdrTypeEther = 1,
- ProtoType = 2,
- HdrALen = 4,
- ProtoALen = 5,
- Operation = 6,
- OpReq = 1,
- OpReply = 2,
-};
-
-struct arpc {
- struct arpc *next;
- uint32_t ip;
- mac_t mac;
-};
-static struct arpc *arpcache;
-static void arpcache_put(uint32_t ip, mac_t mac);
-
-void arp_parse(const uint8_t *buf, size_t len) {
- if (len < Operation + 2) return;
- uint16_t htype = nget16(buf + HdrType);
- uint16_t ptype = nget16(buf + ProtoType);
- uint16_t op = nget16(buf + Operation);
-
- if (!(htype == HdrTypeEther && ptype == ET_IPv4)) return;
- enum { /* only valid for this combination of header + proto */
- SrcMAC = 8,
- SrcIP = 14,
- DstMAC = 18,
- DstIP = 24,
- };
- if (len < DstIP + 4) return;
- arpcache_put(nget32(buf + SrcIP), *(mac_t*)buf + SrcMAC);
-
- if (op == OpReq) {
- uint32_t daddr = nget32(buf + DstIP);
- if (daddr == state.ip) {
- uint8_t *pkt = ether_start(30, (struct ethernet){
- .dst = (void*)(buf + SrcMAC),
- .type = ET_ARP,
- });
- nput16(pkt + HdrType, HdrTypeEther);
- nput16(pkt + ProtoType, ET_IPv4);
- pkt[HdrALen] = 6;
- pkt[ProtoALen] = 4;
- nput16(pkt + Operation, OpReply);
- memcpy(pkt + SrcMAC, state.mac, 6);
- nput32(pkt + SrcIP, state.ip);
- memcpy(pkt + DstMAC, buf + SrcMAC, 10); /* sender's MAC and IP */
- ether_finish(pkt);
- }
- }
-}
-
-void arp_request(uint32_t ip) {
- enum {
- SrcMAC = 8,
- SrcIP = 14,
- DstMAC = 18,
- DstIP = 24,
- };
- uint8_t *pkt = ether_start(28, (struct ethernet){
- .src = &state.mac,
- .dst = &MAC_BROADCAST,
- .type = ET_ARP,
- });
- nput16(pkt + HdrType, HdrTypeEther);
- nput16(pkt + ProtoType, ET_IPv4);
- pkt[HdrALen] = 6;
- pkt[ProtoALen] = 4;
- nput16(pkt + Operation, OpReq);
- memcpy(pkt + SrcMAC, state.mac, 6);
- nput32(pkt + SrcIP, state.ip);
- memcpy(pkt + DstMAC, &MAC_BROADCAST, 6);
- nput32(pkt + DstIP, ip);
- ether_finish(pkt);
-}
-
-static void arpcache_put(uint32_t ip, mac_t mac) {
- for (struct arpc *iter = arpcache; iter; iter = iter->next) {
- if (memcmp(iter->mac, mac, 6) == 0) {
- if (iter->ip == ip) return; /* cache entry correct */
- else break; /* cache entry needs updating */
- }
- }
- struct arpc *e = malloc(sizeof *e);
- e->next = arpcache;
- e->ip = ip;
- memcpy(e->mac, mac, 6);
- arpcache = e;
-}
-
-int arpcache_get(uint32_t ip, mac_t *mac) {
- for (struct arpc *iter = arpcache; iter; iter = iter->next) {
- if (iter->ip == ip) {
- if (mac) memcpy(mac, iter->mac, 6);
- return 0;
- }
- }
- return -1;
-}
-
-void arp_fsread(hid_t h, long offset) {
- const char *fmt = "%08x\t%02x:%02x:%02x:%02x:%02x:%02x\n";
- long linelen = snprintf(NULL, 0, fmt, 0, 1, 2, 3, 4, 5, 6) + 1;
- char buf[28];
- assert(linelen <= (long)sizeof(buf));
- if (offset < 0) goto err;
-
- struct arpc *cur = arpcache;
- if (!cur) goto err;
- for (; linelen <= offset; offset -= linelen) {
- cur = cur->next;
- if (!cur) goto err;
- }
- assert(0 <= offset && offset < linelen);
-
- snprintf(buf, sizeof buf, fmt, cur->ip,
- cur->mac[0],
- cur->mac[1],
- cur->mac[2],
- cur->mac[3],
- cur->mac[4],
- cur->mac[5]);
- _sys_fs_respond(h, buf + offset, linelen - offset, 0);
- return;
-err:
- _sys_fs_respond(h, NULL, -1, 0);
-}
-
-long arp_fswrite(const char *buf, long len, long offset) {
- if (offset != -1) return -1;
- uint32_t ip;
- char tmp[16];
- size_t iplen = len < 15 ? len : 15;
- memcpy(tmp, buf, iplen);
- tmp[iplen] = '\0';
- if (ip_parse(tmp, &ip) < 0) {
- return -1;
- } else {
- arp_request(ip);
- return len;
- }
-}
diff --git a/src/user/app/netstack/ether.c b/src/user/app/netstack/ether.c
deleted file mode 100644
index 52abac2..0000000
--- a/src/user/app/netstack/ether.c
+++ /dev/null
@@ -1,59 +0,0 @@
-#include <camellia/syscalls.h>
-#include "proto.h"
-#include "util.h"
-
-enum {
- DstMAC = 0,
- SrcMAC = 6,
- EtherType = 12,
- Payload = 14,
-};
-struct ethq *ether_queue;
-
-void ether_parse(const uint8_t *buf, size_t len) {
- struct ethernet ether = (struct ethernet){
- .src = (void*)(buf + SrcMAC),
- .dst = (void*)(buf + DstMAC),
- .type = nget16(buf + EtherType),
- };
-
- for (struct ethq **iter = &ether_queue; iter && *iter; ) {
- struct ethq *qe = *iter;
- _sys_fs_respond(qe->h, buf, len, 0);
- /* remove entry */
- /* yes, doing it this way here doesn't make sense. i'm preparing for filtering */
- *iter = qe->next;
- free(qe);
- }
-
- switch (ether.type) {
- case ET_IPv4:
- ipv4_parse(buf + Payload, len - Payload, ether);
- break;
- case ET_ARP:
- arp_parse(buf + Payload, len - Payload);
- break;
- }
-}
-
-static const size_t fhoff = sizeof(size_t);
-uint8_t *ether_start(size_t len, struct ethernet ether) {
- if (len < 60 - Payload) len = 60 - Payload;
-
- if (!ether.dst) eprintf("NULL ether.dst!"); // TODO arp? i guess?
- if (!ether.src) ether.src = &state.mac;
-
- uint8_t *buf = malloc(fhoff + Payload + len);
- memset(buf, 0, fhoff + Payload + len);
- *(size_t*)buf = len + Payload;
- memcpy(buf + fhoff + DstMAC, ether.dst, 6);
- memcpy(buf + fhoff + SrcMAC, ether.src, 6);
- nput16(buf + fhoff + EtherType, ether.type);
- return buf + fhoff + Payload;
-}
-void ether_finish(uint8_t *pkt) {
- uint8_t *buf = pkt - Payload - fhoff;
- size_t len = *(size_t*)buf;
- _sys_write(state.raw_h, buf + fhoff, len, 0, 0);
- free(buf);
-}
diff --git a/src/user/app/netstack/fs.c b/src/user/app/netstack/fs.c
deleted file mode 100644
index 6d51c35..0000000
--- a/src/user/app/netstack/fs.c
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * path format:
- * /net/raw
- * raw ethernet frames (read-write)
- * /net/arp
- * ARP cache (currently read-only)
- * /net/connect/0.0.0.0/1.2.3.4/udp/53
- * connect from 0.0.0.0 (any ip) to 1.2.3.4 on udp port 53
- * /net/listen/0.0.0.0/{tcp,udp}/53
- * waits for a connection to any ip on udp port 53
- * open() returns once a connection to ip 0.0.0.0 on udp port 53 is received
- */
-#include "proto.h"
-#include "util.h"
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-enum handle_type {
- H_ETHER,
- H_TCP,
- H_UDP,
- H_ARP,
-};
-
-struct strqueue {
- struct strqueue *next;
- size_t len;
- char buf[];
-};
-
-struct handle {
- enum handle_type type;
- struct {
- struct udp_conn *c;
- struct strqueue *rx, *rxlast;
- } udp;
- struct {
- struct tcp_conn *c;
- size_t readcap;
- } tcp;
- bool dead;
- hid_t reqh;
-};
-
-
-static void tcp_listen_callback(struct tcp_conn *c, void *arg) {
- struct handle *h = arg;
- h->tcp.c = c;
- _sys_fs_respond(h->reqh, h, 0, 0);
- h->reqh = -1;
-}
-
-/* also called from recv_enqueue. yes, it's a mess */
-static void tcp_recv_callback(void *arg) {
- struct handle *h = arg;
- char buf[1024];
- if (h->reqh >= 0) {
- if (h->tcp.readcap > sizeof buf)
- h->tcp.readcap = sizeof buf;
- size_t len = tcpc_tryread(h->tcp.c, buf, h->tcp.readcap);
- if (len > 0) {
- _sys_fs_respond(h->reqh, buf, len, 0);
- h->reqh = -1;
- }
- }
-}
-
-static void tcp_close_callback(void *arg) {
- struct handle *h = arg;
- h->dead = true;
- if (h->reqh >= 0) {
- _sys_fs_respond(h->reqh, NULL, -ECONNRESET, 0);
- h->reqh = -1;
- return;
- }
-}
-
-static void udp_listen_callback(struct udp_conn *c, void *arg) {
- struct handle *h = arg;
- h->udp.c = c;
- _sys_fs_respond(h->reqh, h, 0, 0);
- h->reqh = -1;
-}
-
-static void udp_recv_callback(const void *buf, size_t len, void *arg) {
- struct handle *h = arg;
- if (h->reqh >= 0) {
- _sys_fs_respond(h->reqh, buf, len, 0);
- h->reqh = -1;
- return;
- }
- struct strqueue *sq = malloc(sizeof(*sq) + len);
- sq->next = NULL;
- sq->len = len;
- memcpy(sq->buf, buf, len);
- if (h->udp.rx) {
- h->udp.rxlast->next = sq;
- h->udp.rxlast = sq;
- } else {
- h->udp.rx = sq;
- h->udp.rxlast = sq;
- }
-}
-
-static void recv_enqueue(struct handle *h, hid_t reqh, size_t readcap) {
- if (h->reqh > 0) {
- // TODO queue
- _sys_fs_respond(reqh, NULL, -1, 0);
- return;
- }
- if (h->type == H_UDP && h->udp.rx) {
- _sys_fs_respond(reqh, h->udp.rx->buf, h->udp.rx->len, 0);
- h->udp.rx = h->udp.rx->next;
- free(h->udp.rx);
- return;
- }
- h->reqh = reqh;
- if (h->type == H_TCP) {
- h->tcp.readcap = readcap;
- tcp_recv_callback(h);
- }
-}
-
-static void fs_open(hid_t reqh, char *path, int flags) {
-#define respond(buf, val) do{ _sys_fs_respond(reqh, buf, val, 0); return; }while(0)
- struct handle *h;
- if (*path != '/') respond(NULL, -1);
- path++;
-
- if (strcmp(path, "raw") == 0) {
- h = malloc(sizeof *h);
- memset(h, 0, sizeof *h);
- h->type = H_ETHER;
- respond(h, 0);
- } else if (strcmp(path, "arp") == 0) {
- h = malloc(sizeof *h);
- memset(h, 0, sizeof *h);
- h->type = H_ARP;
- respond(h, 0);
- }
-
- /* everything below ends up sending packets */
- if (!OPEN_WRITEABLE(flags))
- respond(NULL, -EACCES);
-
- char *save;
- const char *verb, *proto, *port_s;
- uint32_t srcip, dstip;
-
- verb = strtok_r(path, "/", &save);
- if (!verb) respond(NULL, -1);
-
- if (ip_parse(strtok_r(NULL, "/", &save), &srcip) < 0)
- respond(NULL, -1);
- if (srcip != 0) {
- eprintf("unimplemented");
- respond(NULL, -1);
- }
-
- if (strcmp(verb, "listen") == 0) {
- proto = strtok_r(NULL, "/", &save);
- if (!proto) respond(NULL, -1);
- if (strcmp(proto, "udp") == 0) {
- port_s = strtok_r(NULL, "/", &save);
- if (port_s) {
- uint16_t port = strtol(port_s, NULL, 0);
- h = malloc(sizeof *h);
- memset(h, 0, sizeof *h);
- h->type = H_UDP;
- h->reqh = reqh;
- udp_listen(port, udp_listen_callback, udp_recv_callback, h);
- return;
- }
- }
- if (strcmp(proto, "tcp") == 0) {
- port_s = strtok_r(NULL, "/", &save);
- if (port_s) {
- uint16_t port = strtol(port_s, NULL, 0);
- h = malloc(sizeof *h);
- memset(h, 0, sizeof *h);
- h->type = H_TCP;
- h->reqh = reqh;
- tcp_listen(port, tcp_listen_callback, tcp_recv_callback, tcp_close_callback, h);
- return;
- }
- }
- } else if (strcmp(verb, "connect") == 0) {
- if (ip_parse(strtok_r(NULL, "/", &save), &dstip) < 0)
- respond(NULL, -1);
- proto = strtok_r(NULL, "/", &save);
- if (!proto) respond(NULL, -1);
- if (strcmp(proto, "tcp") == 0) {
- port_s = strtok_r(NULL, "/", &save);
- if (port_s) {
- uint16_t port = strtol(port_s, NULL, 0);
- h = malloc(sizeof *h);
- memset(h, 0, sizeof *h);
- h->type = H_TCP;
- h->tcp.c = tcpc_new((struct tcp){
- .dst = port,
- .ip.dst = dstip,
- }, tcp_recv_callback, tcp_close_callback, h);
- if (h->tcp.c) {
- respond(h, 0);
- } else {
- free(h);
- respond(NULL, -1);
- }
- }
- }
- if (strcmp(proto, "udp") == 0) {
- port_s = strtok_r(NULL, "/", &save);
- if (port_s) {
- uint16_t port = strtol(port_s, NULL, 0);
- h = malloc(sizeof *h);
- memset(h, 0, sizeof *h);
- h->type = H_UDP;
- h->udp.c = udpc_new((struct udp){
- .dst = port,
- .ip.dst = dstip,
- }, udp_recv_callback, h);
- if (h->udp.c) {
- respond(h, 0);
- } else {
- free(h);
- respond(NULL, -1);
- }
- }
- }
- }
- respond(NULL, -1);
-#undef respond
-}
-
-void fs_thread(void *arg) { (void)arg;
- const size_t buflen = 4096;
- char *buf = malloc(buflen);
- for (;;) {
- struct ufs_request res;
- hid_t reqh = _sys_fs_wait(buf, buflen, &res);
- if (reqh < 0) break;
- struct handle *h = res.id;
- long ret;
- switch (res.op) {
- case VFSOP_OPEN:
- if (res.len < buflen) {
- buf[res.len] = '\0';
- fs_open(reqh, buf, res.flags);
- } else {
- _sys_fs_respond(reqh, NULL, -1, 0);
- }
- break;
- case VFSOP_READ:
- if (h->dead) {
- _sys_fs_respond(reqh, NULL, -ECONNRESET, 0);
- break;
- }
- switch (h->type) {
- case H_ETHER: {
- struct ethq *qe;
- qe = malloc(sizeof *qe);
- qe->h = reqh;
- qe->next = ether_queue;
- ether_queue = qe;
- break;}
- case H_TCP:
- case H_UDP:
- recv_enqueue(h, reqh, res.capacity);
- break;
- case H_ARP:
- arp_fsread(reqh, res.offset);
- break;
- default:
- _sys_fs_respond(reqh, NULL, -1, 0);
- }
- break;
- case VFSOP_WRITE:
- if (h->dead) {
- _sys_fs_respond(reqh, NULL, -ECONNRESET, 0);
- break;
- }
- switch (h->type) {
- case H_ETHER:
- ret = _sys_write(state.raw_h, buf, res.len, 0, 0);
- _sys_fs_respond(reqh, NULL, ret, 0);
- break;
- case H_TCP:
- tcpc_send(h->tcp.c, buf, res.len);
- _sys_fs_respond(reqh, NULL, res.len, 0);
- break;
- case H_UDP:
- udpc_send(h->udp.c, buf, res.len);
- _sys_fs_respond(reqh, NULL, res.len, 0);
- break;
- case H_ARP:
- _sys_fs_respond(reqh, NULL, arp_fswrite(buf, res.len, res.offset), 0);
- break;
- default:
- _sys_fs_respond(reqh, NULL, -1, 0);
- }
- break;
- case VFSOP_CLOSE:
- // TODO remove entries in queue
- // TODO why does close even have _sys_fs_respond?
- if (h->type == H_TCP) tcpc_close(h->tcp.c);
- if (h->type == H_UDP) udpc_close(h->udp.c);
- free(h);
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- default:
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
- }
- free(buf);
-}
diff --git a/src/user/app/netstack/icmp.c b/src/user/app/netstack/icmp.c
deleted file mode 100644
index 0c6a502..0000000
--- a/src/user/app/netstack/icmp.c
+++ /dev/null
@@ -1,34 +0,0 @@
-#include "proto.h"
-#include "util.h"
-
-enum {
- Type = 0,
- Code = 1,
- Checksum = 2,
- Payload = 4,
-};
-
-void icmp_parse(const uint8_t *buf, size_t len, struct ipv4 ip) {
- if (len < Payload) return;
- uint8_t type = buf[Type];
- if (type == 8 && ip.dst == state.ip) {
- /* echo reply */
- icmp_send(buf + Payload, len - Payload, (struct icmp){
- .type = 0,
- .ip.dst = ip.src,
- .ip.e.dst = ip.e.src,
- });
- }
-}
-
-void icmp_send(const void *payload, size_t len, struct icmp i) {
- i.ip.proto = 1;
- uint8_t *pkt = malloc(Payload + len);
- pkt[Type] = i.type;
- pkt[Code] = i.code;
- memcpy(pkt + Payload, payload, len);
- nput16(pkt + Checksum, 0);
- nput16(pkt + Checksum, ip_checksum(pkt, Payload + len));
- ipv4_send(pkt, Payload + len, i.ip);
- free(pkt);
-}
diff --git a/src/user/app/netstack/ipv4.c b/src/user/app/netstack/ipv4.c
deleted file mode 100644
index 1336dc1..0000000
--- a/src/user/app/netstack/ipv4.c
+++ /dev/null
@@ -1,216 +0,0 @@
-#include "proto.h"
-#include "util.h"
-#include <assert.h>
-#include <stdlib.h>
-
-enum {
- Version = 0,
- HdrLen = 0,
- TotalLen = 2,
- Id = 4,
- FragInfo = 6,
- EvilBit = 0x8000,
- DontFrag = 0x4000,
- MoreFrags = 0x2000,
- FragOff = 0x1FFF,
- TTL = 8,
- Proto = 9,
- Checksum = 10,
- SrcIP = 12,
- DstIP = 16,
-};
-static void ipv4_dispatch(const uint8_t *buf, size_t len, struct ipv4 ip);
-
-struct fragment {
- struct fragment *next; /* sorted */
- size_t len, offset;
- bool last;
- uint8_t buf[];
-};
-struct fragmented {
- /* src, dst, proto, id come from the first arrived packet
- * and are used to tell fragmenteds apart.
- * the rest comes from the sequentially first packet.
- * ip.h.header points to a malloc'd buffer*/
- struct ipv4 h;
-
- struct fragment *first;
- struct fragmented *next, **prev; /* *(inc->prev) == inc */
- // TODO timer
-};
-struct fragmented *fragmenteds;
-static struct fragmented *fragmented_find(struct ipv4 fraghdr);
-static void fragmented_tryinsert(const uint8_t *payload, size_t plen, struct ipv4 ip);
-static void fragmented_tryfinish(struct fragmented *inc);
-static void fragmented_free(struct fragmented *inc);
-
-static struct fragmented *fragmented_find(struct ipv4 fraghdr) {
- struct fragmented *inc;
- for (inc = fragmenteds; inc; inc = inc->next) {
- if (inc->h.src == fraghdr.src &&
- inc->h.dst == fraghdr.dst &&
- inc->h.proto == fraghdr.proto &&
- inc->h.id == fraghdr.id)
- {
- return inc;
- }
- }
- inc = malloc(sizeof *inc);
- memset(inc, 0, sizeof *inc);
- inc->h.src = fraghdr.src;
- inc->h.dst = fraghdr.dst;
- inc->h.proto = fraghdr.proto;
- inc->h.id = fraghdr.id;
-
- inc->next = fragmenteds;
- if (inc->next) inc->next->prev = &inc->next;
- inc->prev = &fragmenteds;
- *inc->prev = inc;
- return inc;
-}
-
-static void fragmented_tryinsert(const uint8_t *payload, size_t plen, struct ipv4 ip) {
- struct fragmented *inc = fragmented_find(ip);
- size_t off = (ip.fraginfo & FragOff) * 8;
- bool last = !(ip.fraginfo & MoreFrags);
- // eprintf("fragmented packet, %u + %u, part of 0x%x", off, plen, inc);
-
- /* find the first fragment at a bigger offset, and insert before it */
- struct fragment **insert = &inc->first;
- for (; *insert; insert = &(*insert)->next) {
- if ((*insert)->offset > off) break;
- if ((*insert)->offset == off) return; /* duplicate packet */
- }
- /* later on: frag->next = *insert;
- * if we're the last fragment, frag->next must == NULL */
- if (last && *insert != NULL) return;
-
- struct fragment *frag = malloc(sizeof(struct fragment) + plen);
- frag->next = *insert;
- *insert = frag;
- frag->len = plen;
- frag->offset = off;
- frag->last = last;
- memcpy(frag->buf, payload, plen);
-
- if (off == 0) { /* save header */
- assert(!inc->h.header);
- void *headercpy = malloc(ip.hlen);
- memcpy(headercpy, ip.header, ip.hlen);
- inc->h = ip;
- inc->h.header = headercpy;
- }
-
- fragmented_tryfinish(inc);
-}
-
-static void fragmented_tryfinish(struct fragmented *inc) {
- if (inc->first->offset != 0) return;
- for (struct fragment *iter = inc->first; iter; iter = iter->next) {
- size_t iterend = iter->offset + iter->len;
- struct fragment *next = iter->next;
- if (next) {
- if (iterend < next->offset) return; /* incomplete */
- if (iterend > next->offset) {
- fragmented_free(inc);
- return;
- }
- } else if (iter->last) {
- void *buf = malloc(iterend);
- for (struct fragment *iter = inc->first; iter; iter = iter->next) {
- assert(iter->offset + iter->len <= iterend);
- memcpy(buf + iter->offset, iter->buf, iter->len);
- }
- ipv4_dispatch(buf, iterend, inc->h);
- free(buf);
- fragmented_free(inc);
- }
- }
-}
-
-static void fragmented_free(struct fragmented *inc) {
- if (inc->next) {
- inc->next->prev = inc->prev;
- *inc->next->prev = inc->next;
- } else {
- *inc->prev = NULL;
- }
-
- for (struct fragment *next, *iter = inc->first; iter; iter = next) {
- next = iter->next;
- free(iter);
- }
- free((void*)inc->h.header);
- free(inc);
-}
-
-
-static void ipv4_dispatch(const uint8_t *buf, size_t len, struct ipv4 ip) {
- switch (ip.proto) {
- case 0x01: icmp_parse(buf, len, ip); break;
- case 0x06: tcp_parse(buf, len, ip); break;
- case 0x11: udp_parse(buf, len, ip); break;
- }
-}
-
-void ipv4_parse(const uint8_t *buf, size_t len, struct ethernet ether) {
- uint8_t version, headerlen;
- uint16_t totallen;
-
- version = buf[Version] >> 4;
- if (version != 4) return;
- headerlen = (buf[HdrLen] & 0xf) * 4;
- totallen = nget16(buf + TotalLen);
- if (totallen < headerlen) return;
-
- /* ignores checksum. TODO? */
-
- struct ipv4 ip = (struct ipv4){
- .e = ether,
- .src = nget32(buf + SrcIP),
- .dst = nget32(buf + DstIP),
- .id = nget16(buf + Id),
- .fraginfo = nget16(buf + FragInfo),
- .proto = buf[Proto],
- .header = buf,
- .hlen = headerlen,
- };
-
- if (ip.fraginfo & ~(EvilBit | DontFrag)) {
- fragmented_tryinsert(buf + headerlen, totallen - headerlen, ip);
- } else {
- if (totallen > len) return;
- ipv4_dispatch(buf + headerlen, totallen - headerlen, ip);
- }
-}
-
-static uint16_t next_id = 0;
-void ipv4_send(const void *payload, size_t len, struct ipv4 ip) {
- const size_t mtu = 1500;
- const size_t hdrlen = 20;
-
- ip.e.type = ET_IPv4;
- if (!ip.src) ip.src = state.ip;
- if (!ip.e.dst && ip.dst == 0xFFFFFFFF)
- ip.e.dst = &MAC_BROADCAST;
-
- uint16_t id = next_id++;
- for (size_t off = 0, fraglen = mtu - hdrlen; off < len; off += fraglen) {
- if (fraglen > len - off)
- fraglen = len - off;
- bool last = off + fraglen >= len;
- uint8_t *pkt = ether_start(hdrlen + fraglen, ip.e);
- pkt[Version] = 0x40;
- pkt[HdrLen] |= hdrlen / 4;
- nput16(pkt + TotalLen, hdrlen + fraglen);
- nput16(pkt + Id, id);
- nput16(pkt + FragInfo, (off >> 3) | (last ? 0 : MoreFrags));
- pkt[TTL] = 0xFF;
- pkt[Proto] = ip.proto;
- nput32(pkt + SrcIP, ip.src);
- nput32(pkt + DstIP, ip.dst);
- nput16(pkt + Checksum, ip_checksum(pkt, hdrlen));
- memcpy(pkt + hdrlen, payload + off, fraglen);
- ether_finish(pkt);
- }
-}
diff --git a/src/user/app/netstack/netstack.c b/src/user/app/netstack/netstack.c
deleted file mode 100644
index 2636429..0000000
--- a/src/user/app/netstack/netstack.c
+++ /dev/null
@@ -1,53 +0,0 @@
-#include "proto.h"
-#include "util.h"
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <thread.h>
-
-struct net_state state = {
- // TODO dynamically get mac
- .mac = {0x52, 0x54, 0x00, 0xCA, 0x77, 0x1A},
-};
-
-void network_thread(void *arg) { (void)arg;
- const size_t buflen = 4096;
- char *buf = malloc(buflen);
- for (;;) {
- long ret = _sys_read(state.raw_h, buf, buflen, -1);
- if (ret < 0) break;
- ether_parse((void*)buf, ret);
- }
- free(buf);
-}
-
-void fs_thread(void *arg);
-
-int main(int argc, char **argv) {
- if (argc < 4) {
- eprintf("usage: netstack iface ip gateway");
- return 1;
- }
- state.raw_h = camellia_open(argv[1], OPEN_RW);
- if (state.raw_h < 0) {
- eprintf("couldn't open %s", argv[1]);
- return 1;
- }
- if (ip_parse(argv[2], &state.ip) < 0) {
- eprintf("invalid ip");
- return -1;
- }
- if (ip_parse(argv[3], &state.gateway) < 0) {
- eprintf("invalid gateway");
- return -1;
- }
- setproctitle(argv[2]);
- arp_request(state.gateway);
- thread_create(0, network_thread, NULL);
- thread_create(0, fs_thread, NULL);
- _sys_await();
- return 0;
-}
diff --git a/src/user/app/netstack/proto.h b/src/user/app/netstack/proto.h
deleted file mode 100644
index 8ea11ac..0000000
--- a/src/user/app/netstack/proto.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#pragma once
-#include <camellia/types.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-typedef uint8_t mac_t[6];
-static const mac_t MAC_BROADCAST = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-
-extern struct net_state {
- mac_t mac;
- uint32_t ip, gateway;
-
- hid_t raw_h;
-} state;
-
-enum { /* ethertype */
- ET_IPv4 = 0x800,
- ET_ARP = 0x806,
-};
-
-struct ethernet {
- const mac_t *src, *dst;
- uint16_t type;
-};
-
-struct ipv4 {
- struct ethernet e;
- uint32_t src, dst;
- uint16_t id, fraginfo;
- uint8_t proto;
- const uint8_t *header; size_t hlen;
-};
-
-struct tcp {
- struct ipv4 ip;
- uint16_t src, dst;
-};
-
-struct udp {
- struct ipv4 ip;
- uint16_t src, dst;
-};
-
-struct icmp {
- struct ipv4 ip;
- uint8_t type, code;
-};
-
-
-/* NOT THREADSAFE, YET USED FROM CONCURRENT THREADS
- * will break if i implement a scheduler*/
-struct ethq {
- struct ethq *next;
- hid_t h;
-};
-extern struct ethq *ether_queue;
-
-void arp_parse(const uint8_t *buf, size_t len);
-void arp_request(uint32_t ip);
-/* 0 on success, -1 on failure */
-int arpcache_get(uint32_t ip, mac_t *mac);
-void arp_fsread(hid_t h, long offset);
-long arp_fswrite(const char *buf, long len, long offset);
-
-void icmp_parse(const uint8_t *buf, size_t len, struct ipv4 ip);
-void icmp_send(const void *payload, size_t len, struct icmp i);
-
-void ipv4_parse(const uint8_t *buf, size_t len, struct ethernet ether);
-void ipv4_send(const void *payload, size_t len, struct ipv4 ip);
-
-void ether_parse(const uint8_t *buf, size_t len);
-uint8_t *ether_start(size_t len, struct ethernet ether);
-void ether_finish(uint8_t *pkt);
-
-struct udp_conn;
-void udp_parse(const uint8_t *buf, size_t len, struct ipv4 ip);
-/* calls callback once, after a client connects. */
-void udp_listen(
- uint16_t port,
- void (*on_conn)(struct udp_conn *, void *carg),
- void (*on_recv)(const void *, size_t, void *carg),
- void *carg);
-struct udp_conn *udpc_new(
- struct udp u,
- void (*on_recv)(const void *, size_t, void *carg),
- void *carg);
-// TODO udp_onclosed
-void udpc_send(struct udp_conn *, const void *buf, size_t len);
-/* frees */
-void udpc_close(struct udp_conn *);
-
-struct tcp_conn;
-void tcp_parse(const uint8_t *buf, size_t len, struct ipv4 ip);
-void tcp_listen(
- uint16_t port,
- void (*on_conn)(struct tcp_conn *, void *carg),
- void (*on_recv)(void *carg),
- void (*on_close)(void *carg),
- void *carg);
-struct tcp_conn *tcpc_new(
- struct tcp t,
- void (*on_recv)(void *carg),
- void (*on_close)(void *carg),
- void *carg);
-size_t tcpc_tryread(struct tcp_conn *, void *buf, size_t len);
-void tcpc_send(struct tcp_conn *, const void *buf, size_t len);
-void tcpc_close(struct tcp_conn *);
diff --git a/src/user/app/netstack/tcp.c b/src/user/app/netstack/tcp.c
deleted file mode 100644
index d1adeab..0000000
--- a/src/user/app/netstack/tcp.c
+++ /dev/null
@@ -1,268 +0,0 @@
-/* Welcome to spaghetti land.
- * This is anything but production quality. It's throwaway code, meant
- * only to see how networking could fit into the architecture of the
- * system. */
-#include "proto.h"
-#include "util.h"
-#include <assert.h>
-#include <shared/ring.h>
-
-enum {
- SrcPort = 0,
- DstPort = 2,
- Seq = 4,
- AckNum = 8, /* last processed seq + 1 */
- Flags = 12,
- FlagSize = 0xF000, /* size of header / 4 bytes */
- /* 3 bits: 0, still unused
- * 3 bits: modern stuff not in the original RFC */
- FlagURG = 0x0020, /* urgent */
- FlagACK = 0x0010,
- FlagPSH = 0x0008, /* force buffer flush */
- FlagRST = 0x0004, /* reset connection */
- FlagSYN = 0x0002, /* first packet; sync sequence numbers */
- FlagFIN = 0x0001, /* last packet */
- FlagAll = 0x003F,
- WinSize = 14, /* amount of data we're willing to receive */
- Checksum = 16,
- Urgent = 18,
- MinHdr = 20,
-};
-
-enum tcp_state {
- LISTEN,
- SYN_SENT,
- SYN_RCVD,
- ESTABILISHED,
- LAST_ACK,
- CLOSED,
-};
-
-struct tcp_conn {
- uint32_t lip, rip;
- mac_t rmac;
- uint16_t lport, rport;
- struct tcp_conn *next, **link;
-
- enum tcp_state state;
- uint32_t lack, rack;
- uint32_t lseq;
- bool uclosed; /* did the user close? */
-
- void (*on_conn)(struct tcp_conn *, void *carg);
- void (*on_recv)(void *carg);
- void (*on_close)(void *carg);
- void *carg;
-
- ring_t rx;
-};
-static struct tcp_conn *conns;
-static void conns_append(struct tcp_conn *c) {
- c->next = conns;
- if (c->next)
- c->next->link = &c->next;
- c->link = &conns;
- *c->link = c;
-}
-static void tcpc_sendraw(struct tcp_conn *c, uint16_t flags, const void *buf, size_t len) {
- uint8_t *pkt = malloc(MinHdr + len);
- memset(pkt, 0, MinHdr);
-
- nput16(pkt + SrcPort, c->lport);
- nput16(pkt + DstPort, c->rport);
- nput32(pkt + Seq, c->lseq);
- c->lseq += len;
- nput32(pkt + AckNum, c->lack);
- flags |= (MinHdr / 4) << 12;
- nput16(pkt + Flags, flags);
- nput16(pkt + WinSize, ring_avail(&c->rx));
- memcpy(pkt + MinHdr, buf, len);
- nput16(pkt + Checksum, ip_checksumphdr(pkt, MinHdr + len, c->lip, c->rip, 6));
-
- ipv4_send(pkt, MinHdr + len, (struct ipv4){
- .proto = 6,
- .src = c->lip,
- .dst = c->rip,
- .e.dst = &c->rmac,
- });
- free(pkt);
-}
-void tcp_listen(
- uint16_t port,
- void (*on_conn)(struct tcp_conn *, void *carg),
- void (*on_recv)(void *carg),
- void (*on_close)(void *carg),
- void *carg)
-{
- struct tcp_conn *c = malloc(sizeof *c);
- memset(c, 0, sizeof *c);
- c->lport = port;
- c->lip = state.ip;
- c->state = LISTEN;
- c->on_conn = on_conn;
- c->on_recv = on_recv;
- c->on_close = on_close;
- c->carg = carg;
- // TODO setting the ring size super low loses every nth byte. probably a bug with ring_t itself!
- c->rx = (ring_t){malloc(4096), 4096, 0, 0};
- conns_append(c);
-}
-struct tcp_conn *tcpc_new(
- struct tcp t,
- void (*on_recv)(void *carg),
- void (*on_close)(void *carg),
- void *carg)
-{
- struct tcp_conn *c = malloc(sizeof *c);
- memset(c, 0, sizeof *c);
- c->lip = t.ip.src ? t.ip.src : state.ip;
- c->rip = t.ip.dst;
- c->lport = t.src ? t.src : 50002; // TODO randomize source ports
- c->rport = t.dst;
- if (arpcache_get(c->rip, &c->rmac) < 0) {
- // TODO wait for ARP reply
- arp_request(c->rip);
- if (arpcache_get(state.gateway, &c->rmac) < 0) {
- eprintf("neither target nor gateway not in ARP cache, dropping");
- free(c);
- return NULL;
- }
- }
-
- c->state = SYN_SENT;
- c->on_recv = on_recv;
- c->on_close = on_close;
- c->carg = carg;
- c->rx = (ring_t){malloc(4096), 4096, 0, 0};
- conns_append(c);
-
- tcpc_sendraw(c, FlagSYN, NULL, 0);
- c->lseq++;
- return c;
-}
-size_t tcpc_tryread(struct tcp_conn *c, void *buf, size_t len) {
- if (!buf) return ring_used(&c->rx);
- return ring_get(&c->rx, buf, len);
-}
-void tcpc_send(struct tcp_conn *c, const void *buf, size_t len) {
- tcpc_sendraw(c, FlagACK | FlagPSH, buf, len);
-}
-static void tcpc_tryfree(struct tcp_conn *c) {
- if (c->state == CLOSED && c->uclosed) {
- if (c->next) c->next->link = c->link;
- *c->link = c->next;
- free(c->rx.buf);
- free(c);
- }
-}
-void tcpc_close(struct tcp_conn *c) {
- /* ONLY FOR USE BY THE USER, drops their reference */
- assert(!c->uclosed);
- c->uclosed = true;
- if (c->state != CLOSED && c->state != LAST_ACK && c->state != LISTEN) {
- tcpc_sendraw(c, FlagFIN | FlagACK, NULL, 0);
- c->state = LAST_ACK;
- c->on_conn = NULL;
- c->on_close = NULL;
- }
- tcpc_tryfree(c);
-}
-
-void tcp_parse(const uint8_t *buf, size_t len, struct ipv4 ip) {
- if (len < 20) return;
- uint16_t srcport = nget16(buf + SrcPort);
- uint16_t dstport = nget16(buf + DstPort);
- uint32_t seq = nget32(buf + Seq);
- uint32_t acknum = nget32(buf + AckNum);
- uint16_t flags = nget16(buf + Flags);
- // uint16_t winsize = nget16(buf + WinSize);
- // uint16_t chksum = nget16(buf + Checksum);
- uint16_t hdrlen = ((flags & FlagSize) >> 12) * 4;
- if (hdrlen > len) return;
- uint16_t payloadlen = len - hdrlen;
-
- for (struct tcp_conn *iter = conns; iter; iter = iter->next) {
- if (iter->state == CLOSED) continue;
- if (iter->lport != dstport) continue;
-
- if (iter->state == LISTEN && (flags & FlagAll) == FlagSYN) {
- iter->state = SYN_RCVD;
- iter->rip = ip.src;
- iter->rport = srcport;
- iter->lack = seq + 1;
- memcpy(&iter->rmac, ip.e.src, sizeof(mac_t));
- tcpc_sendraw(iter, FlagSYN | FlagACK, NULL, 0);
- iter->lseq++;
- if (iter->on_conn) iter->on_conn(iter, iter->carg);
- return;
- }
-
- if (iter->rip == ip.src && iter->rport == srcport) {
- // TODO doesn't handle seq/ack overflows
- if (iter->state == SYN_SENT) {
- if (flags & FlagSYN) {
- iter->state = ESTABILISHED;
- iter->lack = seq + 1;
- tcpc_sendraw(iter, FlagACK, NULL, 0);
- return;
- } else {
- // TODO resend syn?
- return;
- }
- }
- if (flags & FlagACK) {
- if (iter->rack < acknum)
- iter->rack = acknum;
- if (iter->state == LAST_ACK) {
- // TODO check if ack has correct number
- iter->state = CLOSED;
- tcpc_tryfree(iter);
- // TODO free (also after a timeout)
- return;
- }
- }
- if (iter->lack != seq && iter->lack - 1 != seq) {
- eprintf("remote seq jumped by %d", seq - iter->lack);
- tcpc_sendraw(iter, FlagACK, NULL, 0);
- return;
- }
- // TODO check if overflows window size
- if (payloadlen) {
- iter->lack = seq + payloadlen;
- ring_put(&iter->rx, buf + hdrlen, payloadlen);
- if (iter->on_recv) iter->on_recv(iter->carg);
- tcpc_sendraw(iter, FlagACK, NULL, 0);
- }
- if (flags & FlagFIN) {
- // TODO should resend the packet until an ACK is received
- // TODO duplicated in tcpc_close
- tcpc_sendraw(iter, FlagFIN | FlagACK, NULL, 0);
- iter->state = LAST_ACK;
- if (iter->on_close) iter->on_close(iter->carg);
- return;
- }
- return;
- }
- }
-
- if ((flags & FlagRST) == 0) {
- uint8_t *pkt = malloc(MinHdr);
- memset(pkt, 0, MinHdr);
- nput16(pkt + SrcPort, dstport);
- nput16(pkt + DstPort, srcport);
- nput32(pkt + Seq, acknum);
- nput32(pkt + AckNum, seq + 1);
- uint16_t pktflags = FlagRST | FlagACK;
- pktflags |= (MinHdr / 4) << 12;
- nput16(pkt + Flags, pktflags);
- nput16(pkt + Checksum, ip_checksumphdr(pkt, MinHdr, ip.src, ip.dst, 6));
-
- ipv4_send(pkt, MinHdr, (struct ipv4){
- .proto = 6,
- .src = ip.dst,
- .dst = ip.src,
- .e.dst = ip.e.src,
- });
- free(pkt);
- }
-}
diff --git a/src/user/app/netstack/udp.c b/src/user/app/netstack/udp.c
deleted file mode 100644
index 3d560ae..0000000
--- a/src/user/app/netstack/udp.c
+++ /dev/null
@@ -1,124 +0,0 @@
-#include "proto.h"
-#include "util.h"
-
-enum {
- SrcPort = 0,
- DstPort = 2,
- Length = 4,
- Checksum = 6,
- Payload = 8,
-};
-
-
-struct udp_conn {
- uint32_t lip, rip;
- uint16_t lport, rport;
- mac_t rmac;
- void (*on_conn)(struct udp_conn *, void *); /* if non-NULL - listening, if NULL - estabilished */
- void (*on_recv)(const void *, size_t, void *);
- void *carg;
- struct udp_conn *next, **link;
-};
-static struct udp_conn *conns;
-static void conns_append(struct udp_conn *c) {
- c->next = conns;
- if (c->next)
- c->next->link = &c->next;
- c->link = &conns;
- *c->link = c;
-}
-void udp_listen(
- uint16_t port,
- void (*on_conn)(struct udp_conn *, void *carg),
- void (*on_recv)(const void *, size_t, void *carg),
- void *carg)
-{
- if (!on_conn) return;
- struct udp_conn *c = malloc(sizeof *c);
- c->lport = port;
- c->lip = state.ip;
- c->on_conn = on_conn;
- c->on_recv = on_recv;
- c->carg = carg;
- conns_append(c);
-}
-struct udp_conn *udpc_new(
- struct udp u,
- void (*on_recv)(const void *, size_t, void *carg),
- void *carg)
-{
- struct udp_conn *c = malloc(sizeof *c);
- memset(c, 0, sizeof *c);
- c->lip = u.ip.src;
- c->rip = u.ip.dst;
- c->lport = u.src ? u.src : 50000; // TODO randomize source ports
- c->rport = u.dst;
- if (arpcache_get(c->rip, &c->rmac) < 0) {
- // TODO make arp request, wait for reply
- eprintf("not in ARP cache, unimplemented");
- free(c);
- return NULL;
- }
- c->on_recv = on_recv;
- c->carg = carg;
- conns_append(c);
- return c;
-}
-void udpc_send(struct udp_conn *c, const void *buf, size_t len) {
- uint8_t *pkt = malloc(Payload + len);
- nput16(pkt + SrcPort, c->lport);
- nput16(pkt + DstPort, c->rport);
- nput16(pkt + Length, Payload + len);
- nput16(pkt + Checksum, 0);
- memcpy(pkt + Payload, buf, len);
- ipv4_send(pkt, Payload + len, (struct ipv4){
- .proto = 0x11,
- .src = c->lip,
- .dst = c->rip,
- .e.dst = &c->rmac,
- });
- free(pkt);
-}
-void udpc_close(struct udp_conn *c) {
- if (c->next) c->next->link = c->link;
- *(c->link) = c->next;
- free(c);
-}
-
-
-void udp_parse(const uint8_t *buf, size_t len, struct ipv4 ip) {
- uint16_t srcport = nget16(buf + SrcPort);
- uint16_t dstport = nget16(buf + DstPort);
- bool active = false;
-
- for (struct udp_conn *iter = conns; iter; iter = iter->next) {
- if (iter->on_conn && dstport == iter->lport) {
- iter->on_conn(iter, iter->carg);
- iter->on_conn = NULL;
- iter->rport = srcport;
- memcpy(&iter->rmac, ip.e.src, sizeof(mac_t));
- iter->rip = ip.src;
- }
- if (iter->rip == ip.src &&
- iter->rport == srcport &&
- iter->lport == dstport &&
- iter->on_recv)
- {
- active = true;
- iter->on_recv(buf + Payload, len - Payload, iter->carg);
- }
- }
-
- if (!active) {
- uint8_t *pkt = malloc(4 + ip.hlen + 8);
- nput32(pkt, 0);
- memcpy(pkt + 4, ip.header, ip.hlen + 8);
- icmp_send(pkt, 4 + ip.hlen + 8, (struct icmp){
- .type = 3, /* destination unreachable */
- .code = 3, /* port unreachable */
- .ip.dst = ip.src,
- .ip.e.dst = ip.e.src,
- });
- free(pkt);
- }
-}
diff --git a/src/user/app/netstack/util.c b/src/user/app/netstack/util.c
deleted file mode 100644
index 68092aa..0000000
--- a/src/user/app/netstack/util.c
+++ /dev/null
@@ -1,60 +0,0 @@
-#include "util.h"
-
-/* https://www.w3.org/TR/PNG/#D-CRCAppendix */
-static uint32_t crc_table[256];
-uint32_t crc32(const uint8_t *buf, size_t len) {
- if (!crc_table[1]) {
- for (int i = 0; i < 256; i++) {
- uint32_t c = i;
- for (int j = 0; j < 8; j++)
- c = ((c&1) ? 0xedb88320 : 0) ^ (c >> 1);
- crc_table[i] = c;
- }
- }
-
- uint32_t c = 0xFFFFFFFF;
- for (size_t i = 0; i < len; i++)
- c = crc_table[(c ^ buf[i]) & 0xff] ^ (c >> 8);
- return ~c;
-}
-
-uint16_t ip_checksum(const uint8_t *buf, size_t len) {
- uint32_t c = 0;
- while (len >= 2) {
- c += nget16(buf);
- buf += 2; len -= 2;
- }
- if (len) c += (*buf) << 8;
- while (c > 0xFFFF) c = (c & 0xFFFF) + (c >> 16);
- return ~c;
-}
-
-uint16_t ip_checksumphdr(
- const uint8_t *buf, size_t len,
- uint32_t ip1, uint32_t ip2,
- uint16_t proto)
-{
- uint32_t c = (uint16_t)~ip_checksum(buf, len);
- c += (ip1 & 0xFFFF) + (ip1 >> 16);
- c += (ip2 & 0xFFFF) + (ip2 >> 16);
- c += proto + len;
- while (c > 0xFFFF) c = (c & 0xFFFF) + (c >> 16);
- return ~c;
-}
-
-int ip_parse(const char *s, uint32_t *dest) {
- if (!s) return -1;
-
- uint32_t ip = strtol(s, (char**)&s, 0);
- int parts = 1;
- for (; parts < 4; parts++) {
- if (!*s) break;
- if (*s++ != '.') return -1;
- ip <<= 8;
- ip += strtol(s, (char**)&s, 0);
- }
- if (parts > 1)
- ip = ((ip & 0xFFFFFF00) << 8 * (4 - parts)) | (ip & 0xFF);
- *dest = ip;
- return 0;
-}
diff --git a/src/user/app/netstack/util.h b/src/user/app/netstack/util.h
deleted file mode 100644
index 0b29560..0000000
--- a/src/user/app/netstack/util.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#pragma once
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define eprintf(fmt, ...) fprintf(stderr, "netstack: "fmt"\n" __VA_OPT__(,) __VA_ARGS__)
-
-uint32_t crc32(const uint8_t *buf, size_t len);
-uint16_t ip_checksum(const uint8_t *buf, size_t len);
-uint16_t ip_checksumphdr(
- const uint8_t *buf, size_t len,
- uint32_t ip1, uint32_t ip2,
- uint16_t proto);
-/* 0 on success, negative failure */
-int ip_parse(const char *s, uint32_t *ip);
-
-static inline void nput16(void *vbuf, uint16_t n) {
- uint8_t *b = vbuf;
- b[0] = n >> 8;
- b[1] = n >> 0;
-}
-
-static inline void nput32(void *vbuf, uint32_t n) {
- uint8_t *b = vbuf;
- b[0] = n >> 24;
- b[1] = n >> 16;
- b[2] = n >> 8;
- b[3] = n >> 0;
-}
-
-static inline uint16_t nget16(const void *vbuf) {
- const uint8_t *b = vbuf;
- return (b[0] << 8)
- | (b[1] << 0);
-}
-
-static inline uint32_t nget32(const void *vbuf) {
- const uint8_t *b = vbuf;
- return (b[0] << 24)
- | (b[1] << 16)
- | (b[2] << 8)
- | (b[3] << 0);
-}
diff --git a/src/user/app/ps/ps.c b/src/user/app/ps/ps.c
deleted file mode 100644
index 76a5841..0000000
--- a/src/user/app/ps/ps.c
+++ /dev/null
@@ -1,54 +0,0 @@
-#include <_proc.h>
-#include <ctype.h>
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-int
-main(void)
-{
- char *readbuf = malloc(4096);
- char *procbuf = malloc(4096);
- FILE *f = fopen("/proc/", "r");
- if (!f) {
- err(1, "couldn't open /proc/");
- }
-
- // TODO library for iterating over directories
- for (;;) {
- int len = fread(readbuf, 1, 4096, f);
- if (len <= 0) break;
- for (int pos = 0; pos < len; ) {
- char *end = memchr(readbuf + pos, 0, len - pos);
- if (!end) {
- errx(1, "unimplemented: buffer overflow");
- }
- size_t entryl = end - (readbuf+pos) + 1;
- if (isdigit(readbuf[pos])) {
- FILE *g;
- sprintf(procbuf, "/proc/%smem", readbuf+pos);
- g = fopen(procbuf, "r");
- if (!g) {
- warn("couldn't open \"%s\"", procbuf);
- strcpy(procbuf, "(can't peek)");
- } else {
- fseek(g, (long)&_psdata_loc->desc, SEEK_SET);
- if (fread(procbuf, 1, 128, g) <= 0) {
- strcpy(procbuf, "(no psdata)");
- }
- procbuf[128] = '\0';
- fclose(g);
- }
- end[-1] = '\0'; /* remove trailing slash */
- printf("%s\t%s\n", readbuf+pos, procbuf);
- }
- pos += entryl;
- }
- }
-
- free(readbuf);
- free(procbuf);
- fclose(f);
- return 0;
-}
diff --git a/src/user/app/shell/builtins.c b/src/user/app/shell/builtins.c
deleted file mode 100644
index 9c294b2..0000000
--- a/src/user/app/shell/builtins.c
+++ /dev/null
@@ -1,254 +0,0 @@
-#include "builtins.h"
-#include "shell.h"
-#include <camellia.h>
-#include <camellia/fs/misc.h>
-#include <camellia/path.h>
-#include <err.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#define DEFAULT_ARGV(...) \
- char *_argv_default[] = {argv[0], __VA_ARGS__}; \
- if (argc <= 1) { \
- argc = sizeof(_argv_default) / sizeof(*_argv_default); \
- argv = _argv_default; \
- }
-
-static void cmd_cat(int argc, char **argv) {
- const size_t buflen = 4096;
- char *buf = malloc(buflen);
-
- DEFAULT_ARGV("!stdin");
- for (int i = 1; i < argc; i++) {
- FILE *file = fopen(argv[i], "r");
- if (!file) {
- perror(argv[i]);
- return;
- }
- if (!strcmp(argv[i], "!stdin")) fextflags(file, FEXT_NOFILL);
- for (;;) {
- int len = fread(buf, 1, buflen, file);
- if (len <= 0) break;
- fwrite(buf, 1, len, stdout);
- }
- if (ferror(file)) {
- perror(argv[i]);
- return;
- }
- fclose(file);
- }
-}
-
-static void cmd_echo(int argc, char **argv) {
- bool newline = true;
- int i = 1;
-
- if (!strcmp("-n", argv[i])) {
- i++;
- newline = false;
- }
-
- printf("%s", argv[i++]);
- for (; i < argc; i++)
- printf(" %s", argv[i]);
- if (newline)
- printf("\n");
-}
-
-void cmd_getsize(int argc, char **argv) {
- if (argc < 2) errx(1, "no arguments");
- for (int i = 1; i < argc; i++) {
- hid_t h = camellia_open(argv[i], OPEN_READ);
- if (h < 0) {
- warn("error opening %s", argv[i]);
- continue;
- }
- printf("%s: %d\n", argv[i], (int)_sys_getsize(h));
- _sys_close(h);
- }
-}
-
-void cmd_hexdump(int argc, char **argv) {
- DEFAULT_ARGV("!stdin");
- const size_t buflen = 4096;
- uint8_t *buf = malloc(buflen);
- FILE *file;
- bool canonical = strcmp(argv[0], "hd") == 0;
- size_t readlen = ~0;
- size_t pos = 0;
- bool raw = false;
-
- int c;
- optind = 0;
- while ((c = getopt(argc, argv, "Cn:s:r")) != -1) {
- switch (c) {
- case 'C':
- canonical = true;
- break;
- case 'n':
- readlen = strtol(optarg, NULL, 0);
- break;
- case 's':
- pos = strtol(optarg, NULL, 0);
- break;
- case 'r': /* "raw" mode, print data as soon as it's read without buffering */
- raw = true;
- break;
- default:
- return;
- }
- }
- if (readlen != (size_t)~0)
- readlen += pos;
-
- for (; optind < argc; optind++) {
- file = fopen(argv[optind], "r");
- if (!file) {
- warn("couldn't open %s", argv[optind]);
- continue;
- }
- if (raw) fextflags(file, FEXT_NOFILL);
- fseek(file, pos, SEEK_SET);
- bool skipped = false;
- while (pos < readlen) {
- size_t len = buflen;
- if (len > readlen - pos)
- len = readlen - pos;
- len = fread(buf, 1, len, file);
- if (len == 0) break;
-
- for (size_t i = 0; i < len; i += 16) {
- if (i >= 16 && !memcmp(buf + i, buf + i - 16, 16)) {
- if (!skipped) {
- printf("*\n");
- skipped = true;
- }
- continue;
- } else skipped = false;
- printf("%08zx ", pos + i);
-
- for (size_t j = i; j < i + 8 && j < len; j++)
- printf("%02x ", buf[j]);
- printf(" ");
- for (size_t j = i + 8; j < i + 16 && j < len; j++)
- printf("%02x ", buf[j]);
-
- if (canonical) {
- printf(" |");
-
- for (size_t j = i; j < i + 16 && j < len; j++) {
- char c = '.';
- if (0x20 <= buf[j] && buf[j] < 0x7f) c = buf[j];
- printf("%c", c);
- }
- printf("|\n");
- } else {
- printf("\n");
- }
- }
- pos += len;
- }
- printf("%08zx\n", pos);
- fclose(file);
- }
-}
-
-static void cmd_ls(int argc, char **argv) {
- FILE *file;
- const size_t buflen = 4096;
- char *buf = malloc(buflen);
-
- DEFAULT_ARGV(".");
- for (int i = 1; i < argc; i++) {
- char *path = (void*)argv[i];
- int pathlen = strlen(path);
-
- if (!pathlen || path[pathlen - 1] != '/') {
- memcpy(buf, path, pathlen);
- buf[pathlen] = '/';
- buf[pathlen+1] = '\0';
- path = buf;
- }
-
- file = fopen(path, "r");
- if (!file) {
- warn("couldn't open %s", argv[i]);
- continue;
- }
- for (;;) {
- int len = fread(buf, 1, buflen, file);
- if (len <= 0) break;
- for (int i = 0; i < len; i++)
- if (buf[i] == '\0') buf[i] = '\n';
- fwrite(buf, 1, len, stdout);
- }
- fclose(file);
- }
-}
-
-static void cmd_mkdir(int argc, char **argv) {
- // TODO mkdir -p
- if (argc < 2) errx(1, "no arguments");
- for (int i = 1; i < argc; i++) {
- if (mkdir(argv[i], 0777) < 0)
- perror(argv[i]);
- }
-}
-
-static void cmd_rm(int argc, char **argv) {
- if (argc < 2) errx(1, "no arguments");
- for (int i = 1; i < argc; i++) {
- if (unlink(argv[i]) < 0)
- perror(argv[i]);
- }
-}
-
-static void cmd_sleep(int argc, char **argv) {
- if (argc < 2) errx(1, "no arguments");
- _sys_sleep(strtol(argv[1], NULL, 0) * 1000);
-}
-
-static void cmd_touch(int argc, char **argv) {
- if (argc < 2) errx(1, "no arguments");
- for (int i = 1; i < argc; i++) {
- FILE *f = fopen(argv[i], "a");
- if (!f) perror(argv[i]);
- fclose(f);
- }
-}
-
-static void cmd_whitelist(int argc, char **argv) {
- int split = 1;
- for (; split < argc;) {
- if (!strcmp("--", argv[split])) break;
- split++;
- }
- argv[split] = NULL;
- MOUNT_AT("/") { fs_whitelist((void*)&argv[1]); }
-
- if (split < argc) {
- run_args(argc - split - 1, &argv[split + 1], NULL);
- } else {
- const char **argv = (const char*[]){"shell", NULL};
- run_args(1, (void*)argv, NULL);
- }
-}
-
-struct builtin builtins[] = {
- {"cat", cmd_cat},
- {"echo", cmd_echo},
- {"getsize", cmd_getsize},
- {"hd", cmd_hexdump},
- {"hexdump", cmd_hexdump},
- {"ls", cmd_ls},
- {"mkdir", cmd_mkdir},
- {"rm", cmd_rm},
- {"sleep", cmd_sleep},
- {"touch", cmd_touch},
- {"whitelist", cmd_whitelist},
- {NULL, NULL},
-};
diff --git a/src/user/app/shell/builtins.h b/src/user/app/shell/builtins.h
deleted file mode 100644
index 1e422bb..0000000
--- a/src/user/app/shell/builtins.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-#include <camellia/syscalls.h>
-#include <stdbool.h>
-
-struct builtin {
- const char *name;
- void (*fn)(int argc, char **argv);
-};
-
-extern struct builtin builtins[];
diff --git a/src/user/app/shell/parser.c b/src/user/app/shell/parser.c
deleted file mode 100644
index ad09348..0000000
--- a/src/user/app/shell/parser.c
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "shell.h"
-#include <ctype.h>
-#include <stdbool.h>
-#include <string.h>
-
-static char skipspace(char **sp) {
- char *s = *sp;
- while (*s && isspace(*s)) s++;
- *sp = s;
- return *s;
-}
-
-static bool isspecial(char c) {
- return c == '>' || c == '#';
-}
-
-static char *parg(char **sp) {
- char *s = *sp;
- char *res = NULL;
-
- if (skipspace(&s)) {
- // TODO incorrectly handles strings like a"b"
- switch (*s) {
- case '"':
- s++;
- res = s;
- while (*s && *s != '"')
- s++;
- break;
- default:
- res = s;
- while (*s && !isspace(*s) && !isspecial(*s))
- s++;
- if (*s == '#') {
- *s = '\0'; /* end parsing early */
- if (res == s) /* don't output an empty arg */
- res = NULL;
- }
- break;
- }
- if (*s) *s++ = '\0';
- }
-
- *sp = s;
- return res;
-}
-
-int parse(char *s, char **argv, size_t argvlen, struct redir *redir) {
- if (argvlen == 0) return -1;
- size_t argc = 0;
- char *arg;
-
- *argv = NULL;
- redir->stdout = NULL;
- redir->append = false;
-
- while (skipspace(&s)) {
- switch (*s) {
- case '>':
- s++;
- if (*s == '>') {
- s++;
- redir->append = true;
- }
- redir->stdout = parg(&s);
- break;
- default:
- arg = parg(&s);
- argv[argc++] = arg;
- if (argc >= argvlen)
- return -1;
- }
- }
- argv[argc] = NULL;
- return argc;
-}
diff --git a/src/user/app/shell/shell.c b/src/user/app/shell/shell.c
deleted file mode 100644
index 185aa7e..0000000
--- a/src/user/app/shell/shell.c
+++ /dev/null
@@ -1,178 +0,0 @@
-#include "builtins.h"
-#include "shell.h"
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <err.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <camellia/fs/misc.h>
-#include <x86intrin.h>
-
-int main();
-
-static void execp(char **argv) {
- if (!argv || !*argv) return;
- if (strncmp(argv[0], "/", 1) == 0 ||
- strncmp(argv[0], "./", 2) == 0 ||
- strncmp(argv[0], "../", 3) == 0)
- {
- execv(argv[0], argv);
- } else {
- size_t cmdlen = strlen(argv[0]);
- char *s = malloc(cmdlen + 6);
- if (!s) err(1, "malloc");
- memcpy(s, "/bin/", 5);
- memcpy(s + 5, argv[0], cmdlen + 1);
- execv(s, argv);
- free(s);
- }
-}
-
-void run_args(int argc, char **argv, struct redir *redir) {
- if (!*argv) return;
-
- /* "special" commands that can't be handled in a subprocess */
- if (!strcmp(argv[0], "mount")) {
- if (argc < 3) {
- fprintf(stderr, "mount: not enough arguments\n");
- return;
- }
- MOUNT_AT("/") {
- fs_dirinject(argv[1]);
- }
- MOUNT_AT(argv[1]) {
- run_args(argc - 2, argv + 2, redir);
- exit(1);
- }
- return;
- } else if (!strcmp(argv[0], "shadow")) {
- if (argc < 2) {
- fprintf(stderr, "shadow: missing path\n");
- } else {
- _sys_mount(HANDLE_NULLFS, argv[1], strlen(argv[1]));
- }
- } else if (!strcmp(argv[0], "procmnt")) {
- if (argc < 2) {
- fprintf(stderr, "procmnt: missing mountpoint\n");
- return;
- }
- _sys_mount(HANDLE_PROCFS, argv[1], strlen(argv[1]));
- /*
- if (!(3 <= argc && !strcmp(argv[2], "raw"))) {
- if (!mount_at("/")) {
- fs_dirinject(argv[1]);
- exit(1);
- }
- }
- */
- return;
- } else if (!strcmp(argv[0], "cd")) {
- if (chdir(argc > 1 ? argv[1] : "/") < 0)
- perror("cd");
- return;
- } else if (!strcmp(argv[0], "time")) {
- uint64_t time = __rdtsc();
- uint64_t div = 3000;
- run_args(argc - 1, argv + 1, redir);
- time = __rdtsc() - time;
- printf("%lu ns (assuming 3GHz)\n", time / div);
- return;
- } else if (!strcmp(argv[0], "exit")) {
- exit(0);
- } else if (!strcmp(argv[0], "getpid")) {
- printf("my\t%d\nparent\t%d\n", getpid(), getppid());
- return;
- }
-
- if (fork()) {
- _sys_await();
- return;
- }
-
- if (redir && redir->stdout) {
- FILE *f = fopen(redir->stdout, redir->append ? "a" : "w");
- if (!f) {
- err(1, "couldn't open %s for redirection", redir->stdout);
- }
-
- /* a workaround for file offsets not being preserved across exec()s.
- * TODO document that weird behaviour of exec() */
- hid_t p[2];
- if (_sys_pipe(p, 0) < 0) {
- errx(1, "couldn't create redirection pipe");
- }
- if (!_sys_fork(FORK_NOREAP, NULL)) {
- /* the child forwards data from the pipe to the file */
- const size_t buflen = 512;
- char *buf = malloc(buflen);
- if (!buf) err(1, "when redirecting");
- close(p[1]);
- for (;;) {
- long len = _sys_read(p[0], buf, buflen, 0);
- if (len < 0) exit(0);
- fwrite(buf, 1, len, f);
- if (ferror(f)) exit(0);
- }
- }
-
- fclose(f);
- close(p[0]);
- if (_sys_dup(p[1], 1, 0) < 0) {
- errx(1, "dup() failed when redirecting");
- }
- }
-
- for (struct builtin *iter = builtins; iter->name; iter++) {
- if (!strcmp(argv[0], iter->name)) {
- setprogname(argv[0]);
- iter->fn(argc, argv);
- exit(0);
- }
- }
-
- execp(argv);
- if (errno == EINVAL) {
- errx(1, "%s isn't a valid executable", argv[0]);
- } else {
- errx(1, "unknown command: %s", argv[0]);
- }
-}
-
-static void run(char *cmd) {
-#define ARGV_MAX 16
- char *argv[ARGV_MAX];
- struct redir redir;
- int argc = parse(cmd, argv, ARGV_MAX, &redir);
- if (argc < 0) {
- warn("parsing error");
- } else {
- run_args(argc, argv, &redir);
- }
-}
-
-int main(int argc, char **argv) {
- static char buf[256];
- FILE *f = stdin;
-
- if (argc > 1) {
- f = fopen(argv[1], "r");
- if (!f) {
- err(1, "couldn't open %s", argv[1]);
- return 1;
- }
- }
-
- for (;;) {
- if (f == stdin) {
- printf("%s $ ", getcwd(buf, sizeof buf));
- }
- if (!fgets(buf, 256, f)) {
- return 0;
- }
- run(buf);
- }
-}
diff --git a/src/user/app/shell/shell.h b/src/user/app/shell/shell.h
deleted file mode 100644
index 050e704..0000000
--- a/src/user/app/shell/shell.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma once
-#include <stdbool.h>
-#include <stddef.h>
-
-struct redir {
- const char *stdout;
- bool append;
-};
-
-int parse(char *s, char **argv, size_t argvlen, struct redir *redir);
-void run_args(int argc, char **argv, struct redir *redir);
diff --git a/src/user/app/testelf/main.c b/src/user/app/testelf/main.c
deleted file mode 100644
index 0cbe56c..0000000
--- a/src/user/app/testelf/main.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#include <err.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-const char *str = "Hello!", *str2 = "World.";
-
-int main(int argc, char **argv) {
- printf("elftest's &main == %p\n", &main);
- printf("%s %s\n", str, str2);
- printf("argc == %u\n", argc);
- for (int i = 0; i < argc; i++)
- printf("argv[%u] == %p == \"%s\"\n", i, argv[i], argv[i]);
- if (argv[1] && strcmp(argv[1], "stackexec") == 0) {
- /* exec something with arguments on the stack */
- const char s_d[] = "I am a pretty long string on the stack. Oh my. " \
- "I hope I won't get corrupted.\0";
- char s[sizeof(s_d)];
- memcpy(s, s_d, sizeof(s_d));
- const char *argv2[] = {"/bin/testelf", s, s, "hello", s, s, s, "lol", NULL};
- printf("argv2 == %p, s == %p\n== exec ==\n", argv2, s);
- execv((void*)argv2[0], (void*)argv2);
- err(1, "execv");
- }
- return 0;
-}
diff --git a/src/user/app/tests/kernel/fdlimit.c b/src/user/app/tests/kernel/fdlimit.c
deleted file mode 100644
index f332357..0000000
--- a/src/user/app/tests/kernel/fdlimit.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#include "../tests.h"
-#include <camellia/flags.h>
-#include <errno.h>
-#include <unistd.h>
-
-static void test_fdlimit_pipe(void) {
- hid_t ends[2];
- hid_t h[2] = {-1, -1};
- for (;;) {
- hid_t cur = _sys_open("/", 1, OPEN_READ);
- if (cur == -EMFILE) break;
- test(cur >= 0);
- h[0] = h[1];
- h[1] = cur;
- }
- test(h[0] >= 0); /* we need at least two handles */
-
- test(_sys_pipe(ends, 0) == -EMFILE);
- test(_sys_open("/", 1, OPEN_READ) == -EMFILE);
-
- close(h[1]);
- test(_sys_pipe(ends, 0) == -EMFILE);
- test(_sys_open("/", 1, OPEN_READ) == h[1]);
- test(_sys_open("/", 1, OPEN_READ) == -EMFILE);
-
- close(h[0]);
- close(h[1]);
- test(_sys_pipe(ends, 0) == 0);
-}
-
-static void test_fdlimit_fork(void) {
- for (;;) {
- hid_t cur = _sys_open("/", 1, OPEN_READ);
- if (cur == -EMFILE) break;
- test(cur >= 0);
- }
-
- if (!_sys_fork(0, NULL)) _sys_exit(123);
-
- test(_sys_fork(FORK_NEWFS, NULL) == -EMFILE);
- test(_sys_await() == 123);
- test(_sys_await() == ~0);
-}
-
-void r_k_fdlimit(void) {
- /* all these tests implicitly test if the vfs returns -EMFILE */
- run_test(test_fdlimit_pipe);
- run_test(test_fdlimit_fork);
-}
diff --git a/src/user/app/tests/kernel/fs.c b/src/user/app/tests/kernel/fs.c
deleted file mode 100644
index b5684d7..0000000
--- a/src/user/app/tests/kernel/fs.c
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "../tests.h"
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <stdbool.h>
-#include <string.h>
-
-static void test_unfinished_req(void) {
- hid_t h = -1;
- int ret = _sys_fork(FORK_NEWFS, &h);
- test(0 <= ret);
- if (ret == 0) {
- // TODO make a similar test with all 0s passed to fs_wait
- struct ufs_request res;
- _sys_fs_wait(NULL, 0, &res);
- // TODO second fs_wait
- exit(0);
- } else {
- test(0 <= h);
- test(_sys_mount(h, "/", 1) == 0);
- int ret = _sys_open("/", 1, 0);
- test(ret < 0);
- // the handler quits while handling that call - but this syscall should return anyways
- }
-}
-
-static void test_orphaned_fs(void) {
- hid_t h = -1;
- int ret = _sys_fork(FORK_NEWFS, &h);
- test(0 <= ret);
- if (ret == 0) {
- exit(0);
- } else {
- test(0 <= h);
- test(_sys_mount(h, "/", 1) == 0);
- int ret = _sys_open("/", 1, 0);
- test(ret < 0);
- }
-}
-
-static void test_fs_cleanup(void) {
- const char *msg = "success";
- int msglen = 8;
- char buf[16];
- hid_t ends[2];
- test(_sys_pipe(ends, 0) >= 0);
- if (!_sys_fork(0, NULL)) {
- hid_t h = -1;
- if (_sys_fork(FORK_NEWFS, &h) == 0) {
- for (;;) {
- struct ufs_request req;
- hid_t reqh = _sys_fs_wait(buf, sizeof buf, &req);
- if (reqh < 0) break;
- _sys_fs_respond(reqh, NULL, 0, 0); /* success */
- }
- /* this is the test: does it break out of the loop
- * when it should cleanup */
- _sys_write(ends[1], msg, msglen, -1, 0);
- exit(0);
- } else {
- test(_sys_mount(h, "/", 1) == 0);
- h = _sys_open("/", 1, 0);
- test(h >= 0);
- _sys_close(h);
- // TODO another test without the delay
- _sys_sleep(0);
- exit(0);
- }
- } else {
- test(_sys_read(ends[0], buf, sizeof buf, 0) == msglen);
- test(memcmp(buf, msg, msglen) == 0);
- }
-}
-
-void r_k_fs(void) {
- run_test(test_unfinished_req);
- run_test(test_orphaned_fs);
- run_test(test_fs_cleanup);
- run_test(test_fs_cleanup);
-}
diff --git a/src/user/app/tests/kernel/misc.c b/src/user/app/tests/kernel/misc.c
deleted file mode 100644
index 5d6b531..0000000
--- a/src/user/app/tests/kernel/misc.c
+++ /dev/null
@@ -1,66 +0,0 @@
-#include "../tests.h"
-#include <camellia/errno.h>
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <string.h>
-#include <unistd.h>
-
-static void test_fault_kill(void) {
- if (!fork()) { /* invalid memory access */
- asm volatile("movb $69, 0" ::: "memory");
- test_fail();
- }
- if (!fork()) { /* #GP */
- asm volatile("hlt" ::: "memory");
- test_fail();
- }
-
- int await_cnt = 0;
- while (_sys_await() != ~0) await_cnt++;
- test(await_cnt == 2);
-}
-
-static void test_efault(void) {
-#if 0
- const char *str = "o, 16 characters";
- char str2[16];
- char *invalid = (void*)0x1000;
- hid_t h;
-
- memcpy(str2, str, 16);
-
- test((h = _sys_open(TMPFILEPATH, strlen(TMPFILEPATH), OPEN_CREATE | OPEN_WRITE)) >= 0);
- test(_sys_write(h, str, 16, 0, 0) == 16);
- test(_sys_write(h, str2, 16, 0, 0) == 16);
-
- test(_sys_write(h, invalid, 16, 0, 0) == -EFAULT);
-
- /* x64 non-canonical pointers */
- test(_sys_write(h, (void*)((uintptr_t)str ^ 0x8000000000000000), 16, 0, 0) == -EFAULT);
- test(_sys_write(h, (void*)((uintptr_t)str ^ 0x1000000000000000), 16, 0, 0) == -EFAULT);
- test(_sys_write(h, (void*)((uintptr_t)str ^ 0x0100000000000000), 16, 0, 0) == -EFAULT);
- test(_sys_write(h, (void*)((uintptr_t)str ^ 0x0010000000000000), 16, 0, 0) == -EFAULT);
- test(_sys_write(h, (void*)((uintptr_t)str ^ 0x0001000000000000), 16, 0, 0) == -EFAULT);
- test(_sys_write(h, (void*)((uintptr_t)str ^ 0x0000800000000000), 16, 0, 0) == -EFAULT);
-
- test(_sys_write(h, (void*)((uintptr_t)str2 ^ 0x8000000000000000), 16, 0, 0) == -EFAULT);
- test(_sys_write(h, (void*)((uintptr_t)str2 ^ 0x1000000000000000), 16, 0, 0) == -EFAULT);
- test(_sys_write(h, (void*)((uintptr_t)str2 ^ 0x0100000000000000), 16, 0, 0) == -EFAULT);
- test(_sys_write(h, (void*)((uintptr_t)str2 ^ 0x0010000000000000), 16, 0, 0) == -EFAULT);
- test(_sys_write(h, (void*)((uintptr_t)str2 ^ 0x0001000000000000), 16, 0, 0) == -EFAULT);
- test(_sys_write(h, (void*)((uintptr_t)str2 ^ 0x0000800000000000), 16, 0, 0) == -EFAULT);
-
- test(_sys_write(h, str, 16, 0, 0) == 16);
- close(h);
-#endif
-}
-
-static void test_invalid_syscall(void) {
- test(_syscall(~0, 0, 0, 0, 0, 0) < 0);
-}
-
-void r_k_misc(void) {
- run_test(test_fault_kill);
- run_test(test_efault);
- run_test(test_invalid_syscall);
-}
diff --git a/src/user/app/tests/kernel/miscsyscall.c b/src/user/app/tests/kernel/miscsyscall.c
deleted file mode 100644
index 459da2a..0000000
--- a/src/user/app/tests/kernel/miscsyscall.c
+++ /dev/null
@@ -1,315 +0,0 @@
-#include "../tests.h"
-#include <camellia/errno.h>
-#include <camellia/execbuf.h>
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <string.h>
-#include <unistd.h>
-
-
-static void test_await(void) {
- /* creates 16 child processes, each returning a different value. then checks
- * if await() returns every value exactly once */
- int ret;
- int counts[16] = {0};
-
- for (int i = 0; i < 16; i++)
- if (!fork())
- exit(i);
-
- while ((ret = _sys_await()) != ~0) {
- test(0 <= ret && ret < 16);
- counts[ret]++;
- }
-
- for (int i = 0; i < 16; i++)
- test(counts[i] == 1);
-}
-
-static void test_await2(void) {
- /* hangs on failure */
- if (!fork()) {
- if (!fork()) {
- for (;;) _sys_sleep(1000000000);
- } else {
- exit(123);
- }
- }
- test(_sys_await() == 123);
- test(_sys_await() == ~0); /* don't wait for tombstone */
- _sys_filicide();
-}
-
-static void test_wait2_basic(void) {
- struct sys_wait2 data = {0};
- int pid;
- pid = fork();
- if (pid == 0) {
- exit(420);
- }
- test(_sys_wait2(-1, 0, &data) == pid);
- test(data.status == 420);
- test(_sys_wait2(-1, 0, NULL) == -ECHILD);
-}
-
-static void test_pipe(void) {
- const char *pipe_msgs[2] = {"hello", "world"};
- hid_t ends[2];
- char buf[16];
-
- /* test regular reads / writes */
- test(_sys_pipe(ends, 0) >= 0);
- if (!fork()) {
- /* those repeated asserts ensure that you can't read/write to the wrong ends */
- test(_sys_read(ends[1], buf, 16, 0) < 0);
- test(_sys_write(ends[0], buf, 16, 0, 0) < 0);
-
- test(5 == _sys_write(ends[1], pipe_msgs[0], 5, -1, 0));
-
- test(_sys_read(ends[1], buf, 16, 0) < 0);
- test(_sys_write(ends[0], buf, 16, 0, 0) < 0);
-
- test(5 == _sys_write(ends[1], pipe_msgs[1], 5, -1, 0));
-
- exit(0);
- } else {
- test(_sys_read(ends[1], buf, 16, 0) < 0);
- test(_sys_write(ends[0], buf, 16, 0, 0) < 0);
-
- test(5 == _sys_read(ends[0], buf, 16, 0));
- test(!memcmp(buf, pipe_msgs[0], 5));
-
- test(_sys_read(ends[1], buf, 16, 0) < 0);
- test(_sys_write(ends[0], buf, 16, 0, 0) < 0);
-
- test(5 == _sys_read(ends[0], buf, 16, 0));
- test(!memcmp(buf, pipe_msgs[1], 5));
-
- _sys_await();
- }
- close(ends[0]);
- close(ends[1]);
-
-
- /* writing to pipes with one end closed */
- test(_sys_pipe(ends, 0) >= 0);
- for (int i = 0; i < 16; i++) {
- if (!fork()) {
- close(ends[1]);
- test(_sys_read(ends[0], buf, 16, 0) < 0);
- exit(0);
- }
- }
- close(ends[1]);
- for (int i = 0; i < 16; i++)
- _sys_await();
- close(ends[0]);
-
- test(_sys_pipe(ends, 0) >= 0);
- for (int i = 0; i < 16; i++) {
- if (!fork()) {
- close(ends[0]);
- test(_sys_write(ends[1], buf, 16, 0, 0) < 0);
- exit(0);
- }
- }
- close(ends[0]);
- for (int i = 0; i < 16; i++)
- _sys_await();
- close(ends[1]);
-
-
- /* queueing */
- test(_sys_pipe(ends, 0) >= 0);
- for (int i = 0; i < 16; i++) {
- if (!fork()) {
- test(_sys_write(ends[1], pipe_msgs[0], 5, -1, 0) == 5);
- exit(0);
- }
- }
- close(ends[1]);
- for (int i = 0; i < 16; i++) {
- test(_sys_read(ends[0], buf, sizeof buf, 0) == 5);
- _sys_await();
- }
- test(_sys_read(ends[0], buf, sizeof buf, 0) < 0);
- close(ends[0]);
-
- test(_sys_pipe(ends, 0) >= 0);
- for (int i = 0; i < 16; i++) {
- if (!fork()) {
- memset(buf, 0, sizeof buf);
- test(_sys_read(ends[0], buf, 5, -1) == 5);
- test(!memcmp(buf, pipe_msgs[1], 5));
- exit(0);
- }
- }
- close(ends[0]);
- for (int i = 0; i < 16; i++) {
- test(_sys_write(ends[1], pipe_msgs[1], 5, -1, 0) == 5);
- _sys_await();
- }
- test(_sys_write(ends[1], pipe_msgs[1], 5, -1, 0) < 0);
- close(ends[1]);
-
-
- // not a to.do detect when all processes that can read are stuck on writing to the pipe and vice versa
- // it seems like linux just lets the process hang endlessly.
-}
-
-static void test_memflag(void) {
- void *page = (void*)0x77777000;
- _sys_memflag(page, 4096, MEMFLAG_PRESENT); // allocate page
- memset(page, 77, 4096); // write to it
- _sys_memflag(page, 4096, 0); // free it
-
- if (!fork()) {
- memset(page, 11, 4096); // should segfault
- exit(0);
- } else {
- test(_sys_await() != 0); // test if the process crashed
- }
-
- char *pages[4];
- for (size_t i = 0; i < 4; i++) {
- pages[i] = _sys_memflag(NULL, 4096, MEMFLAG_FINDFREE);
- test(pages[i] == _sys_memflag(NULL, 4096, MEMFLAG_FINDFREE | MEMFLAG_PRESENT));
- if (i > 0) test(pages[i] != pages[i-1]);
- *pages[i] = 0x77;
- }
-
- for (size_t i = 0; i < 4; i++)
- _sys_memflag(pages, 4096, MEMFLAG_PRESENT);
-}
-
-static void test_dup(void) {
- hid_t pipe[2];
- hid_t h1, h2;
- test(_sys_pipe(pipe, 0) >= 0);
-
- if (!fork()) {
- close(pipe[0]);
-
- h1 = _sys_dup(pipe[1], -1, 0);
- test(h1 >= 0);
- test(h1 != pipe[1]);
- h2 = _sys_dup(h1, -1, 0);
- test(h2 >= 0);
- test(h2 != pipe[1] && h2 != h1);
-
- _sys_write(pipe[1], "og", 2, 0, 0);
- _sys_write(h1, "h1", 2, 0, 0);
- _sys_write(h2, "h2", 2, 0, 0);
-
- close(pipe[1]);
- _sys_write(h1, "h1", 2, 0, 0);
- _sys_write(h2, "h2", 2, 0, 0);
-
- test(_sys_dup(h1, pipe[1], 0) == pipe[1]);
- test(_sys_dup(h2, pipe[1], 0) == pipe[1]);
- test(_sys_dup(h1, pipe[1], 0) == pipe[1]);
- test(_sys_dup(h2, pipe[1], 0) == pipe[1]);
- close(h1);
- close(h2);
-
- test(_sys_dup(pipe[1], h2, 0) == h2);
- _sys_write(h2, "h2", 2, 0, 0);
- close(h2);
-
- test(_sys_dup(pipe[1], h1, 0) == h1);
- _sys_write(h1, "h1", 2, 0, 0);
- close(h1);
-
- exit(0);
- } else {
- char buf[16];
- size_t count = 0;
- close(pipe[1]);
- while (_sys_read(pipe[0], buf, sizeof buf, 0) >= 0)
- count++;
- test(count == 7);
- _sys_await();
- }
-
-
- close(pipe[0]);
-}
-
-static void test_execbuf(void) {
- if (!fork()) {
- uint64_t buf[] = {
- EXECBUF_SYSCALL, _SYS_EXIT, 123, 0, 0, 0, 0,
- };
- _sys_execbuf(buf, sizeof buf);
- test_fail();
- } else {
- test(_sys_await() == 123);
- }
-}
-
-static void test_sleep(void) {
- hid_t reader;
- FILE *writer;
- if (!forkpipe(&writer, &reader)) {
- if (!fork()) {
- if (!fork()) {
- _sys_sleep(100);
- fprintf(writer, "1");
- _sys_sleep(200);
- fprintf(writer, "3");
- _sys_sleep(200);
- fprintf(writer, "5");
- _sys_exit(0);
- }
- if (!fork()) {
- fprintf(writer, "0");
- _sys_sleep(200);
- fprintf(writer, "2");
- _sys_sleep(200);
- fprintf(writer, "4");
- /* get killed while asleep
- * a peaceful death, i suppose. */
- for (;;) _sys_sleep(1000000000);
- }
- _sys_await();
- _sys_filicide();
- _sys_exit(0);
- }
-
- /* this part checks if, after killing an asleep process,
- * other processes can still wake up */
- _sys_sleep(600);
- fprintf(writer, "6");
- exit(0);
- } else {
- const char *expected = "0123456";
- size_t target = strlen(expected);
- size_t pos = 0;
- for (;;) {
- char buf[128];
- long ret = _sys_read(reader, buf, sizeof buf, 0);
- if (ret < 0) break;
- test(pos + ret <= target);
- test(memcmp(buf, expected + pos, ret) == 0);
- pos += ret;
- }
- test(pos == target);
- }
-}
-
-static void test_badopen(void) {
- test(_sys_open(TMPFILEPATH, strlen(TMPFILEPATH), OPEN_CREATE | OPEN_WRITE) >= 0);
- test(_sys_open(TMPFILEPATH, strlen(TMPFILEPATH), OPEN_CREATE) == -EINVAL);
-}
-
-void r_k_miscsyscall(void) {
- run_test(test_await);
- run_test(test_await2);
- run_test(test_wait2_basic);
- run_test(test_pipe);
- run_test(test_memflag);
- run_test(test_dup);
- run_test(test_execbuf);
- run_test(test_sleep);
- run_test(test_badopen);
-}
diff --git a/src/user/app/tests/kernel/path.c b/src/user/app/tests/kernel/path.c
deleted file mode 100644
index 5a22c36..0000000
--- a/src/user/app/tests/kernel/path.c
+++ /dev/null
@@ -1,108 +0,0 @@
-#include "../tests.h"
-#include <camellia/path.h>
-#include <string.h>
-#include <camellia/compat.h>
-#include <camellia/fs/misc.h>
-
-static void test_path_simplify(void) {
- const char *testcases[][2] = {
- {"/", "/"},
- {"/.", "/"},
- {"//", "/"},
- {"/asdf", "/asdf"},
- {"/asdf/", "/asdf/"},
- {"/asdf//", "/asdf/"},
- {"/asdf/./", "/asdf/"},
- {"/a/./b", "/a/b"},
- {"/a/./b/", "/a/b/"},
-
- // some slightly less easy cases
- {"/asdf/..", "/"},
- {"/asdf/../", "/"},
- {"/asdf/.", "/asdf/"},
- {"/asdf//.", "/asdf/"},
-
- {"/foo/bar/..", "/foo/"},
- {"/foo/bar/../baz", "/foo/baz"},
- {"/foo/bar/../baz/", "/foo/baz/"},
- {"/foo/bar/xyz/..", "/foo/bar/"},
- {"/foo/bar/xyz/../", "/foo/bar/"},
-
- // going under the root or close to it
- {"/..", NULL},
- {"/../asdf", NULL},
- {"/../asdf/", NULL},
- {"/./a/../..", NULL},
- {"/a/a/../..", "/"},
- {"/a/../a/..", "/"},
- {"/a/../../a", NULL},
- {"/../a/../a", NULL},
- {"/../../a/a", NULL},
- {"/////../..", NULL},
- {"//a//../..", NULL},
-
- // relative paths aren't allowed
- {"relative", NULL},
- {"some/stuff", NULL},
- {"./stuff", NULL},
- {"../stuff", NULL},
- {"", NULL},
- };
-
- char buf[256];
- for (size_t i = 0; i < sizeof(testcases) / sizeof(testcases[0]); i++) {
- const char *input = testcases[i][0];
- const char *expected = testcases[i][1];
- int len = path_simplify(input, buf, strlen(input));
- if (expected == NULL) {
- test(len == 0);
- } else {
- // TODO an argument for printing info on test failure
- test(len == (int)strlen(expected) && !memcmp(expected, buf, len));
- }
- }
-}
-
-static void mount_resolve_drv(const char *path) {
- if (mount_at(path) != 0) return;
-
- struct ufs_request res;
- while (!c0_fs_wait(NULL, 0, &res)) {
- // TODO does the first argument of c0_fs_respond need to be non-const?
- c0_fs_respond((void*)path, strlen(path), 0);
- }
- exit(1);
-}
-
-static void test_mount_resolve(void) {
- const char *testcases[][2] = {
- {"/", "/"},
- {"/test", "/"},
- {"/dir", "/dir"},
- {"/dir/..", "/"},
- {"/dir/../dir", "/dir"},
- {"/dirry", "/"},
- {"/dir/", "/dir"},
- {"/dir/shadowed", "/dir"},
- {"/dir/shadowed/", "/dir"},
- };
- mount_resolve_drv("/");
- mount_resolve_drv("/dir/shadowed");
- mount_resolve_drv("/dir");
-
- char buf[16];
- for (size_t i = 0; i < sizeof(testcases) / sizeof(testcases[0]); i++) {
- const char *input = testcases[i][0];
- const char *expected = testcases[i][1];
- hid_t h = _sys_open(input, strlen(input), 0);
- test(h >= 0);
- int len = _sys_read(h, buf, sizeof buf, 0);
- test(len == (int)strlen(expected) && !memcmp(expected, buf, len));
- _sys_close(h);
- }
-}
-
-void r_k_path(void) {
- run_test(test_path_simplify);
- run_test(test_mount_resolve);
-}
diff --git a/src/user/app/tests/kernel/threads.c b/src/user/app/tests/kernel/threads.c
deleted file mode 100644
index b3c1c06..0000000
--- a/src/user/app/tests/kernel/threads.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include "../tests.h"
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <string.h>
-#include <esemaphore.h>
-#include <thread.h>
-
-int global_n;
-static void basic_thread(void *sem) {
- global_n = 10;
- esem_signal(sem);
-}
-static void test_basic_thread(void) {
- struct evil_sem *sem = esem_new(0);
- global_n = 0;
- thread_create(FORK_NOREAP, basic_thread, sem);
- esem_wait(sem);
- test(global_n == 10);
-}
-
-hid_t global_h;
-static void shared_handle(void *sem) {
- hid_t ends[2];
- test(_sys_pipe(ends, 0) >= 0);
- global_h = ends[0];
- esem_signal(sem);
- _sys_write(ends[1], "Hello!", 7, -1, 0);
-}
-static void test_shared_handle(void) {
- struct evil_sem *sem = esem_new(0);
- char buf[16];
- global_h = -1;
- thread_create(FORK_NOREAP, shared_handle, sem);
- esem_wait(sem);
-
- test(global_h >= 0);
- test(_sys_read(global_h, buf, sizeof buf, 0) == 7);
- test(!strcmp("Hello!", buf));
-}
-
-static void many_thread(void *arg) {
- *(uint64_t*)arg += 10;
-}
-static void test_many_threads(void) {
- uint64_t n = 0;
- for (int i = 0; i < 10; i++) thread_create(0, many_thread, &n);
- for (int i = 0; i < 10; i++) _sys_await();
- test(n == 100);
-}
-
-void r_k_threads(void) {
- run_test(test_basic_thread);
- run_test(test_shared_handle);
- run_test(test_many_threads);
-}
diff --git a/src/user/app/tests/libc/esemaphore.c b/src/user/app/tests/libc/esemaphore.c
deleted file mode 100644
index f089f4f..0000000
--- a/src/user/app/tests/libc/esemaphore.c
+++ /dev/null
@@ -1,95 +0,0 @@
-#include "../tests.h"
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <esemaphore.h>
-
-static void odd(hid_t out, struct evil_sem *sem1, struct evil_sem *sem2) {
- _sys_write(out, "1", 1, -1, 0);
- esem_signal(sem1);
-
- esem_wait(sem2);
- _sys_write(out, "3", 1, -1, 0);
- esem_signal(sem1);
-
- esem_wait(sem2);
- _sys_write(out, "5", 1, -1, 0);
- esem_signal(sem1);
-}
-
-static void even(hid_t out, struct evil_sem *sem1, struct evil_sem *sem2) {
- esem_wait(sem1);
- _sys_write(out, "2", 1, -1, 0);
- esem_signal(sem2);
-
- esem_wait(sem1);
- _sys_write(out, "4", 1, -1, 0);
- esem_signal(sem2);
-
- esem_wait(sem1);
- _sys_write(out, "6", 1, -1, 0);
- esem_signal(sem2);
-}
-
-static void test_semaphore(void) {
- struct evil_sem *sem1, *sem2;
- hid_t pipe[2];
- test(_sys_pipe(pipe, 0) >= 0);
-
- if (!fork()) {
- sem1 = esem_new(0);
- sem2 = esem_new(0);
- test(sem1 && sem2);
- if (!fork()) {
- odd(pipe[1], sem1, sem2);
- exit(69);
- } else {
- even(pipe[1], sem1, sem2);
- test(_sys_await() == 69);
- }
- esem_free(sem1);
- esem_free(sem2);
-
- _sys_write(pipe[1], "|", 1, -1, 0);
-
- sem1 = esem_new(0);
- sem2 = esem_new(0);
- test(sem1 && sem2);
- if (!fork()) {
- even(pipe[1], sem1, sem2);
- exit(69);
- } else {
- odd(pipe[1], sem1, sem2);
- test(_sys_await() == 69);
- _sys_await();
- }
- esem_free(sem1);
- esem_free(sem2);
-
- _sys_filicide();
- exit(0);
- } else {
- close(pipe[1]);
-
- char buf[16];
- size_t pos = 0;
- for (;;) {
- int ret = _sys_read(pipe[0], buf + pos, sizeof(buf) - pos, 0);
- if (ret < 0) break;
- pos += ret;
- }
- buf[pos] = '\0'; // idc about the "potential" overflow
- if (strcmp(buf, "123456|123456")) {
- printf("%s\n", buf);
- test_fail();
- }
-
- _sys_await();
- }
-}
-
-void r_libc_esemaphore(void) {
- run_test(test_semaphore);
-}
diff --git a/src/user/app/tests/libc/setjmp.c b/src/user/app/tests/libc/setjmp.c
deleted file mode 100644
index 0dded9d..0000000
--- a/src/user/app/tests/libc/setjmp.c
+++ /dev/null
@@ -1,31 +0,0 @@
-#include "../tests.h"
-#include <stdbool.h>
-#include <setjmp.h>
-
-static void test_setjmp(void) {
- jmp_buf env;
- volatile bool inner;
- int val;
- inner = false;
- if (!(val = setjmp(env))) {
- inner = true;
- longjmp(env, 1234);
- test(0);
- } else {
- test(val == 1234);
- test(inner);
- }
- inner = false;
- if (!(val = setjmp(env))) {
- inner = true;
- longjmp(env, 0);
- test(0);
- } else {
- test(val == 1);
- test(inner);
- }
-}
-
-void r_libc_setjmp(void) {
- run_test(test_setjmp);
-}
diff --git a/src/user/app/tests/libc/string.c b/src/user/app/tests/libc/string.c
deleted file mode 100644
index 6afe350..0000000
--- a/src/user/app/tests/libc/string.c
+++ /dev/null
@@ -1,124 +0,0 @@
-#include "../tests.h"
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-
-static void test_memcmp(void) {
- test(0 == memcmp("some", "thing", 0));
- test(0 != memcmp("some", "thing", 1));
- test(0 != memcmp("some", "thing", 4));
-
- test(0 == memcmp("test", "tennis", 0));
- test(0 == memcmp("test", "tennis", 1));
- test(0 == memcmp("test", "tennis", 2));
- test(0 != memcmp("test", "tennis", 3));
- test(0 != memcmp("test", "tennis", 4));
- test(0 != memcmp("test", "tennis", 5));
-
- test(0 > memcmp("foo", "moo", 4));
- test(0 < memcmp("moo", "foo", 4));
- test(0 > memcmp("555", "654", 3));
- test(0 < memcmp("654", "555", 3));
-}
-
-static bool memall(const unsigned char *s, unsigned char c, size_t n) {
- for (size_t i = 0; i < n; i++)
- if (s[i] != c) return false;
- return true;
-}
-
-static void test_memset(void) {
- const size_t buflen = 4096;
- void *buf = malloc(buflen);
- test(buf);
- for (int i = 0; i < 257; i++) {
- memset(buf, i, buflen);
- test(memall(buf, i & 0xff, buflen));
- }
- free(buf);
-}
-
-static void test_memmove(void) {
- const int partsize = 64;
- char buf[partsize * 3];
- for (int i = 0; i < partsize * 2; i++) {
- memset(buf, 0, sizeof buf);
- for (int j = 0; j < partsize; j++) buf[i + j] = j;
- memmove(buf + partsize, buf + i, partsize);
- for (int j = 0; j < partsize; j++) test(buf[partsize + j] == j);
- }
-}
-
-static void test_strcmp(void) {
- test(0 == strcmp("string", "string"));
- test(0 > strcmp("str", "string"));
- test(0 < strcmp("string", "str"));
-
- test(0 != strcmp("stress", "string"));
-
- test(0 != strncmp("abc", "ab", 3));
- test(0 == strncmp("abc", "ab", 2));
-}
-
-static void test_strtol(void) {
- char *end;
- test(1234 == strtol("1234", NULL, 10));
- test(1234 == strtol("+1234", NULL, 10));
- test(-1234 == strtol("-1234", NULL, 10));
-
- test(1234 == strtol("1234", &end, 10));
- test(!strcmp("", end));
- test(1234 == strtol(" 1234hello", &end, 10));
- test(!strcmp("hello", end));
-
- test(1234 == strtol(" 1234hello", &end, 0));
- test(!strcmp("hello", end));
- test(0xCAF3 == strtol(" 0xCaF3hello", &end, 0));
- test(!strcmp("hello", end));
- test(01234 == strtol(" 01234hello", &end, 0));
- test(!strcmp("hello", end));
-}
-
-static void test_strspn(void) {
- test(0 == strspn("", "1234"));
- test(0 == strspn("asdf", "1234"));
- test(0 == strspn("a2df", "1234"));
- test(2 == strspn("42df", "1234"));
- test(4 == strspn("4211", "1234"));
-
- test(0 == strcspn("", "1234"));
- test(4 == strcspn("asdf", "1234"));
- test(1 == strcspn("a2df", "1234"));
-}
-
-static void test_strtok(void) {
- const char *sep = " \t";
- {
- char line[] = "LINE TO BE SEPARATED";
- test(!strcmp(strtok(line, sep), "LINE"));
- test(!strcmp(strtok(NULL, sep), "TO"));
- test(!strcmp(strtok(NULL, sep), "BE"));
- test(!strcmp(strtok(NULL, sep), "SEPARATED"));
- for (int i = 0; i < 4; i++)
- test(strtok(NULL, sep) == NULL);
- }
- {
- char line[] = " LINE TO\tBE \t SEPARATED ";
- test(!strcmp(strtok(line, sep), "LINE"));
- test(!strcmp(strtok(NULL, sep), "TO"));
- test(!strcmp(strtok(NULL, sep), "BE"));
- test(!strcmp(strtok(NULL, sep), "SEPARATED"));
- for (int i = 0; i < 4; i++)
- test(strtok(NULL, sep) == NULL);
- }
-}
-
-void r_libc_string(void) {
- run_test(test_memcmp);
- run_test(test_memset);
- run_test(test_memmove);
- run_test(test_strcmp);
- run_test(test_strtol);
- run_test(test_strspn);
- run_test(test_strtok);
-}
diff --git a/src/user/app/tests/shared/printf.c b/src/user/app/tests/shared/printf.c
deleted file mode 100644
index d8df48a..0000000
--- a/src/user/app/tests/shared/printf.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include "../tests.h"
-#include <stdio.h>
-#include <string.h>
-
-#pragma GCC diagnostic ignored "-Wformat-truncation"
-
-static void test_printf(void) {
- char buf[64];
- memset(buf, '?', 64);
-
- /* test proper overflow handling in snprintf */
- test(13 == snprintf(buf, 15, "That's 0x%x", 0x1337));
- test(!memcmp(buf, "That's 0x1337\0??", 16));
- test(17 == snprintf(buf, 15, "%05x %05x %05x", 0, 0, 0));
- test(!memcmp(buf, "00000 00000 00\0?", 16));
-
- /* all the other stuff */
- snprintf(buf, sizeof buf, "%010x", 0x1BABE);
- test(!strcmp(buf, "000001babe"));
- snprintf(buf, sizeof buf, "%10x", 0x1BABE);
- test(!strcmp(buf, " 1babe"));
- snprintf(buf, sizeof buf, "%10s", "hello");
- test(!strcmp(buf, " hello"));
-
- snprintf(buf, sizeof buf, "%s%%%s", "ab", "cd");
- test(!strcmp(buf, "ab%cd"));
-
- snprintf(buf, sizeof buf, "%05u,%05u", 1234, 56789);
- test(!strcmp(buf, "01234,56789"));
-
- snprintf(buf, sizeof buf, "%5d,%5d", 123, 4567);
- test(!strcmp(buf, " 123, 4567"));
- snprintf(buf, sizeof buf, "%5d,%5d", -123, -4567);
- test(!strcmp(buf, " -123,-4567"));
-
- snprintf(buf, sizeof buf, "%u,%d,%x", 0, 0, 0);
- test(!strcmp(buf, "0,0,0"));
-
- /* precision */
- snprintf(buf, sizeof buf, "%5.2u,%5.2d,%5.2x", 0, 0, 0);
- test(!strcmp(buf, " 00, 00, 00"));
- snprintf(buf, sizeof buf, "%5.2u,%5.2d,%5.2x", 10, -10, 0x10);
- test(!strcmp(buf, " 10, -10, 10"));
- snprintf(buf, sizeof buf, "%5.3d", -1);
- test(!strcmp(buf, " -001"));
- snprintf(buf, sizeof buf, "%.5d", 123);
- test(!strcmp(buf, "00123"));
-
- snprintf(buf, sizeof buf, "%.1s,%.10s,%.*s", "hello", "hello", 3, "hello");
- test(!strcmp(buf, "h,hello,hel"));
-}
-
-void r_s_printf(void) {
- run_test(test_printf);
-}
diff --git a/src/user/app/tests/shared/ringbuf.c b/src/user/app/tests/shared/ringbuf.c
deleted file mode 100644
index d2a35a1..0000000
--- a/src/user/app/tests/shared/ringbuf.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#include "../tests.h"
-#include <shared/ring.h>
-#include <string.h>
-
-static void test_ringbuf(void) {
- char backbuf[16], cmpbuf[16];
- size_t num_read = 0, num_written = 0;
- uint8_t c;
-
- ring_t r = {backbuf, 16, 0, 0};
-
- /* aliasing */
- for (size_t i = 0; i < 16; i++) {
- test(ring_used(&r) == 0);
- test(ring_avail(&r) == 16);
- ring_put(&r, "11 bytes...", 11);
- test(ring_used(&r) == 11);
- test(ring_avail(&r) == 5);
-
- memset(cmpbuf, 0, sizeof cmpbuf);
- test(ring_get(&r, cmpbuf, 16) == 11);
- test(memcmp(cmpbuf, "11 bytes...", 11) == 0);
- }
-
- test(ring_used(&r) == 0);
- for (size_t i = 0; i < 7; i++)
- ring_put1b(&r, num_written++);
- test(ring_used(&r) == 7);
- for (size_t i = 0; i < 3; i++) {
- ring_get(&r, &c, 1);
- test(num_read++ == c);
- }
- test(ring_used(&r) == 4);
-
- for (size_t j = 0; j < 40; j++) {
- for (size_t i = 0; i < 7; i++)
- ring_put1b(&r, num_written++ & 0xff);
- test(ring_used(&r) == 11);
- for (size_t i = 0; i < 7; i++) {
- ring_get(&r, &c, 1);
- test((num_read++ & 0xff) == c);
- }
- test(ring_used(&r) == 4);
- }
-}
-
-void r_s_ringbuf(void) {
- run_test(test_ringbuf);
-}
diff --git a/src/user/app/tests/stress.c b/src/user/app/tests/stress.c
deleted file mode 100644
index 1ef018c..0000000
--- a/src/user/app/tests/stress.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include "tests.h"
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-static void run_forked(void (*fn)()) {
- if (!fork()) {
- fn();
- exit(0);
- } else {
- /* successful tests must return 0
- * TODO add a better fail msg */
- if (_sys_await() != 0) test_fail();
- }
-}
-
-
-static void stress_fork(void) {
- for (size_t i = 0; i < 2048; i++) {
- if (!fork()) exit(0);
- _sys_await();
- }
-}
-
-void stress_all(void) {
- run_forked(stress_fork);
-}
diff --git a/src/user/app/tests/tests.c b/src/user/app/tests/tests.c
deleted file mode 100644
index 5cba682..0000000
--- a/src/user/app/tests/tests.c
+++ /dev/null
@@ -1,68 +0,0 @@
-#include "tests.h"
-#include <camellia/syscalls.h>
-#include <unistd.h>
-
-__attribute__((visibility("hidden")))
-extern char __executable_start[];
-
-FILE *fail_trig;
-
-void run_test(void (*fn)()) {
- if (!fork()) {
- fn();
- _sys_filicide();
- exit(0);
- } else {
- /* successful tests must return 0 */
- if (_sys_await() != 0) {
- test_failf("%p, base %p", (void*)((void*)fn - (void*)__executable_start), __executable_start);
- }
- }
-}
-
-int forkpipe(FILE **f, hid_t *h) {
- hid_t ends[2];
- if (_sys_pipe(ends, 0) < 0) {
- fprintf(stderr, "couldn't create pipe\n");
- exit(1);
- }
- int ret = fork();
- if (!ret) {
- close(ends[0]);
- *f = fdopen(ends[1], "w");
- *h = -1;
- } else {
- close(ends[1]);
- *f = NULL;
- *h = ends[0];
- }
- return ret;
-}
-
-int main(void) {
- hid_t reader;
- if (!forkpipe(&fail_trig, &reader)) {
- r_k_miscsyscall();
- r_k_fs();
- r_k_fdlimit();
- r_k_misc();
- r_k_path();
- r_k_threads();
- r_libc_esemaphore();
- r_libc_setjmp();
- r_libc_string();
- r_s_printf();
- r_s_ringbuf();
- exit(0);
- } else {
- for (;;) {
- char buf[128];
- long ret = _sys_read(reader, buf, sizeof buf, 0);
- if (ret < 0) break;
- printf("\033[31mFAIL\033[0m ");
- fwrite(buf, ret, 1, stdout);
- printf("\n");
- }
- }
- return 0;
-}
diff --git a/src/user/app/tests/tests.h b/src/user/app/tests/tests.h
deleted file mode 100644
index 5037e1a..0000000
--- a/src/user/app/tests/tests.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#pragma once
-#include <camellia/syscalls.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#define TMPFILEPATH "/tmp/.test_internal"
-
-void run_test(void (*fn)());
-
-void r_k_fdlimit(void);
-void r_k_fs(void);
-void r_k_misc(void);
-void r_k_miscsyscall(void);
-void r_k_path(void);
-void r_k_threads(void);
-void r_libc_esemaphore(void);
-void r_libc_setjmp(void);
-void r_libc_string(void);
-void r_s_printf(void);
-void r_s_ringbuf(void);
-
-extern FILE *fail_trig;
-
-int forkpipe(FILE **f, hid_t *h);
-
-#define argify(str) str, sizeof(str) - 1
-#define test_fail() do { \
- fprintf(fail_trig, "%s():%u", __func__, __LINE__); \
- fflush(fail_trig); \
- exit(0); \
-} while (0)
-#define test_failf(fmt, ...) do { \
- fprintf(fail_trig, "%s():%u " fmt, __func__, __LINE__, __VA_ARGS__); \
- fflush(fail_trig); \
- exit(0); \
-} while (0)
-#define test(cond) if (!(cond)) test_fail();
diff --git a/src/user/app/tmpfs/tmpfs.c b/src/user/app/tmpfs/tmpfs.c
deleted file mode 100644
index 6d58790..0000000
--- a/src/user/app/tmpfs/tmpfs.c
+++ /dev/null
@@ -1,198 +0,0 @@
-#include <camellia/flags.h>
-#include <camellia/fs/dir.h>
-#include <camellia/fs/misc.h>
-#include <camellia/fsutil.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-struct node {
- char *name;
- size_t namelen;
- bool directory;
- char *buf;
- size_t size, capacity;
-
- size_t open; /* amount of open handles */
-
- struct node *sibling, *child;
- /* Pointer to the sibling/child field referencing the node. NULL for removed
- * files. */
- struct node **ref;
-
- /* allocated by tmpfs_open
- * freed by node_close when (open == 0 && ref == NULL && self != node_root). */
-};
-
-static struct node node_root = {
- .directory = true,
-};
-
-/** Responds to open(), finding an existing node, or creating one when applicable. */
-static struct node *tmpfs_open(const char *path, struct ufs_request *req);
-/** Finds a direct child with the given name. */
-static struct node *node_getchild(struct node *parent, const char *name, size_t len);
-/** Corresponds to close(); drops a reference. */
-static void node_close(struct node *node);
-/** Removes a file. It's kept in memory until all the open handles are closed. */
-static long node_remove(struct node *node);
-
-
-static struct node *node_getchild(struct node *parent, const char *name, size_t len) {
- for (struct node *iter = parent->child; iter; iter = iter->sibling) {
- if (iter->namelen == len && !memcmp(name, iter->name, len)) {
- return iter;
- }
- }
- return NULL;
-}
-
-static struct node *tmpfs_open(const char *path, struct ufs_request *req) {
- /* *path is not null terminated! */
- struct node *node = &node_root;
- if (req->len == 0) return NULL;
- if (req->len == 1) return node; /* "/" */
- path++;
- req->len--;
-
- bool more = true;
- size_t segpos = 0, seglen; /* segments end with a slash, inclusive */
- while (more) {
- struct node *parent = node;
- char *slash = memchr(path + segpos, '/', req->len - segpos);
- seglen = (slash ? (size_t)(slash - path + 1) : req->len) - segpos;
- more = segpos + seglen < req->len;
-
- node = node_getchild(parent, path + segpos, seglen);
- if (!node) {
- if (!more && (req->flags & OPEN_CREATE)) {
- node = calloc(1, sizeof *node);
-
- node->name = malloc(seglen + 1);
- if (node->name == NULL) {
- free(node);
- return NULL;
- }
- memcpy(node->name, path + segpos, seglen);
- node->name[seglen] = '\0';
-
- node->directory = slash;
- node->namelen = seglen;
- if (parent->child) {
- parent->child->ref = &node->sibling;
- *parent->child->ref = parent->child;
- }
- node->ref = &parent->child;
- *node->ref = node;
- } else {
- return NULL;
- }
- }
- segpos += seglen;
- }
- node->open++;
- return node;
-}
-
-static void node_close(struct node *node) {
- node->open--;
- if (!node->ref && node != &node_root && node->open == 0) {
- free(node->buf);
- free(node);
- }
-}
-
-static long node_remove(struct node *node) {
- if (node == &node_root) return -1;
- if (!node->ref) return -1;
- if (node->child) return -ENOTEMPTY;
- *node->ref = node->sibling;
- node->ref = NULL;
- node_close(node);
- return 0;
-}
-
-int main(void) {
- const size_t buflen = 4096;
- char *buf = malloc(buflen);
- if (!buf) return -1;
-
- for (;;) {
- struct ufs_request req;
- hid_t reqh = ufs_wait(buf, buflen, &req);
- struct node *ptr = req.id;
- if (reqh < 0) break;
-
- switch (req.op) {
- case VFSOP_OPEN:
- ptr = tmpfs_open(buf, &req);
- _sys_fs_respond(reqh, ptr, ptr ? 0 : -ENOENT, 0);
- break;
-
- case VFSOP_READ:
- if (ptr->directory) {
- struct dirbuild db;
- dir_start(&db, req.offset, buf, buflen);
- for (struct node *iter = ptr->child; iter; iter = iter->sibling) {
- dir_appendl(&db, iter->name, iter->namelen);
- }
- _sys_fs_respond(reqh, buf, dir_finish(&db), 0);
- } else {
- fs_normslice(&req.offset, &req.len, ptr->size, false);
- _sys_fs_respond(reqh, ptr->buf + req.offset, req.len, 0);
- }
- break;
-
- case VFSOP_WRITE:
- if (ptr->directory) {
- _sys_fs_respond(reqh, NULL, -ENOSYS, 0);
- break;
- }
-
- fs_normslice(&req.offset, &req.len, ptr->size, true);
- if (ptr->capacity <= req.offset + req.len) {
- ptr->capacity = (req.offset + req.len + 511) & ~511;
- ptr->buf = realloc(ptr->buf, ptr->capacity);
- }
-
- memcpy(ptr->buf + req.offset, buf, req.len);
- if ((req.flags & WRITE_TRUNCATE) || ptr->size < req.offset + req.len) {
- ptr->size = req.offset + req.len;
- }
- _sys_fs_respond(reqh, NULL, req.len, 0);
- break;
-
- case VFSOP_GETSIZE:
- if (ptr->directory) {
- // TODO could be cached in ptr->size
- struct dirbuild db;
- dir_start(&db, req.offset, NULL, buflen);
- for (struct node *iter = ptr->child; iter; iter = iter->sibling) {
- dir_append(&db, iter->name);
- }
- _sys_fs_respond(reqh, NULL, dir_finish(&db), 0);
- } else {
- _sys_fs_respond(reqh, NULL, ptr->size, 0);
- }
- break;
-
- case VFSOP_REMOVE:
- _sys_fs_respond(reqh, NULL, node_remove(ptr), 0);
- break;
-
- case VFSOP_CLOSE:
- node_close(ptr);
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
-
- default:
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
- }
- return 1;
-}
diff --git a/src/user/app/vterm/draw.c b/src/user/app/vterm/draw.c
deleted file mode 100644
index ee36a0f..0000000
--- a/src/user/app/vterm/draw.c
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "vterm.h"
-#include <camellia/execbuf.h>
-#include <camellia/syscalls.h>
-#include <string.h>
-
-struct framebuf fb;
-struct rect dirty;
-
-void scroll(void) {
- size_t row_len = fb.pitch * font.h;
- memmove(fb.b, fb.b + row_len, fb.len - row_len);
- memset(fb.b + fb.len - row_len, 0, row_len);
- cursor.y--;
-
- dirty.x1 = 0; dirty.y1 = 0;
- dirty.x2 = ~0; dirty.y2 = ~0;
-}
diff --git a/src/user/app/vterm/font.c b/src/user/app/vterm/font.c
deleted file mode 100644
index 777b094..0000000
--- a/src/user/app/vterm/font.c
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "vterm.h"
-#include <err.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-struct psf2 font;
-void *font_data;
-
-void font_load(const char *path) {
- FILE *f = fopen(path, "r");
- if (!f) {
- err(1, "couldn't open font \"%s\"", path);
- }
-
- void *buf;
- long buflen;
-
- fseek(f, 0, SEEK_END);
- buflen = ftell(f);
- if (buflen < 0) {
- errx(1, "can't get the size of \"%s\"", path);
- }
-
- buf = malloc(buflen);
- if (!buf) {
- err(1, "out of memory");
- }
-
- fseek(f, 0, SEEK_SET);
- fread(buf, 1, buflen, f);
- if (ferror(f)) {
- err(1, "error reading font");
- }
- fclose(f);
-
- if (!memcmp(buf, "\x72\xb5\x4a\x86", 4)) {
- memcpy(&font, buf, sizeof font);
- font_data = buf + font.glyph_offset;
- } else if (!memcmp(buf, "\x36\x04", 2)) {
- struct psf1 *hdr = buf;
- font = (struct psf2){
- .glyph_amt = 256,
- .glyph_size = hdr->h,
- .h = hdr->h,
- .w = 8,
- };
- font_data = buf + 4;
- } else {
- errx(1, "invalid psf header");
- }
-}
-
-void font_blit(uint32_t glyph, int x, int y) {
- if (glyph >= font.glyph_amt) glyph = 0;
- if (x < 0 || (x+1) * font.w >= fb.width ||
- y < 0 || (y+1) * font.h >= fb.height)
- {
- return;
- }
-
- dirty_mark(&dirty, x * font.w, y * font.h);
- dirty_mark(&dirty, (x+1) * font.w - 1, (y+1) * font.h - 1);
-
- char *bitmap = font_data + font.glyph_size * glyph;
- for (size_t i = 0; i < font.w; i++) {
- for (size_t j = 0; j < font.h; j++) {
- size_t idx = j * font.w + i;
- char byte = bitmap[idx / 8];
- byte >>= (7-(idx&7));
- byte &= 1;
- *((uint32_t*)&fb.b[fb.pitch * (y * font.h + j) + 4 * (x * font.w + i)]) = byte * 0xB0B0B0;
- }
- }
- return;
-}
diff --git a/src/user/app/vterm/vterm.c b/src/user/app/vterm/vterm.c
deleted file mode 100644
index f365f6b..0000000
--- a/src/user/app/vterm/vterm.c
+++ /dev/null
@@ -1,72 +0,0 @@
-#include "vterm.h"
-#include <camellia/syscalls.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <camellia/compat.h>
-
-struct point cursor = {0};
-
-void in_char(char c) {
- switch (c) {
- case '\n':
- cursor.x = 0;
- cursor.y++;
- break;
- case '\b':
- if (cursor.x > 0) cursor.x--;
- break;
- case '\t':
- /* rounds down to nearest multiple of 8 and adds 8
- = adding 1 and rounding up to the nearest multiple of 8 */
- cursor.x = (cursor.x & ~7) + 8;
- break;
- default:
- font_blit(c, cursor.x, cursor.y);
- cursor.x++;
- }
-
- if (cursor.x * font.w >= fb.width) {
- cursor.x = 0;
- cursor.y++;
- }
- while ((cursor.y + 1) * font.h >= fb.height) scroll();
-}
-
-int main(void) {
- if (fb_setup(&fb, "/kdev/video/") < 0) {
- eprintf("fb_setup error");
- return 1;
- }
- font_load("/init/usr/share/fonts/spleen/spleen-8x16.psfu");
-
- static char buf[512];
- struct ufs_request res;
- while (!c0_fs_wait(buf, sizeof buf, &res)) {
- switch (res.op) {
- case VFSOP_OPEN:
- // TODO check path
- c0_fs_respond(NULL, 0, 0);
- break;
-
- case VFSOP_WRITE:
- if (res.flags) {
- c0_fs_respond(NULL, -1, 0);
- } else {
- for (size_t i = 0; i < res.len; i++)
- in_char(buf[i]);
- dirty_flush(&dirty, &fb);
- c0_fs_respond(NULL, res.len, 0);
- }
- break;
-
- default:
- c0_fs_respond(NULL, -1, 0);
- break;
- }
- }
-
- return 1;
-}
diff --git a/src/user/app/vterm/vterm.h b/src/user/app/vterm/vterm.h
deleted file mode 100644
index 026e71a..0000000
--- a/src/user/app/vterm/vterm.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#pragma once
-#include <camellia/types.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <draw.h>
-
-#define eprintf(fmt, ...) fprintf(stderr, "vterm: "fmt"\n" __VA_OPT__(,) __VA_ARGS__)
-
-
-struct psf1 {
- uint16_t magic;
- uint8_t mode;
- uint8_t h;
-} __attribute__((packed));
-struct psf2 {
- uint32_t magic;
- uint32_t version;
- uint32_t glyph_offset;
- uint32_t flags;
- uint32_t glyph_amt;
- uint32_t glyph_size;
- uint32_t h;
- uint32_t w;
-} __attribute__((packed));
-extern struct psf2 font;
-extern void *font_data;
-void font_load(const char *path);
-void font_blit(uint32_t glyph, int x, int y);
-
-extern struct framebuf fb;
-
-extern struct rect dirty;
-void vdirty_mark(uint32_t x, uint32_t y);
-void flush(void);
-void scroll(void);
-
-struct point {uint32_t x, y;};
-extern struct point cursor;
-void in_char(char c);
diff --git a/src/user/bootstrap/entry.S b/src/user/bootstrap/entry.S
deleted file mode 100644
index bd1b417..0000000
--- a/src/user/bootstrap/entry.S
+++ /dev/null
@@ -1,27 +0,0 @@
-#define ASM_FILE 1
-#include <camellia/syscalls.h>
-#include <camellia/flags.h>
-
-.set STACK_TOP, 0xFFFFFFFFFFFFFFFF
-.set STACK_PAGES, 4
-
-.section .text.startup
-.global _start
-.type _start, @function
-_start:
- mov $_SYS_MEMFLAG, %rdi
- mov $(STACK_TOP & ~0xFFF - (STACK_PAGES - 1) * 0x1000), %rsi
- mov $(STACK_PAGES * 0x1000), %rdx
- mov $MEMFLAG_PRESENT, %r10
- syscall
-
- mov $_SYS_MEMFLAG, %rdi
- mov $_bss_start, %rsi
- mov $_bss_end, %rdx
- sub $_bss_start, %rdx
- mov $MEMFLAG_PRESENT, %r10
- mov %rsp, %r8
- syscall
-
- mov $(STACK_TOP & ~0xF), %rsp
- call main // and don't you dare return
diff --git a/src/user/bootstrap/linker.ld b/src/user/bootstrap/linker.ld
deleted file mode 100644
index 10e3f98..0000000
--- a/src/user/bootstrap/linker.ld
+++ /dev/null
@@ -1,31 +0,0 @@
-ENTRY(_start)
-
-SECTIONS
-{
- . = 0x20000;
- _bss_start = .;
- .bss BLOCK(4K) : ALIGN(4K)
- {
- *(COMMON)
- *(.bss)
- }
- _bss_end = .;
-
- . = 2M;
- .text BLOCK(4K) : ALIGN(4K)
- {
- /* the assert needs to be inside of a section or it'll be a syntax error */
- ASSERT(_bss_end <= 2M, "bss too big, needs to be moved down");
- *(.text.startup)
- *(.text)
- }
- .rodata BLOCK(4K) : ALIGN(4K)
- {
- *(.rodata)
- }
- .data BLOCK(4K) : ALIGN(4K)
- {
- *(.data*)
- }
- _initrd = .; /* is just appended onto the end of the binary */
-}
diff --git a/src/user/bootstrap/main.c b/src/user/bootstrap/main.c
deleted file mode 100644
index d27da39..0000000
--- a/src/user/bootstrap/main.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <_proc.h>
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <stdio.h>
-#include <string.h>
-#include <elfload.h>
-#include <camellia/fs/misc.h>
-
-#include "tar.h"
-
-extern char _bss_start;
-extern char _bss_end;
-extern char _initrd;
-
-__attribute__((section(".text")))
-int main(void) {
- _sys_memflag(_psdata_loc, 1, MEMFLAG_PRESENT);
- setprogname("bootstrap");
-
- _sys_mount(HANDLE_PROCFS, "/proc/", strlen("/proc/"));
- MOUNT_AT("/") {
- fs_dirinject2((const char*[]) {
- "/proc/",
- "/init/",
- NULL
- });
- }
- MOUNT_AT("/init/") {
- tar_driver(&_initrd);
- }
-
- const char *initpath = "bin/amd64/init";
- char *initargv[] = {"init", NULL};
- void *init = tar_find(initpath, strlen(initpath), &_initrd, ~0) + 512;
- if (init) {
- _klogf("execing init");
- elf_exec(init, initargv, NULL);
- _klogf("elf_exec failed");
- } else {
- _klogf("couldn't find init.elf");
- }
- _sys_exit(1);
-}
diff --git a/src/user/bootstrap/tar.c b/src/user/bootstrap/tar.c
deleted file mode 100644
index 2020fe0..0000000
--- a/src/user/bootstrap/tar.c
+++ /dev/null
@@ -1,155 +0,0 @@
-#include "tar.h"
-#include <camellia/flags.h>
-#include <camellia/fsutil.h>
-#include <camellia/syscalls.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <camellia/compat.h>
-#include <camellia/fs/dir.h>
-
-#define BUF_SIZE 64
-
-static void *tar_open(const char *path, int len, void *base, size_t base_len);
-static char tar_type(void *meta);
-static void tar_dirbuild(struct dirbuild *db, const char *meta, void *base, size_t base_len);
-static void tar_read(struct ufs_request *res, void *base, size_t base_len);
-static int tar_size(void *sector);
-static int oct_parse(char *str, size_t len);
-
-
-static const char *root_fakemeta = ""; /* see comment in tar_open */
-
-
-void tar_driver(void *base) {
- static char buf[BUF_SIZE];
- struct ufs_request res;
- void *ptr;
- while (!c0_fs_wait(buf, BUF_SIZE, &res)) {
- switch (res.op) {
- case VFSOP_OPEN:
- ptr = tar_open(buf, res.len, base, ~0);
- c0_fs_respond(ptr, ptr ? 0 : -1, 0);
- break;
-
- case VFSOP_READ:
- tar_read(&res, base, ~0);
- break;
-
- case VFSOP_GETSIZE:
- if (tar_type(res.id) != '5') {
- c0_fs_respond(NULL, tar_size(res.id), 0);
- } else {
- struct dirbuild db;
- dir_start(&db, res.offset, NULL, 0);
- tar_dirbuild(&db, res.id, base, ~0);
- c0_fs_respond(NULL, dir_finish(&db), 0);
- }
- break;
-
- default:
- c0_fs_respond(NULL, -1, 0); // unsupported
- break;
- }
- }
- exit(0);
-}
-
-static char tar_type(void *meta) {
- if (meta == root_fakemeta) return '5';
- return *(char*)(meta + 156);
-}
-
-static void *tar_open(const char *path, int len, void *base, size_t base_len) {
- if (len <= 0) return NULL;
- path += 1; // skip the leading slash
- len -= 1;
-
- /* TAR archives don't (seem to) contain an entry for the root dir, so i'm
- * returning a fake one. this isn't a full entry because i'm currently too
- * lazy to create a full one - thus, it has to be special cased in tar_read */
- if (len == 0)
- return (void*)root_fakemeta;
-
- return tar_find(path, len, base, base_len);
-}
-
-static void tar_dirbuild(struct dirbuild *db, const char *meta, void *base, size_t base_len) {
- size_t meta_len = strlen(meta);
- for (size_t off = 0; off < base_len;) {
- if (0 != memcmp(base + off + 257, "ustar", 5))
- break; // not a metadata sector
-
- /* check if prefix matches */
- if (0 == memcmp(base + off, meta, meta_len)
- && *(char*)(base + off + meta_len) != '\0') {
- char *suffix = base + off + meta_len;
-
- /* check if the path contains any non-trailing slashes */
- char *slash = strchr(suffix, '/');
- if (!slash || slash[1] == '\0') {
- if (dir_append(db, suffix)) break;
- }
- }
-
- int size = tar_size(base + off);
- off += 512; // skip this metadata sector
- off += (size + 511) & ~511; // skip the data sectors
- }
-}
-
-static void tar_read(struct ufs_request *res, void *base, size_t base_len) {
- void *meta = (void*)res->id;
- static char buf[BUF_SIZE];
- // TODO reuse a single buffer for both tar_driver and tar_read
-
- switch (tar_type(meta)) {
- case '\0':
- case '0': /* normal files */
- fs_normslice(&res->offset, &res->len, tar_size(meta), false);
- c0_fs_respond(meta + 512 + res->offset, res->len, 0);
- break;
-
- case '5': /* directory */
- struct dirbuild db;
- dir_start(&db, res->offset, buf, sizeof buf);
- tar_dirbuild(&db, meta, base, base_len);
- c0_fs_respond(buf, dir_finish(&db), 0);
- break;
-
- default:
- c0_fs_respond(NULL, -1, 0);
- break;
- }
-}
-
-static int tar_size(void *sector) {
- return oct_parse(sector + 124, 11);
-}
-
-void *tar_find(const char *path, size_t path_len, void *base, size_t base_len) {
- int size;
- if (path_len > 100) return NULL; // illegal path
-
- for (size_t off = 0; off < base_len;) {
- if (0 != memcmp(base + off + 257, "ustar", 5))
- break; // not a metadata sector
- if (0 == memcmp(base + off, path, path_len) &&
- *(char*)(base + off + path_len) == '\0')
- return base + off; // file found, quit
-
- size = tar_size(base + off);
- off += 512; // skip this metadata sector
- off += (size + 511) & ~511; // skip the data sectors
- }
- return NULL;
-}
-
-static int oct_parse(char *str, size_t len) {
- int res = 0;
- for (size_t i = 0; i < len; i++) {
- res *= 8;
- res += str[i] - '0'; // no format checking
- }
- return res;
-}
diff --git a/src/user/bootstrap/tar.h b/src/user/bootstrap/tar.h
deleted file mode 100644
index e7ab130..0000000
--- a/src/user/bootstrap/tar.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-#include <camellia/types.h>
-#include <stddef.h>
-
-_Noreturn void tar_driver(void *base);
-void *tar_find(const char *path, size_t path_len, void *base, size_t base_len);
diff --git a/src/user/lib/_start.s b/src/user/lib/_start.s
deleted file mode 100644
index 12d2c5f..0000000
--- a/src/user/lib/_start.s
+++ /dev/null
@@ -1,17 +0,0 @@
-.section .text
-.global _start
-.type _start, @function
-.weak _start
-_start:
- mov %rsp, %rdi
- and $~0xF, %rsp
-
- /* prevent floating point crashes. thanks heat */
- push $0x1f80
- ldmxcsr (%rsp)
- add $8, %rsp
-
- call _start2
- hlt
- /* the call shouldn't return, thus the hlt.
- * using a call instead of jmp for stack alignment */
diff --git a/src/user/lib/_start2.c b/src/user/lib/_start2.c
deleted file mode 100644
index b4eb76a..0000000
--- a/src/user/lib/_start2.c
+++ /dev/null
@@ -1,42 +0,0 @@
-#include <_proc.h>
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <elfload.h>
-
-int main(int argc, char **argv, char **envp);
-
-__attribute__((visibility("hidden")))
-extern char __executable_start[];
-
-const char *shortname(const char *path) {
- if (!path) return "unknown program";
- const char *slash = strrchr(path, '/');
- if (slash) return slash + 1;
- return path;
-}
-
-void intr_trampoline(void); /* intr.s */
-
-_Noreturn void _start2(struct execdata *ed) {
- const char *progname;
- elf_selfreloc();
-
- /* done first so it isn't allocated elsewhere by accident */
- _sys_memflag(_psdata_loc, 1, MEMFLAG_PRESENT);
- _psdata_loc->base = __executable_start;
- /* sets ->desc */
- progname = shortname(ed->argv[0]);
- setprogname(progname);
-
- _klogf("_start2 %s %p", progname, __executable_start);
-
- _sys_intr_set(intr_trampoline);
- intr_set(intr_default);
- __setinitialcwd(ed->cwd);
-
- exit(main(ed->argc, ed->argv, ed->envp));
-}
diff --git a/src/user/lib/assert.c b/src/user/lib/assert.c
deleted file mode 100644
index 0c46450..0000000
--- a/src/user/lib/assert.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <assert.h>
-#include <camellia/syscalls.h>
-#include <stdio.h>
-
-_Noreturn void __badassert(const char *func, const char *file, int line) {
- fprintf(stderr, "assertion failure %s:%s:%u\n", file, func, line);
- _sys_exit(1);
-}
diff --git a/src/user/lib/camellia.c b/src/user/lib/camellia.c
deleted file mode 100644
index 4e092e4..0000000
--- a/src/user/lib/camellia.c
+++ /dev/null
@@ -1,30 +0,0 @@
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-hid_t camellia_open(const char *path, int flags) {
- hid_t ret;
- char *buf;
- size_t len;
-
- if (path == NULL)
- return errno = EINVAL, -EINVAL;
- if (flags & OPEN_CREATE)
- flags |= OPEN_WRITE;
-
- len = absolutepath(NULL, path, 0);
- buf = malloc(len);
- if (!buf)
- return -errno;
- absolutepath(buf, path, len);
- ret = _sys_open(buf, strlen(buf), flags);
- free(buf);
-
- if (ret < 0)
- errno = -ret;
-
- return ret;
-}
diff --git a/src/user/lib/compat.c b/src/user/lib/compat.c
deleted file mode 100644
index 3ec47f9..0000000
--- a/src/user/lib/compat.c
+++ /dev/null
@@ -1,20 +0,0 @@
-#include <camellia/syscalls.h>
-#include <stdio.h>
-#include <camellia/compat.h>
-
-#define eprintf(fmt, ...) fprintf(stderr, "user/lib/compat: "fmt"\n" __VA_OPT__(,) __VA_ARGS__)
-
-static hid_t h = -1;
-long c0_fs_wait(char *buf, long len, struct ufs_request *res) {
- if (h != -1) {
- eprintf("didn't respond to request!");
- c0_fs_respond(NULL, -1, 0);
- }
- h = _sys_fs_wait(buf, len, res);
- return h >= 0 ? 0 : -1;
-}
-long c0_fs_respond(void *buf, long ret, int flags) {
- ret = _sys_fs_respond(h, buf, ret, flags);
- h = -1;
- return ret;
-}
diff --git a/src/user/lib/ctype.c b/src/user/lib/ctype.c
deleted file mode 100644
index fa49a07..0000000
--- a/src/user/lib/ctype.c
+++ /dev/null
@@ -1,65 +0,0 @@
-#include <ctype.h>
-
-int isalnum(int c) {
- return isalpha(c) || isdigit(c);
-}
-
-int isalpha(int c) {
- return islower(c) || isupper(c);
-}
-
-int iscntrl(int c) {
- return c <= 0x1f || c == 0x7f;
-}
-
-int isdigit(int c) {
- return '0' <= c && c <= '9';
-}
-
-int isgraph(int c) {
- return isalpha(c) || isdigit(c) || ispunct(c);
-}
-
-int islower(int c) {
- return 'a' <= c && c <= 'z';
-}
-
-int isprint(int c) {
- return isgraph(c) || c == ' ';
-}
-
-int ispunct(int c) {
- return ('!' <= c && c <= '/')
- || (':' <= c && c <= '@')
- || ('[' <= c && c <= '`')
- || ('{' <= c && c <= '~');
-}
-
-int isspace(int c) {
- return c == ' '
- || c == '\f'
- || c == '\n'
- || c == '\r'
- || c == '\t'
- || c == '\v';
-}
-
-int isupper(int c) {
- return 'A' <= c && c <= 'Z';
-}
-
-int isxdigit(int c) {
- return ('0' <= c && c <= '9')
- || ('A' <= c && c <= 'F')
- || ('a' <= c && c <= 'f');
-}
-
-int tolower(int c) {
- if (isupper(c)) return c - 'A' + 'a';
- return c;
-}
-
-int toupper(int c) {
- if (islower(c)) return c - 'a' + 'A';
- return c;
-}
diff --git a/src/user/lib/dirent.c b/src/user/lib/dirent.c
deleted file mode 100644
index c2d1b9c..0000000
--- a/src/user/lib/dirent.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <dirent.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-DIR *opendir(const char *name) {
- FILE *fp = NULL;
- DIR *dir = NULL;
- fp = fopen(name, "r");
- if (!fp) {
- goto err;
- }
- dir = calloc(1, sizeof *dir);
- if (!dir) {
- goto err;
- }
- dir->fp = fp;
- return dir;
-err:
- if (fp) fclose(fp);
- free(dir);
- return NULL;
-}
-
-int closedir(DIR *dir) {
- fclose(dir->fp);
- free(dir);
- return 0;
-}
-
-struct dirent *readdir(DIR *dir) {
- int i = 0;
- char *buf = dir->dent.d_name;
- for (;;) {
- int c = fgetc(dir->fp);
- if (c == EOF) {
- if (i == 0) return NULL;
- else break;
- }
- if (c == '\0') {
- break;
- }
- if (i == sizeof(dir->dent.d_name)-1) {
- /* overflow */
- for (;;) {
- c = fgetc(dir->fp);
- if (c == EOF || c == '\0') break;
- }
- return errno = ENAMETOOLONG, NULL;
- }
- buf[i++] = c;
- }
- buf[i] = '\0';
- return &dir->dent;
-}
diff --git a/src/user/lib/draw/draw.c b/src/user/lib/draw/draw.c
deleted file mode 100644
index 1c2a371..0000000
--- a/src/user/lib/draw/draw.c
+++ /dev/null
@@ -1,83 +0,0 @@
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <draw.h>
-
-void dirty_reset(struct rect *d) {
- d->x1 = ~0; d->y1 = ~0;
- d->x2 = 0; d->y2 = 0;
-}
-
-void dirty_mark(struct rect *d, uint32_t x, uint32_t y) {
- if (d->x1 > x) d->x1 = x;
- if (d->x2 < x) d->x2 = x;
- if (d->y1 > y) d->y1 = y;
- if (d->y2 < y) d->y2 = y;
-}
-
-int fb_setup(struct framebuf *fb, const char *base) {
- char path[64], *spec;
- size_t pos;
- FILE *f;
-
- f = fopen(base, "r");
- if (!f) return -errno;
-
- pos = strlen(base);
- memcpy(path, base, pos);
- spec = path + pos;
- fread(spec, 1, sizeof(path) - pos, f);
- /* assumes the read went correctly */
- fclose(f);
-
- fb->fd = camellia_open(path, OPEN_RW);
- if (fb->fd < 0) return fb->fd;
-
- fb->width = strtol(spec, &spec, 0);
- if (*spec++ != 'x') return -EINVAL;
- fb->height = strtol(spec, &spec, 0);
- if (*spec++ != 'x') return -EINVAL;
- fb->bpp = strtol(spec, &spec, 0);
- if (fb->bpp != 32) return -EINVAL;
-
- fb->len = _sys_getsize(fb->fd);
- fb->pitch = fb->len / fb->height;
- fb->b = malloc(fb->len);
-
- _sys_read(fb->fd, fb->b, fb->len, 0);
-
- return 0;
-}
-
-int fb_anon(struct framebuf *fb, size_t w, size_t h) {
- fb->width = w;
- fb->height = h;
- fb->bpp = 32;
- fb->pitch = fb->width * fb->bpp / 8;
- fb->len = fb->pitch * fb->height;
- fb->b = malloc(fb->len);
- fb->fd = -1;
- return 0;
-}
-
-uint32_t *fb_pixel(struct framebuf *fb, uint32_t x, uint32_t y) {
- if (x < fb->width && y < fb->height)
- return (void*)fb->b + fb->pitch * y + 4 * x;
- return NULL;
-}
-
-void fb_cpy(
- struct framebuf *dest, const struct framebuf *src,
- size_t xd, size_t yd, size_t xs, size_t ys, size_t w, size_t h)
-{
- for (size_t y = 0; y < h; y++) {
- memcpy(
- fb_pixel( dest, xd, yd + y),
- fb_pixel((void*)src, xs, ys + y),
- w * 4
- );
- }
-}
diff --git a/src/user/lib/draw/flush.c b/src/user/lib/draw/flush.c
deleted file mode 100644
index 88bf3d6..0000000
--- a/src/user/lib/draw/flush.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <camellia/execbuf.h>
-#include <camellia/syscalls.h>
-#include <draw.h>
-
-static void flush_combined(struct rect pix, struct framebuf *fb) {
- size_t low = fb->pitch * pix.y1 + 4 * pix.x1;
- size_t high = fb->pitch * pix.y2 + 4 * pix.y2 + 4;
- _sys_write(fb->fd, fb->b + low, high - low, low, 0);
-}
-
-static void flush_split(struct rect pix, struct framebuf *fb) {
- static uint64_t execbuf[EXECBUF_MAX_LEN / sizeof(uint64_t)];
- size_t epos = 0;
- if (7 * (pix.y2 - pix.y1) * sizeof(uint64_t) >= sizeof execbuf) {
- flush_combined(pix, fb);
- return;
- }
-
- for (uint32_t y = pix.y1; y < pix.y2; y++) {
- size_t low = fb->pitch * y + 4 * pix.x1;
- size_t high = fb->pitch * y + 4 * pix.x2 + 4;
-
- execbuf[epos++] = EXECBUF_SYSCALL;
- execbuf[epos++] = _SYS_WRITE;
- execbuf[epos++] = fb->fd;
- execbuf[epos++] = (uintptr_t)fb->b + low;
- execbuf[epos++] = high - low;
- execbuf[epos++] = low;
- execbuf[epos++] = 0;
- }
- _sys_execbuf(execbuf, epos * sizeof(uint64_t));
-}
-
-void dirty_flush(struct rect *d, struct framebuf *fb) {
- if (~d->x1 == 0) return;
- if (d->x2 >= fb->width) d->x2 = fb->width - 1;
- if (d->y2 >= fb->height) d->y2 = fb->height - 1;
-
- /* the threshold is mostly arbitrary, wasn't based on any real benchmarks */
- if (d->x2 - d->x1 > fb->width - 600) flush_combined(*d, fb);
- else flush_split(*d, fb);
- dirty_reset(d);
-}
diff --git a/src/user/lib/elf.h b/src/user/lib/elf.h
deleted file mode 100644
index 8dc6242..0000000
--- a/src/user/lib/elf.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/* shamelessly stolen from https://github.com/adachristine/sophia/tree/main/api/elf */
-#pragma once
-#include <stdint.h>
-
-typedef uint8_t Elf_Byte;
-
-#define EI_MAG0 0
-#define EI_MAG1 1
-#define EI_MAG2 2
-#define EI_MAG3 3
-#define EI_CLASS 4
-#define EI_DATA 5
-#define EI_VERSION 6
-#define EI_OSABI 7
-#define EI_ABIVERSION 8
-#define EI_PAD 9
-#define EI_NIDENT 16
-
-#define ELFMAG0 0x7f
-#define ELFMAG1 'E'
-#define ELFMAG2 'L'
-#define ELFMAG3 'F'
-
-#define ELFCLASSNONE 0
-#define ELFCLASS32 1
-#define ELFCLASS64 2
-
-#define ELFDATANONE 0
-#define ELFDATA2LSB 1
-#define ELFDATA2MSB 2
-
-#define EI_VERSION 6
-#define EV_NONE 0
-#define EV_CURRENT 1
-
-#define ELFOSABI_NONE 0
-#define ELFOSABI_SYSV EI_OSABI_NONE
-
-#define ET_NONE 0
-#define ET_REL 1
-#define ET_EXEC 2
-#define ET_DYN 3
-#define ET_CORE 4
-#define ET_LOOS 0xfe00
-#define ET_HIOS 0xfeff
-
-#define EM_NONE 0
-
-#define PT_NULL 0
-#define PT_LOAD 1
-#define PT_DYNAMIC 2
-
-#define PF_X 0x01
-#define PF_W 0x02
-#define PF_R 0x04
-
-#define SHT_NULL 0
-#define SHT_PROGITS 1
-#define SHT_SYMTAB 2
-#define SHT_STRTAB 3
-#define SHT_RELA 4
-#define SHT_HASH 5
-#define SHT_DYNAMIC 6
-
-#define SHF_WRITE 0x1
-#define SHF_ALLOC 0x2
-#define SHF_EXEC 0x4
-#define SHF_MERGE 0x10
-#define SHF_STRINGS 0x20
-
-#define DT_NULL 0
-#define DT_NEEDED 1
-#define DT_PLTRELSZ 2
-#define DT_PLTGOT 3
-#define DT_HASH 4
-#define DT_STRTAB 5
-#define DT_SYMTAB 6
-#define DT_RELA 7
-#define DT_RELASZ 8
-#define DT_RELAENT 9
-#define DT_STRSZ 10
-#define DT_SYMENT 11
-#define DT_JMPREL 0x17
-
-typedef uint64_t Elf64_Addr;
-typedef uint64_t Elf64_Off;
-typedef uint16_t Elf64_Section;
-typedef uint16_t Elf64_Versym;
-typedef uint16_t Elf64_Half;
-typedef int32_t Elf64_Sword;
-typedef uint32_t Elf64_Word;
-typedef int64_t Elf64_Sxword;
-typedef uint64_t Elf64_Xword;
-
-typedef struct Elf64_Ehdr Elf64_Ehdr;
-typedef struct Elf64_Phdr Elf64_Phdr;
-typedef struct Elf64_Shdr Elf64_Shdr;
-typedef struct Elf64_Sym Elf64_Sym;
-typedef struct Elf64_Dyn Elf64_Dyn;
-
-typedef struct Elf64_Rel Elf64_Rel;
-typedef struct Elf64_Rela Elf64_Rela;
-
-#define EM_X86_64 62
-
-struct Elf64_Ehdr
-{
- Elf_Byte e_ident[EI_NIDENT];
- Elf64_Half e_type;
- Elf64_Half e_machine;
- Elf64_Word e_version;
- Elf64_Addr e_entry;
- Elf64_Off e_phoff;
- Elf64_Off e_shoff;
- Elf64_Word e_flags;
- Elf64_Half e_ehsize;
- Elf64_Half e_phentsize;
- Elf64_Half e_phnum;
- Elf64_Half e_shentsize;
- Elf64_Half e_shnum;
- Elf64_Half e_shstrndx;
-};
-
-struct Elf64_Phdr
-{
- Elf64_Word p_type;
- Elf64_Word p_flags;
- Elf64_Off p_offset;
- Elf64_Addr p_vaddr;
- Elf64_Addr p_paddr;
- Elf64_Xword p_filesz;
- Elf64_Xword p_memsz;
- Elf64_Xword p_align;
-};
-
-struct Elf64_Shdr
-{
- Elf64_Word sh_name;
- Elf64_Word sh_type;
- Elf64_Xword sh_flags;
- Elf64_Addr sh_addr;
- Elf64_Off sh_offset;
- Elf64_Xword sh_size;
- Elf64_Word sh_link;
- Elf64_Word sh_info;
- Elf64_Off sh_addralign;
- Elf64_Xword sh_entsize;
-};
-
-struct Elf64_Sym
-{
- Elf64_Word st_name;
- Elf_Byte st_info;
- Elf_Byte st_other;
- Elf64_Half st_shndx;
- Elf64_Addr st_value;
- Elf64_Xword st_size;
-};
-
-struct Elf64_Dyn
-{
- Elf64_Xword d_tag;
- union
- {
- Elf64_Xword d_val;
- Elf64_Addr d_ptr;
- };
-};
-
-#define ELF64_R_SYM(info) ((info)>>32)
-#define ELF64_R_TYPE(info) ((Elf64_Word)(info))
-#define ELF64_R_INFO(sym, type) (((Elf64_Xword)(sym)<<32)+(Elf64_Xword)(type))
-
-#define R_X86_64_JUMP_SLOT 7
-#define R_X86_64_RELATIVE 8
-
-struct Elf64_Rel
-{
- Elf64_Addr r_offset;
- Elf64_Xword r_info;
-};
-
-struct Elf64_Rela
-{
- Elf64_Addr r_offset;
- Elf64_Xword r_info;
- Elf64_Sxword r_addend;
-};
diff --git a/src/user/lib/elfload.S b/src/user/lib/elfload.S
deleted file mode 100644
index 78d5b3c..0000000
--- a/src/user/lib/elfload.S
+++ /dev/null
@@ -1,20 +0,0 @@
-#define ASM_FILE 1
-#include <camellia/syscalls.h>
-
-.section .text
-.global _freejmp_chstack
-.type _freejmp_chstack, @function
-// void _freejmp_chstack(void *entry, void *low, size_t len, char **argv, char **envp, void *stack);
-_freejmp_chstack:
- mov %r9, %rsp
- jmp _freejmp
-
-.section .text
-.global execbuf_chstack
-.type execbuf_chstack, @function
-// _Noreturn void execbuf_chstack(void *stack, void __user *buf, size_t len);
-execbuf_chstack:
- mov %rdi, %rsp
- mov $_SYS_EXECBUF, %rdi
- syscall
- hlt // if execbuf failed we might as well crash
diff --git a/src/user/lib/elfload.c b/src/user/lib/elfload.c
deleted file mode 100644
index c1a08f8..0000000
--- a/src/user/lib/elfload.c
+++ /dev/null
@@ -1,182 +0,0 @@
-#include <camellia/execbuf.h>
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "elf.h"
-#include <elfload.h>
-
-void elf_execf(FILE *f, char **argv, char **envp) {
- size_t ret;
- void *buf;
- long buflen;
-
- fseek(f, 0, SEEK_END);
- buflen = ftell(f);
- if (buflen < 0) return; /* errno set by fseek */
- buf = malloc(buflen);
-
- // TODO don't read the entire file into memory
- fseek(f, 0, SEEK_SET);
- if (!buf) return;
- ret = fread(buf, buflen, 1, f);
- fclose(f);
- if (ret == 1) {
- elf_exec(buf, argv, envp);
- }
- free(buf);
-}
-
-static bool valid_ehdr(const struct Elf64_Ehdr *h) {
- return h->e_ident[0] == 0x7f
- && h->e_ident[1] == 'E'
- && h->e_ident[2] == 'L'
- && h->e_ident[3] == 'F'
- && h->e_machine == EM_X86_64
- && h->e_version == 1;
-}
-
-static bool load_phdr(const void *elf, void *exebase, size_t idx) {
- const struct Elf64_Ehdr *ehdr = elf;
- const struct Elf64_Phdr *phdr = elf + ehdr->e_phoff + idx * ehdr->e_phentsize;
-
- if (phdr->p_type == PT_DYNAMIC) return true;
-
- if (phdr->p_type != PT_LOAD) {
- printf("unknown type %x\n", phdr->p_type);
- return false;
- }
- // TODO overlap check
- // TODO don't ignore flags
- _sys_memflag(exebase + phdr->p_vaddr, phdr->p_memsz, MEMFLAG_PRESENT);
- // TODO check that filesz <= memsz
- memcpy(exebase + phdr->p_vaddr, elf + phdr->p_offset, phdr->p_filesz);
- return true;
-}
-
-static size_t elf_spread(const void *elf) {
- const struct Elf64_Ehdr *ehdr = elf;
- uintptr_t high = 0, low = ~0;
- for (size_t phi = 0; phi < ehdr->e_phnum; phi++) {
- const struct Elf64_Phdr *phdr = elf + ehdr->e_phoff + phi * ehdr->e_phentsize;
- if (high < phdr->p_vaddr + phdr->p_memsz)
- high = phdr->p_vaddr + phdr->p_memsz;
- if (low > phdr->p_vaddr)
- low = phdr->p_vaddr;
- }
- return high - low;
-}
-
-static void *memdup(const void *orig, size_t len) {
- void *n = malloc(len);
- if (n) memcpy(n, orig, len);
- return n;
-}
-
-static const char *default_argv[] = {NULL};
-
-/* frees memory outside of [low; low + len] and jumps to *entry
- * also sets up main's stack */
-void _freejmp_chstack(void *entry, void *low, size_t len, const char **argv, char **envp, void *stack); // elfload.s
-_Noreturn void execbuf_chstack(void *stack, void __user *buf, size_t len);
-void _freejmp(void *entry, void *low, size_t imglen, const char **argv, char **envp) {
- // TODO error checking
- // although i guess it's fine for it to crash
- // also TODO just alloc a new stack
- void *stack = (void*)~0;
- struct execdata ed;
- size_t argv_len;
- size_t cwd_len = absolutepath(NULL, NULL, 0);
-
- if (!argv) argv = default_argv;
-
- ed.argc = 0;
- while (argv[ed.argc]) ed.argc++;
- argv_len = (ed.argc+1) * sizeof(char *);
-
- /* make a copy of argv, so it doesn't get overridden
- * if it overlaps with the new stack. */
- argv = memdup(argv, argv_len);
- for (int i = 0; i < ed.argc; i++) {
- argv[i] = strdup(argv[i]);
- }
- ed.cwd = malloc(cwd_len);
- getcwd(ed.cwd, cwd_len);
-
- stack -= argv_len;
- ed.argv = stack;
-
- for (int i = 0; i < ed.argc; i++) {
- size_t len = strlen(argv[i]) + 1;
- stack -= len;
- memcpy(stack, argv[i], len);
- ed.argv[i] = stack;
- }
- ed.argv[ed.argc] = NULL;
-
- /* push cwd */
- stack -= cwd_len;
- memcpy(stack, ed.cwd, cwd_len);
- ed.cwd = stack;
-
- stack -= sizeof ed;
- memcpy(stack, &ed, sizeof ed);
-
- uintptr_t high = (uintptr_t)low + imglen;
- uint64_t buf[] = {
- EXECBUF_SYSCALL, _SYS_MEMFLAG, 0, (uintptr_t)low, 0, 0, 0,
- EXECBUF_SYSCALL, _SYS_MEMFLAG, high, ~0 - 0xF000 - high, 0, 0, 0,
- EXECBUF_JMP, (uintptr_t)entry,
- };
- execbuf_chstack(stack, buf, sizeof buf);
-}
-
-static void *elf_loadmem(struct Elf64_Ehdr *ehdr) {
- void *exebase;
- size_t spread = elf_spread(ehdr);
- switch (ehdr->e_type) {
- case ET_EXEC:
- exebase = (void*)0;
- break;
- case ET_DYN:
- exebase = _sys_memflag((void*)0x1000, spread, MEMFLAG_FINDFREE);
- if (!exebase)
- return NULL;
- break;
- default:
- return NULL;
- }
- for (size_t phi = 0; phi < ehdr->e_phnum; phi++) {
- if (!load_phdr((void*)ehdr, exebase, phi)) {
- _sys_memflag(exebase, spread, 0);
- return NULL;
- }
- }
- return exebase;
-}
-
-void elf_exec(void *base, char **argv, char **envp) {
- struct Elf64_Ehdr *ehdr = base;
- if (!valid_ehdr(ehdr)) return;
-
- void *exebase = elf_loadmem(ehdr);
- if (!exebase) return;
-
- void *newstack = _sys_memflag((void*)0x11000, 0x1000, MEMFLAG_FINDFREE | MEMFLAG_PRESENT) + 0x1000 - 8;
- if (!newstack) return;
-
- _freejmp_chstack(exebase + ehdr->e_entry, exebase, elf_spread(ehdr) + 0x1000, (const char**)argv, envp, newstack);
-}
-
-void *elf_partialexec(void *base) {
- struct Elf64_Ehdr *ehdr = base;
- if (!valid_ehdr(ehdr)) return NULL;
-
- void *exebase = elf_loadmem(ehdr);
- if (!exebase) return NULL;
-
- return exebase + ehdr->e_entry;
-}
diff --git a/src/user/lib/elfreloc.c b/src/user/lib/elfreloc.c
deleted file mode 100644
index aab2a2a..0000000
--- a/src/user/lib/elfreloc.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <stdio.h>
-#include "elf.h"
-
-__attribute__((visibility("hidden")))
-extern struct Elf64_Dyn _DYNAMIC[];
-
-__attribute__((visibility("hidden")))
-extern char __executable_start[];
-
-static struct Elf64_Dyn *dyn_gettag(Elf64_Xword tag) {
- for (size_t i = 0;; i++) {
- if (_DYNAMIC[i].d_tag == tag) return &_DYNAMIC[i];
- if (_DYNAMIC[i].d_tag == DT_NULL) return NULL;
- }
-}
-
-void elf_selfreloc(void) {
- // TODO DT_REL, DT_JMPREL
-
- struct Elf64_Dyn *rela_tag = dyn_gettag(DT_RELA);
- if (rela_tag) {
- /* not checking pointer validity,
- * crashing on an invalid elf is fine */
- size_t relasz = dyn_gettag(DT_RELASZ)->d_val;
- size_t relaent = dyn_gettag(DT_RELAENT)->d_val;
- for (size_t o = 0; o < relasz; o += relaent) {
- struct Elf64_Rela *r = (void*)__executable_start + rela_tag->d_ptr + o;
- uintptr_t *target = (void*)__executable_start + r->r_offset;
-
- switch (ELF64_R_TYPE(r->r_info)) {
- case R_X86_64_RELATIVE:
- *target = (uintptr_t)&__executable_start + r->r_addend;
- break;
- default:
- _klogf("elf: unsupported relocation type\n");
- }
- }
- }
-}
diff --git a/src/user/lib/err.c b/src/user/lib/err.c
deleted file mode 100644
index 7a220fe..0000000
--- a/src/user/lib/err.c
+++ /dev/null
@@ -1,50 +0,0 @@
-#include <err.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-_Noreturn void err(int ret, const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- vwarn(fmt, args);
- va_end(args);
- exit(ret);
-}
-
-_Noreturn void errx(int ret, const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- vwarnx(fmt, args);
- va_end(args);
- exit(ret);
-}
-
-void warn(const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- vwarn(fmt, args);
- va_end(args);
-}
-
-void warnx(const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- vwarnx(fmt, args);
- va_end(args);
-}
-
-void vwarn(const char *fmt, va_list args) {
- fprintf(stderr, "%s: ", getprogname());
- if (fmt) {
- vfprintf(stderr, fmt, args);
- fprintf(stderr, ": ");
- }
- fprintf(stderr, "%s\n", strerror(errno));
-}
-
-void vwarnx(const char *fmt, va_list args) {
- fprintf(stderr, "%s: ", getprogname());
- if (fmt) vfprintf(stderr, fmt, args);
- fprintf(stderr, "\n");
-}
diff --git a/src/user/lib/esemaphore.c b/src/user/lib/esemaphore.c
deleted file mode 100644
index 2707d11..0000000
--- a/src/user/lib/esemaphore.c
+++ /dev/null
@@ -1,56 +0,0 @@
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <esemaphore.h>
-
-void esem_signal(struct evil_sem *sem) {
- _sys_write(sem->signal, NULL, 0, 0, 0);
-}
-
-void esem_wait(struct evil_sem *sem) {
- _sys_read(sem->wait, NULL, 0, 0);
-}
-
-struct evil_sem *esem_new(int value) {
- hid_t ends_wait[2], ends_signal[2];
- struct evil_sem *sem;
-
- if (value < 0) return NULL;
- if (_sys_pipe(ends_wait, 0) < 0) return NULL;
- if (_sys_pipe(ends_signal, 0) < 0) goto fail_signal;
- if (!(sem = malloc(sizeof *sem))) goto fail_malloc;
-
- if (!_sys_fork(FORK_NOREAP, NULL)) {
- close(ends_signal[1]);
- while (_sys_read(ends_signal[0], NULL, 0, 0) >= 0) {
- if (!_sys_fork(FORK_NOREAP, NULL)) {
- _sys_write(ends_wait[1], NULL, 0, 0, 0);
- exit(0);
- }
- }
- exit(0);
- }
- close(ends_signal[0]);
- close(ends_wait[1]);
-
- sem->wait = ends_wait[0];
- sem->signal = ends_signal[1];
-
- while (value--) esem_signal(sem);
- return sem;
-
-fail_malloc:
- close(ends_signal[0]);
- close(ends_signal[1]);
-fail_signal:
- close(ends_wait[0]);
- close(ends_wait[1]);
- return NULL;
-}
-
-void esem_free(struct evil_sem *sem) {
- close(sem->wait);
- close(sem->signal);
- free(sem);
-}
diff --git a/src/user/lib/fcntl.c b/src/user/lib/fcntl.c
deleted file mode 100644
index b2d8685..0000000
--- a/src/user/lib/fcntl.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <bits/panic.h>
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdarg.h>
-
-#include <stdio.h>
-
-int open(const char *path, int flags, ...) {
- (void)path; (void)flags;
- _klogf("failing open(\"%s\")", path);
- return errno = ENOSYS, -1;
-}
-
-int fcntl(int fd, int cmd, ...) {
- va_list argp;
- va_start(argp, cmd);
- if (cmd == F_DUPFD) {
- int to = va_arg(argp, int);
- va_end(argp);
- return _sys_dup(fd, to, DUP_SEARCH);
- } else {
- va_end(argp);
- _klogf("failing fcntl(%d)", cmd);
- return errno = ENOSYS, -1;
- }
-}
diff --git a/src/user/lib/fs/dir.c b/src/user/lib/fs/dir.c
deleted file mode 100644
index b7f840d..0000000
--- a/src/user/lib/fs/dir.c
+++ /dev/null
@@ -1,84 +0,0 @@
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <limits.h>
-#include <string.h>
-#include <camellia/fs/dir.h>
-
-void dir_start(struct dirbuild *db, long offset, char *buf, size_t buflen) {
- db->offset = offset;
- db->buf = buf;
- db->bpos = 0;
- db->blen = buflen;
- db->error = 0;
-
- // TODO decide how negative directory offsets should be handled
- if (offset < 0) db->error = -ENOSYS;
-}
-
-bool dir_append(struct dirbuild *db, const char *name) {
- return dir_appendl(db, name, strlen(name));
-}
-
-bool dir_appendl(struct dirbuild *db, const char *name, size_t len) {
- if (db->error) return true;
- if (len > (size_t)LONG_MAX) {
- db->error = -1;
- return true;
- }
-
- len++; // account for the null byte
-
- if (db->offset < (long)len) {
- name += db->offset;
- len -= db->offset;
- db->offset = 0;
-
- if (db->buf) {
- // TODO no buffer overrun check
- memcpy(db->buf + db->bpos, name, len - 1);
- db->buf[db->bpos + len - 1] = '\0';
- }
- db->bpos += len;
- } else {
- db->offset -= len;
- }
- return false;
-}
-
-bool dir_append_from(struct dirbuild *db, hid_t h) {
- if (db->error) return true;
- if (db->buf && db->bpos == db->blen) return false;
-
- int ret;
- if (db->buf) {
- ret = _sys_read(h, db->buf + db->bpos, db->blen - db->bpos, db->offset);
- if (ret < 0) {
- db->error = ret;
- return true;
- } else if (ret > 0) {
- /* not eof */
- db->offset = 0;
- db->bpos += ret;
- return false;
- } /* else ret == 0, EOF, need getsize */
- }
-
- ret = _sys_getsize(h);
- if (ret < 0) {
- db->error = ret;
- return true;
- }
- if (db->offset < ret) {
- /* should only occur when !buf, otherwise leaks previous data from buf.
- * TODO consider impact */
- db->bpos += ret - db->offset;
- db->offset = 0;
- } else {
- db->offset -= ret;
- }
- return false;
-}
-
-long dir_finish(struct dirbuild *db) {
- return db->error ? db->error : db->bpos;
-}
diff --git a/src/user/lib/fs/dirinject.c b/src/user/lib/fs/dirinject.c
deleted file mode 100644
index 9b08756..0000000
--- a/src/user/lib/fs/dirinject.c
+++ /dev/null
@@ -1,129 +0,0 @@
-#include <assert.h>
-#include <camellia/fs/dir.h>
-#include <camellia/fs/misc.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/param.h>
-#include <unistd.h>
-
-typedef struct Handle {
- int delegate;
- int plen;
- char path[];
-} Handle;
-
-static int
-dir_seglen(const char *path)
-{
- /* if path contains /, return its position + 1
- * otherwise, return strlen */
- int len = 0;
- while (path[len]) {
- if (path[len] == '/') {
- len++;
- break;
- }
- len++;
- }
- return len;
-}
-
-static int
-find_injects(const char *injects[], const char *path, int plen, struct dirbuild *db)
-{
- // TODO deduplicate
- const char *inj;
- int matches = 0;
- assert(plen >= 1);
- assert(path[plen-1] == '/');
-
- while ((inj = *injects++)) {
- int ilen = strlen(inj);
- if (plen < ilen && memcmp(path, inj, plen) == 0) {
- if (db) {
- /* inj[plen-1] == '/' */
- const char *ent = inj + plen;
- dir_appendl(db, ent, dir_seglen(ent));
- }
- matches++;
- }
- }
- return matches;
-}
-
-void
-fs_dirinject2(const char *injects[])
-{
- const size_t buflen = 4096;
- char *buf = malloc(buflen);
- if (!buf) exit(1);
-
- for (;;) {
- struct ufs_request req;
- hid_t reqh = _sys_fs_wait(buf, buflen, &req);
- if (reqh < 0) break;
- Handle *hndl = req.id;
- switch (req.op) {
- case VFSOP_OPEN: {
- if (buf[req.len - 1] == '/') {
- if (find_injects(injects, buf, req.len, NULL) > 0) {
- /* opening a directory that we're injecting into */
- hndl = malloc(sizeof(Handle) + req.len);
- if (hndl == NULL) {
- _sys_fs_respond(reqh, NULL, -EGENERIC, 0);
- break;
- }
- /* ignore errors from _sys_open */
- hndl->delegate = _sys_open(buf, req.len, req.flags);
- hndl->plen = req.len;
- memcpy(hndl->path, buf, hndl->plen);
- _sys_fs_respond(reqh, hndl, 0, 0);
- break;
- }
- }
- /* default behaviour */
- forward_open(reqh, buf, req.len, req.flags);
- break;
- }
-
- case VFSOP_CLOSE: {
- if (hndl->delegate >= 0) {
- close(hndl->delegate);
- }
- free(hndl);
- _sys_fs_respond(reqh, NULL, 0, 0);
- break;
- }
-
- case VFSOP_READ:
- case VFSOP_GETSIZE: {
- struct dirbuild db;
- char *target = NULL;
- if (req.op == VFSOP_READ) {
- target = buf;
- }
- req.capacity = MIN(req.capacity, buflen);
-
- dir_start(&db, req.offset, target, req.capacity);
- find_injects(injects, hndl->path, hndl->plen, &db);
- if (hndl->delegate >= 0) {
- dir_append_from(&db, hndl->delegate);
- }
- _sys_fs_respond(reqh, target, dir_finish(&db), 0);
- break;
- }
-
- default: {
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
- }
- }
- exit(0);
-}
-
-void
-fs_dirinject(const char *path) {
- fs_dirinject2((const char*[]){ path, NULL });
-}
diff --git a/src/user/lib/fs/misc.c b/src/user/lib/fs/misc.c
deleted file mode 100644
index 30e5ab4..0000000
--- a/src/user/lib/fs/misc.c
+++ /dev/null
@@ -1,160 +0,0 @@
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <camellia/compat.h>
-#include <camellia/fs/dir.h>
-#include <camellia/fs/misc.h>
-
-void forward_open(hid_t reqh, const char *path, long len, int flags) {
- // TODO use threads
- // TODO solve for more complex cases, e.g. fs_union
- /* done in a separate thread/process because open() can block,
- * but that should only hold the caller back, and not the fs driver.
- *
- * for example, running `httpd` in one term would prevent you from doing
- * basically anything on the second term, because fs_dirinject would be
- * stuck on open()ing the socket */
- if (!_sys_fork(FORK_NOREAP, NULL)) {
- _sys_fs_respond(reqh, NULL, _sys_open(path, len, flags), FSR_DELEGATE);
- exit(0);
- }
- close(reqh);
-}
-
-void fs_passthru(const char *prefix) {
- const size_t buflen = 1024;
- char *buf = malloc(buflen);
- int prefix_len = prefix ? strlen(prefix) : 0;
- if (!buf) exit(1);
-
- for (;;) {
- struct ufs_request res;
- hid_t reqh = _sys_fs_wait(buf, buflen, &res);
- if (reqh < 0) break;
- switch (res.op) {
- case VFSOP_OPEN:
- if (prefix) {
- if (prefix_len + res.len > buflen) {
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
-
- memmove(buf + prefix_len, buf, res.len);
- memcpy(buf, prefix, prefix_len);
- res.len += prefix_len;
- }
- forward_open(reqh, buf, res.len, res.flags);
- break;
-
- default:
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
- }
- exit(0);
-}
-
-void fs_union(const char **list) {
- struct ufs_request res;
-
- /* the buffer is split into two halves:
- * the second one is filled out with the path by fs_wait
- * the first one is used for the prepended paths */
- const size_t buflen = 1024;
- const size_t prelen = 512;
- const size_t postlen = buflen - prelen;
- char *pre = malloc(buflen);
- char *post = pre + prelen;
- long ret;
- struct dirbuild db;
- if (!pre) exit(1);
-
- while (!c0_fs_wait(post, postlen, &res)) {
- switch (res.op) {
- case VFSOP_OPEN:
- if (res.len == 1) { /* root directory */
- c0_fs_respond(NULL, 0, 0);
- break;
- }
-
- ret = -1;
- for (size_t i = 0; ret < 0 && list[i]; i++) {
- const char *prefix = list[i];
- size_t prefixlen = strlen(prefix); // TODO cache
- if (prefixlen > prelen) continue;
- char *path = post - prefixlen;
- memcpy(path, prefix, prefixlen);
-
- ret = _sys_open(path, prefixlen + res.len, res.flags);
-
- post[res.len] = '\0';
- }
- if (ret < 0) ret = -1;
- c0_fs_respond(NULL, ret, FSR_DELEGATE);
- break;
-
- case VFSOP_READ:
- case VFSOP_GETSIZE:
- if (res.capacity > buflen)
- res.capacity = buflen;
- bool end = false;
- char *target = res.op == VFSOP_READ ? pre : NULL;
- dir_start(&db, res.offset, target, res.capacity);
- for (size_t i = 0; !end && list[i]; i++) {
- const char *prefix = list[i];
- size_t prefixlen = strlen(prefix);
- // TODO only open the directories once
- // TODO ensure trailing slash
- hid_t h = _sys_open(prefix, prefixlen, OPEN_READ);
- if (h < 0) continue;
- end = end || dir_append_from(&db, h);
- _sys_close(h);
- }
- c0_fs_respond(target, dir_finish(&db), 0);
- break;
-
- default:
- c0_fs_respond(NULL, -1, 0);
- break;
- }
- }
- exit(0);
-}
-
-hid_t ufs_wait(char *buf, size_t len, struct ufs_request *req) {
- hid_t reqh;
- for (;;) {
- reqh = _sys_fs_wait(buf, len, req);
- if (reqh < 0) break;
- if (req->op == VFSOP_OPEN) {
- if (req->len == len) {
- _sys_fs_respond(reqh, NULL, -ENAMETOOLONG, 0);
- continue;
- }
- buf[req->len] = '\0';
- // TODO ensure passed paths don't have null bytes in them in the kernel
- }
- break;
- }
- return reqh;
-}
-
-int mount_at(const char *path) {
- hid_t h;
- int ret = _sys_fork(FORK_NEWFS, &h);
- if (ret == 0) {
- _klogf("%s: impl", path);
- setproctitle("%s", path);
- } else if (ret > 0) {
- _sys_mount(h, path, strlen(path));
- close(h);
- } else {
- _sys_mount(HANDLE_NULLFS, path, strlen(path));
- }
- return ret;
-}
diff --git a/src/user/lib/fs/whitelist.c b/src/user/lib/fs/whitelist.c
deleted file mode 100644
index 54a79c3..0000000
--- a/src/user/lib/fs/whitelist.c
+++ /dev/null
@@ -1,114 +0,0 @@
-#include <camellia/flags.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <camellia/fs/dir.h>
-#include <camellia/fs/misc.h>
-
-static int dir_seglen2(const char *path, size_t len) {
- /* returns the length of the first segment of the path, including the trailing / (if any). */
- for (size_t i = 0; i < len; i++) {
- if (path[i] == '/')
- return i + 1;
- }
- return len;
-}
-
-/** @return the length of the path w/o suffixes */
-static size_t suffix_parse(const char *path, size_t len, bool *ro_ptr) {
- bool ro = false;
- if (len >= 3 && !memcmp(path + len - 3, ":ro", 3)) {
- ro = true;
- len -= 3;
- }
- if (ro_ptr) *ro_ptr = ro;
- return len;
-}
-
-/** Check if a path is a prefix of another path. */
-// TODO move to libc; tests
-static bool prefix_match(const char *prefix, size_t plen, const char *full, size_t flen) {
- if (flen < plen) return false;
- if (flen == plen)
- return memcmp(full, prefix, flen) == 0;
- return plen >= 1
- && prefix[plen - 1] == '/' /* prefixes must point to one of the parent directories */
- && memcmp(full, prefix, plen) == 0;
-}
-
-void fs_whitelist(const char **whitelist) {
- const size_t buflen = 1024;
- char *buf = malloc(buflen);
- if (!buf) exit(1);
- for (;;) {
- struct ufs_request res;
- hid_t reqh = _sys_fs_wait(buf, buflen, &res);
- if (reqh < 0) break;
-
- char *ipath = res.id; /* the path of the open()ed directory */
-
- switch (res.op) {
- case VFSOP_OPEN: {
- bool error = false;
- bool passthru = false;
- bool inject = false;
-
- for (const char **entry = whitelist; *entry; entry++) {
- bool ro = false;
- size_t entry_len = suffix_parse(*entry, strlen(*entry), &ro);
- /* If *entry is a prefix of the opened path, pass the open() through. */
- if (prefix_match(*entry, entry_len, buf, res.len)) {
- passthru = true;
- if (ro && OPEN_WRITEABLE(res.flags))
- error = true;
- break;
- }
- /* If the path is a prefix of *entry, we might need to inject a directory. */
- if (prefix_match(buf, res.len, *entry, entry_len)) {
- inject = true;
- }
- }
- if (error) {
- _sys_fs_respond(reqh, NULL, -EACCES, 0);
- } else if (passthru) {
- forward_open(reqh, buf, res.len, res.flags);
- } else if (inject) {
- // TODO all the inject points could be precomputed
- ipath = malloc(res.len + 1);
- memcpy(ipath, buf, res.len);
- ipath[res.len] = '\0';
- _sys_fs_respond(reqh, ipath, 0, 0);
- } else {
- _sys_fs_respond(reqh, NULL, -1, 0);
- }
- break;
- }
- case VFSOP_READ:
- case VFSOP_GETSIZE: {
- struct dirbuild db;
- size_t ilen = strlen(ipath);
- char *target = res.op == VFSOP_READ ? buf : NULL;
- dir_start(&db, res.offset, target, buflen);
- for (const char **entry = whitelist; *entry; entry++) {
- // TODO could be precomputed too
- size_t elen = suffix_parse(*entry, strlen(*entry), NULL);
- if (ilen < elen && !memcmp(ipath, *entry, ilen))
- dir_appendl(&db, *entry + ilen, dir_seglen2(*entry + ilen, elen - ilen));
- }
- _sys_fs_respond(reqh, target, dir_finish(&db), 0);
- break;
- }
- case VFSOP_CLOSE: {
- free(ipath);
- _sys_fs_respond(reqh, NULL, 0, 0);
- break;
- }
- default: {
- _sys_fs_respond(reqh, NULL, -1, 0);
- break;
- }
- }
- }
- exit(0);
-}
diff --git a/src/user/lib/include/__errno.h b/src/user/lib/include/__errno.h
deleted file mode 100644
index 7551ce0..0000000
--- a/src/user/lib/include/__errno.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* generated by awk */
-#ifdef E
-E( 1, "EGENERIC unknown error")
-E( 2, "EFAULT")
-E( 3, "EBADF bad file descriptor")
-E( 4, "EINVAL")
-E( 5, "ENOSYS unsupported")
-E( 6, "ERANGE")
-E( 7, "ENOMEM")
-E( 8, "ENOENT")
-E( 9, "ENOTEMPTY")
-E( 10, "EACCES")
-E( 11, "EMFILE all file descriptors taken")
-E( 12, "ECONNRESET")
-E( 13, "EPIPE")
-E( 14, "ECHILD")
-E(200, "EISDIR")
-E(201, "ENAMETOOLONG")
-E(202, "ENOTDIR")
-E(203, "ELOOP")
-E(204, "ENOEXEC")
-E(205, "EINTR")
-E(206, "EWOULDBLOCK")
-E(207, "EEXIST")
-E(208, "EAGAIN")
-#endif
diff --git a/src/user/lib/include/__errno.h.awk b/src/user/lib/include/__errno.h.awk
deleted file mode 100644
index 6232835..0000000
--- a/src/user/lib/include/__errno.h.awk
+++ /dev/null
@@ -1,20 +0,0 @@
-BEGIN {
- print "/* generated by awk */";
- print "#ifdef E";
-}
-
-END {
- print "#endif";
-}
-
-/#define/ {
- comment = $2;
- num = $3;
- # extract the comment, if present
- if (index($0, "/*")) {
- sub(/[^/]*\/\*/, "");
- sub(/ *\*\//, "");
- comment = comment $0;
- }
- printf "E(%3s, \"%s\")\n", num, comment;
-}
diff --git a/src/user/lib/include/_proc.h b/src/user/lib/include/_proc.h
deleted file mode 100644
index 5f9c321..0000000
--- a/src/user/lib/include/_proc.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-
-struct _psdata {
- /* Description of the process, see setprogname.
- * Assumed to be null terminated. */
- char desc[1024];
-
- /* Base offset where the executable was loaded. */
- void *base;
-};
-
-/* First allocated in bootstrap.
- * Freed on every exec(), just to be immediately reallocated by _start2(). */
-static struct _psdata *const _psdata_loc = (void*)0x10000;
diff --git a/src/user/lib/include/alloca.h b/src/user/lib/include/alloca.h
deleted file mode 100644
index 9c7641c..0000000
--- a/src/user/lib/include/alloca.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-#include <stddef.h>
-void *alloca(size_t size);
diff --git a/src/user/lib/include/bits/file.h b/src/user/lib/include/bits/file.h
deleted file mode 100644
index 63a31c4..0000000
--- a/src/user/lib/include/bits/file.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#pragma once
-typedef struct _LIBC_FILE FILE;
diff --git a/src/user/lib/include/bits/panic.h b/src/user/lib/include/bits/panic.h
deleted file mode 100644
index 91aec5f..0000000
--- a/src/user/lib/include/bits/panic.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-#include <stdio.h>
-#include <stdlib.h>
-
-#define __libc_panic(...) do { fprintf(stderr, "__libc_panic @ %s:", __func__); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); abort(); } while (0)
diff --git a/src/user/lib/include/camellia.h b/src/user/lib/include/camellia.h
deleted file mode 100644
index 2e4998b..0000000
--- a/src/user/lib/include/camellia.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-#include <camellia/flags.h>
-#include <camellia/types.h>
-
-hid_t camellia_open(const char *path, int flags);
diff --git a/src/user/lib/include/camellia/compat.h b/src/user/lib/include/camellia/compat.h
deleted file mode 100644
index a7c6f1f..0000000
--- a/src/user/lib/include/camellia/compat.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-#include <camellia/types.h>
-
-/* c0 - fs_wait returning a handle */
-long c0_fs_wait(char *buf, long len, struct ufs_request *res);
-long c0_fs_respond(void *buf, long ret, int flags);
diff --git a/src/user/lib/include/camellia/fs/dir.h b/src/user/lib/include/camellia/fs/dir.h
deleted file mode 100644
index d34a652..0000000
--- a/src/user/lib/include/camellia/fs/dir.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#pragma once
-#include <camellia/types.h>
-#include <stdbool.h>
-#include <stddef.h>
-
-struct dirbuild {
- long offset;
- char *buf;
- long bpos, blen;
- long error;
-};
-
-void dir_start(struct dirbuild *db, long offset, char *buf, size_t buflen);
-bool dir_append(struct dirbuild *db, const char *name);
-bool dir_appendl(struct dirbuild *db, const char *name, size_t len);
-bool dir_append_from(struct dirbuild *db, hid_t h);
-long dir_finish(struct dirbuild *db);
diff --git a/src/user/lib/include/camellia/fs/misc.h b/src/user/lib/include/camellia/fs/misc.h
deleted file mode 100644
index 301c604..0000000
--- a/src/user/lib/include/camellia/fs/misc.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#pragma once
-#include <stdbool.h>
-#include <stdlib.h>
-
-void forward_open(hid_t reqh, const char *path, long len, int flags);
-
-void fs_passthru(const char *prefix);
-void fs_whitelist(const char **list);
-void fs_union(const char **list);
-
-void fs_dirinject(const char *path);
-void fs_dirinject2(const char *injects[]);
-
-int mount_at(const char *path);
-
-// TODO separate fs drivers and wrappers around syscalls
-
-/** like _sys_fs_wait, but ensures *buf is a null terminated string on VFSOP_OPEN */
-hid_t ufs_wait(char *buf, size_t len, struct ufs_request *req);
-
-/** Mounts something and injects its path into the fs */
-#define MOUNT_AT(path) for (; mount_at(path) == 0; exit(1))
diff --git a/src/user/lib/include/ctype.h b/src/user/lib/include/ctype.h
deleted file mode 100644
index 1ebb111..0000000
--- a/src/user/lib/include/ctype.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#pragma once
-
-int isalnum(int c);
-int isalpha(int c);
-int iscntrl(int c);
-int isdigit(int c);
-int isgraph(int c);
-int islower(int c);
-int isprint(int c);
-int ispunct(int c);
-int isspace(int c);
-int isupper(int c);
-int isxdigit(int c);
-
-int tolower(int c);
-int toupper(int c);
diff --git a/src/user/lib/include/dirent.h b/src/user/lib/include/dirent.h
deleted file mode 100644
index 7c419d7..0000000
--- a/src/user/lib/include/dirent.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#pragma once
-#include <stdio.h>
-
-struct dirent {
- ino_t d_ino;
- char d_name[256]; /* NAME_MAX + 1 */
-};
-
-typedef struct {
- FILE *fp;
- struct dirent dent;
-} DIR;
-
-DIR *opendir(const char *name);
-int closedir(DIR *dir);
-struct dirent *readdir(DIR *dir);
diff --git a/src/user/lib/include/draw.h b/src/user/lib/include/draw.h
deleted file mode 100644
index 5e614be..0000000
--- a/src/user/lib/include/draw.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#pragma once
-#include <camellia/types.h>
-#include <stddef.h>
-#include <stdint.h>
-
-struct framebuf {
- size_t len, width, height, pitch;
- uint8_t bpp;
- char *b;
-
- hid_t fd;
-};
-
-struct rect { uint32_t x1, y1, x2, y2; };
-void dirty_reset(struct rect *d);
-void dirty_mark(struct rect *d, uint32_t x, uint32_t y);
-void dirty_flush(struct rect *d, struct framebuf *fb);
-
-int fb_setup(struct framebuf *fb, const char *base);
-int fb_anon(struct framebuf *fb, size_t w, size_t h);
-uint32_t *fb_pixel(struct framebuf *fb, uint32_t x, uint32_t y);
-void fb_cpy(
- struct framebuf *dest, const struct framebuf *src,
- size_t xd, size_t yd, size_t xs, size_t ys, size_t w, size_t h);
diff --git a/src/user/lib/include/elfload.h b/src/user/lib/include/elfload.h
deleted file mode 100644
index 825f765..0000000
--- a/src/user/lib/include/elfload.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-#include <bits/file.h>
-
-struct execdata {
- int argc;
- char **argv, **envp;
- char *cwd;
-};
-
-void elf_execf(FILE *f, char **argv, char **envp);
-void elf_exec(void *base, char **argv, char **envp);
-void *elf_partialexec(void *elf); /* returns pointer to entry point */
-
-void elf_selfreloc(void); // elfreloc.c
diff --git a/src/user/lib/include/err.h b/src/user/lib/include/err.h
deleted file mode 100644
index 6b63c6c..0000000
--- a/src/user/lib/include/err.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-#include <stdarg.h>
-
-_Noreturn void err(int ret, const char *fmt, ...);
-_Noreturn void errx(int ret, const char *fmt, ...);
-void warn(const char *fmt, ...);
-void warnx(const char *fmt, ...);
-
-void vwarn(const char *fmt, va_list args);
-void vwarnx(const char *fmt, va_list args);
diff --git a/src/user/lib/include/errno.h b/src/user/lib/include/errno.h
deleted file mode 100644
index 6686a01..0000000
--- a/src/user/lib/include/errno.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-#include <camellia/errno.h>
-extern int errno;
diff --git a/src/user/lib/include/esemaphore.h b/src/user/lib/include/esemaphore.h
deleted file mode 100644
index 9cc85e0..0000000
--- a/src/user/lib/include/esemaphore.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#pragma once
-#include <camellia/types.h>
-
-struct evil_sem {
- hid_t wait, signal;
-};
-
-void esem_signal(struct evil_sem *sem);
-void esem_wait(struct evil_sem *sem);
-
-struct evil_sem *esem_new(int value);
-void esem_free(struct evil_sem *sem);
diff --git a/src/user/lib/include/fcntl.h b/src/user/lib/include/fcntl.h
deleted file mode 100644
index 6338d1f..0000000
--- a/src/user/lib/include/fcntl.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma once
-
-#define F_SETFL 1
-#define F_GETFL 2
-#define F_DUPFD 3
-#define F_SETFD 4
-
-#define FD_CLOEXEC 1
-
-#define O_APPEND 0
-#define O_CREAT 0
-#define O_EXCL 0
-#define O_NONBLOCK 0
-#define O_RDONLY 0
-#define O_RDWR 0
-#define O_TRUNC 0
-#define O_WRONLY 0
-
-#define R_OK 1
-#define W_OK 2
-#define X_OK 4
-
-/* it can either take an additonal mode_t argument or none */
-int open(const char *path, int flags, ...);
-int fcntl(int fd, int cmd, ...);
diff --git a/src/user/lib/include/ftw.h b/src/user/lib/include/ftw.h
deleted file mode 100644
index 6dc8132..0000000
--- a/src/user/lib/include/ftw.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-#include <sys/stat.h>
-
-int ftw(const char *dirpath,
- int (*fn)(const char *fpath, const struct stat *sb, int typeflag),
- int nopenfd);
diff --git a/src/user/lib/include/getopt.h b/src/user/lib/include/getopt.h
deleted file mode 120000
index 4890ceb..0000000
--- a/src/user/lib/include/getopt.h
+++ /dev/null
@@ -1 +0,0 @@
-../vendor/getopt/getopt.h \ No newline at end of file
diff --git a/src/user/lib/include/grp.h b/src/user/lib/include/grp.h
deleted file mode 100644
index e7b99c9..0000000
--- a/src/user/lib/include/grp.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma once
-#include <sys/types.h>
-
-struct group {
- char *gr_name;
- char *gr_passwd;
- gid_t gr_gid;
- char **gr_mem;
-};
-
-struct group *getgrgid(gid_t gid);
diff --git a/src/user/lib/include/inttypes.h b/src/user/lib/include/inttypes.h
deleted file mode 100644
index 9a6118b..0000000
--- a/src/user/lib/include/inttypes.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <stdint.h>
diff --git a/src/user/lib/include/limits.h b/src/user/lib/include/limits.h
deleted file mode 100644
index 972553f..0000000
--- a/src/user/lib/include/limits.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-#include <camellia/path.h> // just for PATH_MAX
-// #include_next <limits.h>
-
-#define _POSIX2_RE_DUP_MAX 255
-#define NAME_MAX 255
diff --git a/src/user/lib/include/locale.h b/src/user/lib/include/locale.h
deleted file mode 100644
index 1221375..0000000
--- a/src/user/lib/include/locale.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#pragma once
-#include <limits.h>
-
-#define LC_ALL 0
-#define LC_COLLATE 1
-#define LC_CTYPE 2
-#define LC_MESSAGES 3
-#define LC_MONETARY 4
-#define LC_NUMERIC 5
-#define LC_TIME 6
-
-struct lconv {
- char *decimal_point;
- char *thousands_sep;
- char *grouping;
- char *mon_decimal_point;
- char *mon_thousands_sep;
- char *mon_grouping;
- char *positive_sign;
- char *negative_sign;
- char *currency_symbol;
- char frac_digits;
- char p_cs_precedes;
- char n_cs_precedes;
- char p_sep_by_space;
- char n_sep_by_space;
- char p_sign_posn;
- char n_sign_posn;
- char *int_curr_symbol;
- char int_frac_digits;
- char int_p_cs_precedes;
- char int_n_cs_precedes;
- char int_p_sep_by_space;
- char int_n_sep_by_space;
- char int_p_sign_posn;
- char int_n_sign_posn;
-};
-
-static inline struct lconv *localeconv(void) {
- /* per Linux's lconv(3) */
- static struct lconv locale = (struct lconv){
- .decimal_point = ".",
- .thousands_sep = "",
- .grouping = "",
- .mon_decimal_point = "",
- .mon_thousands_sep = "",
- .mon_grouping = "",
- .positive_sign = "",
- .negative_sign = "",
- .currency_symbol = "",
- .frac_digits = CHAR_MAX,
- .p_cs_precedes = CHAR_MAX,
- .n_cs_precedes = CHAR_MAX,
- .p_sep_by_space = CHAR_MAX,
- .n_sep_by_space = CHAR_MAX,
- .p_sign_posn = CHAR_MAX,
- .n_sign_posn = CHAR_MAX,
- .int_curr_symbol = "",
- .int_frac_digits = CHAR_MAX,
- .int_p_cs_precedes = CHAR_MAX,
- .int_n_cs_precedes = CHAR_MAX,
- .int_p_sep_by_space = CHAR_MAX,
- .int_n_sep_by_space = CHAR_MAX,
- .int_p_sign_posn = CHAR_MAX,
- .int_n_sign_posn = CHAR_MAX,
- };
- return &locale;
-}
-
-static inline char *setlocale(int category, const char *locale) {
- (void)category; (void)locale;
- return NULL;
-}
diff --git a/src/user/lib/include/malloc.h b/src/user/lib/include/malloc.h
deleted file mode 120000
index 80b9bf5..0000000
--- a/src/user/lib/include/malloc.h
+++ /dev/null
@@ -1 +0,0 @@
-../vendor/dlmalloc/malloc.h \ No newline at end of file
diff --git a/src/user/lib/include/math.h b/src/user/lib/include/math.h
deleted file mode 100644
index 1aec564..0000000
--- a/src/user/lib/include/math.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#pragma once
-
-#define INFINITY __builtin_inff()
-#define HUGE_VAL ((double)INFINITY)
-
-double acos(double x);
-double asin(double x);
-double atan2(double x, double y);
-double cos(double x);
-double cosh(double x);
-double sin(double x);
-double sinh(double x);
-double tan(double x);
-double tanh(double x);
-
-double fabs(double x);
-double floor(double x);
-double ceil(double x);
-double log(double x);
-double log2(double x);
-double log10(double x);
-double exp(double x);
-double fmod(double x, double y);
-double frexp(double num, int *exp);
-double ldexp(double x, int exp);
-double pow(double x, double y);
-double sqrt(double x);
diff --git a/src/user/lib/include/pwd.h b/src/user/lib/include/pwd.h
deleted file mode 100644
index 6721ca2..0000000
--- a/src/user/lib/include/pwd.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-#include <sys/types.h>
-
-struct passwd {
- char *pw_name;
- char *pw_passwd;
- uid_t pw_uid;
- gid_t pw_gid;
- char *pw_gecos;
- char *pw_dir;
- char *pw_shell;
-};
-
-struct passwd *getpwuid(uid_t uid);
diff --git a/src/user/lib/include/setjmp.h b/src/user/lib/include/setjmp.h
deleted file mode 100644
index 6d05d79..0000000
--- a/src/user/lib/include/setjmp.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#pragma once
-#include <bits/panic.h>
-
-typedef uint64_t jmp_buf[8]; /* rbx, rsp, rbp, r12, r13, r14, r15, rip */
-typedef char sigjmp_buf[1];
-
-int setjmp(jmp_buf env);
-_Noreturn void longjmp(jmp_buf env, int val);
-
-static inline int sigsetjmp(sigjmp_buf env, int savemask) {
- (void)env; (void)savemask;
- return 0;
-}
-
-static inline _Noreturn void siglongjmp(sigjmp_buf env, int val) {
- (void)env; (void)val;
- __libc_panic("unimplemented");
-}
diff --git a/src/user/lib/include/signal.h b/src/user/lib/include/signal.h
deleted file mode 100644
index 012481e..0000000
--- a/src/user/lib/include/signal.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#pragma once
-#include <bits/panic.h>
-#include <sys/types.h>
-#include <errno.h> // only for ENOSYS
-
-#define SIGHUP 1
-#define SIGINT 2
-#define SIGQUIT 3
-#define SIGILL 4
-#define SIGTRAP 5
-#define SIGABRT 6
-#define SIGFPE 8
-#define SIGKILL 9
-#define SIGSEGV 11
-#define SIGPIPE 13
-#define SIGALRM 14
-#define SIGTERM 15
-
-#define SIGCONT 16
-#define SIGPIPE 17
-#define SIGTSTP 18
-#define SIGTTIN 19
-#define SIGTTOU 20
-#define SIGWINCH 21
-#define SIGCHLD 22
-
-#define NSIG 32
-
-#define SIG_DFL 0
-#define SIG_ERR 0
-#define SIG_IGN 0
-#define SIG_SETMASK 0
-
-typedef int sig_atomic_t;
-typedef struct {} sigset_t;
-typedef struct {} siginfo_t;
-extern const char *const sys_siglist[];
-
-struct sigaction {
- void (*sa_handler)(int);
- void (*sa_sigaction)(int, siginfo_t *, void *);
- sigset_t sa_mask;
- int sa_flags;
- void (*sa_restorer)(void);
-};
-
-int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact);
-int sigemptyset(sigset_t *set);
-int sigfillset(sigset_t *set);
-int sigprocmask(int how, const sigset_t *set, const sigset_t *oldset);
-int sigsuspend(const sigset_t *mask);
-int signal(int sig, void (*func)(int));
-int kill(pid_t pid, int sig);
-int raise(int sig);
diff --git a/src/user/lib/include/stdio.h b/src/user/lib/include/stdio.h
deleted file mode 100644
index 48d5058..0000000
--- a/src/user/lib/include/stdio.h
+++ /dev/null
@@ -1,84 +0,0 @@
-#pragma once
-#include <bits/file.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <sys/types.h>
-
-#define EOF (-1)
-#define STDIN_FILENO 0
-#define STDOUT_FILENO 1
-#define STDERR_FILENO 2
-
-#define SEEK_SET 1
-#define SEEK_CUR 2
-#define SEEK_END 3
-
-#define _IONBF 0
-#define _IOFBF 1
-#define _IOLBF 2
-
-#define BUFSIZ 4096
-
-/* stop fread() from trying to fill the entire buffer before returning
- * i.e. it will call _sys_read() exactly once */
-#define FEXT_NOFILL 1
-
-int printf(const char *restrict fmt, ...);
-int fprintf(FILE *restrict f, const char *restrict fmt, ...);
-
-int sprintf(char *restrict s, const char *restrict fmt, ...);
-
-int vprintf(const char *restrict fmt, va_list ap);
-int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap);
-
-int _klogf(const char *fmt, ...); // for kernel debugging only
-
-
-extern FILE *const stdin, *const stdout, *const stderr;
-
-FILE *fopen(const char *path, const char *mode);
-FILE *freopen(const char *path, const char *mode, FILE *);
-FILE *fdopen(int fd, const char *mode);
-FILE *file_clone(const FILE *, const char *mode);
-FILE *popen(const char *cmd, const char *mode);
-int pclose(FILE *f);
-FILE *tmpfile(void);
-
-int fextflags(FILE *, int extflags);
-int setvbuf(FILE *restrict f, char *restrict buf, int type, size_t size);
-int fclose(FILE *);
-int fflush(FILE *f);
-
-size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict);
-size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict);
-int fputs(const char *s, FILE *f);
-char *fgets(char *buf, int size, FILE *f);
-int fgetc(FILE *f);
-int getc(FILE *f);
-int fputc(int c, FILE *f);
-int putc(int c, FILE *f);
-int ungetc(int c, FILE *f);
-
-int fseek(FILE *f, long offset, int whence);
-int fseeko(FILE *f, off_t offset, int whence);
-long ftell(FILE *f);
-off_t ftello(FILE *f);
-
-int feof(FILE *);
-int ferror(FILE *);
-void clearerr(FILE *f);
-
-void perror(const char *s);
-int puts(const char *s);
-int getchar(void);
-int putchar(int c);
-
-off_t lseek(int fd, off_t off, int whence);
-
-int remove(const char *path);
-int rename(const char *old, const char *new);
-
-#define L_tmpnam (5 + 16 + 1)
-char *tmpnam(char *s);
-
-int sscanf(const char *restrict s, const char *restrict format, ...);
diff --git a/src/user/lib/include/stdlib.h b/src/user/lib/include/stdlib.h
deleted file mode 100644
index ee9d179..0000000
--- a/src/user/lib/include/stdlib.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#pragma once
-#include <stddef.h>
-#include <stdlib.h>
-
-#ifndef NO_MALLOC_H
-#include <malloc.h>
-#endif
-
-#define EXIT_SUCCESS 0
-#define EXIT_FAILURE 1
-
-_Noreturn void abort(void);
-_Noreturn void exit(int);
-
-const char *getprogname(void);
-void setprogname(const char *progname);
-void setproctitle(const char *fmt, ...);
-
-int mkstemp(char *template);
-char *getenv(const char *name);
-int system(const char *cmd);
-
-int abs(int i);
-
-int atoi(const char *s);
-double atof(const char *s);
-
-long strtol(const char *restrict s, char **restrict end, int base);
-long long strtoll(const char *restrict s, char **restrict end, int base);
-unsigned long strtoul(const char *restrict s, char **restrict end, int base);
-unsigned long long strtoull(const char *restrict s, char **restrict end, int base);
-double strtod(const char *restrict s, char **restrict end);
-
-void qsort(void *base, size_t nmemb, size_t size, int (*cmp)(const void *a, const void *b));
diff --git a/src/user/lib/include/string.h b/src/user/lib/include/string.h
deleted file mode 100644
index 78bed9b..0000000
--- a/src/user/lib/include/string.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma once
-#include <shared/mem.h>
-#include <strings.h> /* work around bad include in dash */
-
-char *strchr(const char *s, int c);
-char *strrchr(const char *s, int c);
-
-size_t strspn(const char *s, const char *accept);
-size_t strcspn(const char *s, const char *reject);
-char *strpbrk(const char *s1, const char *s2);
-
-char *strtok(char *restrict s, const char *restrict sep);
-char *strtok_r(char *restrict s, const char *restrict sep, char **restrict state);
-
-int strncmp(const char *s1, const char *s2, size_t n);
-int strcoll(const char *s1, const char *s2);
-
-char *strstr(const char *s1, const char *s2);
-
-char *strcpy(char *restrict s1, const char *restrict s2);
-char *strncpy(char *restrict s1, const char *restrict s2, size_t n);
-char *stpncpy(char *restrict dst, const char *restrict src, size_t n);
-char *strdup(const char *s);
-
-char *strerror(int errnum);
diff --git a/src/user/lib/include/strings.h b/src/user/lib/include/strings.h
deleted file mode 100644
index d0abc47..0000000
--- a/src/user/lib/include/strings.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-#include <stddef.h>
-
-int strcasecmp(const char *s1, const char *s2);
-int strncasecmp(const char *s1, const char *s2, size_t n);
diff --git a/src/user/lib/include/sys/ioctl.h b/src/user/lib/include/sys/ioctl.h
deleted file mode 100644
index 708bc3f..0000000
--- a/src/user/lib/include/sys/ioctl.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-#include <errno.h> // only for ENOSYS
-
-#define TIOCGWINSZ 0
-struct winsize {
- int ws_row, ws_col;
-};
-
-static inline int ioctl(int fd, int req, ...) {
- (void)fd; (void)req;
- errno = ENOSYS;
- return -1;
-}
diff --git a/src/user/lib/include/sys/mman.h b/src/user/lib/include/sys/mman.h
deleted file mode 100644
index 074ebe2..0000000
--- a/src/user/lib/include/sys/mman.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#pragma once
-#include <camellia/flags.h>
-#include <sys/types.h>
-
-#define MMAP_UNSUPPORTED 0xFFFF
-
-#define PROT_EXEC 1
-#define PROT_NONE MMAP_UNSUPPORTED
-#define PROT_READ 1
-#define PROT_WRITE 1
-
-#define MAP_FIXED MMAP_UNSUPPORTED
-#define MAP_PRIVATE 0
-#define MAP_SHARED MMAP_UNSUPPORTED
-#define MAP_ANONYMOUS 1
-
-void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off);
-int munmap(void *addr, size_t len);
diff --git a/src/user/lib/include/sys/param.h b/src/user/lib/include/sys/param.h
deleted file mode 100644
index e6c9d6f..0000000
--- a/src/user/lib/include/sys/param.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#define MIN(a, b) ((a)<(b) ? (a):(b))
-#define MAX(a, b) ((a)<(b) ? (b):(a))
diff --git a/src/user/lib/include/sys/resource.h b/src/user/lib/include/sys/resource.h
deleted file mode 100644
index 4582ce0..0000000
--- a/src/user/lib/include/sys/resource.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#pragma once
-struct rusage {};
diff --git a/src/user/lib/include/sys/stat.h b/src/user/lib/include/sys/stat.h
deleted file mode 100644
index 343db55..0000000
--- a/src/user/lib/include/sys/stat.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#pragma once
-#include <bits/panic.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h> // struct timespec
-#include <errno.h> // only for ENOSYS
-
-struct stat {
- dev_t st_dev;
- ino_t st_ino;
- mode_t st_mode;
- nlink_t st_nlink;
- uid_t st_uid;
- gid_t st_gid;
- dev_t st_rdev;
- off_t st_size;
- blksize_t st_blksize;
- blkcnt_t st_blocks;
-
- struct timespec st_atim;
- struct timespec st_mtim;
- struct timespec st_ctim;
-
-#define st_atime st_atim.tv_sec
-#define st_mtime st_mtim.tv_sec
-#define st_ctime st_ctim.tv_sec
-};
-
-#define S_IFMT 0170000
-#define S_IFSOCK 0140000
-#define S_IFLNK 0120000
-#define S_IFREG 0100000
-#define S_IFBLK 0060000
-#define S_IFDIR 0040000
-#define S_IFCHR 0020000
-#define S_IFIFO 0010000
-#define S_ISUID 04000
-#define S_ISGID 02000
-#define S_ISVTX 01000
-
-/* inode(7) */
-#define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
-#define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
-#define S_ISCHR(m) ((m & S_IFMT) == S_IFCHR)
-#define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK)
-#define S_ISFIFO(m) ((m & S_IFMT) == S_IFIFO)
-#define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK)
-#define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK)
-
-int fstat(int fd, struct stat *sb);
-int stat(const char *restrict path, struct stat *restrict sb);
-int lstat(const char *restrict path, struct stat *restrict sb);
-int mkdir(const char *path, mode_t mode);
-
-static inline mode_t umask(mode_t mask) {
- (void)mask;
- __libc_panic("unimplemented");
-}
-
-static inline int chmod(const char *path, mode_t mode) {
- (void)path; (void)mode;
- errno = ENOSYS;
- return -1;
-}
-
-static inline int mknod(const char *path, mode_t mode, dev_t dev) {
- (void)path; (void)mode; (void)dev;
- errno = ENOSYS;
- return -1;
-}
diff --git a/src/user/lib/include/sys/sysmacros.h b/src/user/lib/include/sys/sysmacros.h
deleted file mode 100644
index 30e0efd..0000000
--- a/src/user/lib/include/sys/sysmacros.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#define makedev(maj, min) 0
-#define major(x) 0
-#define minor(x) 0
diff --git a/src/user/lib/include/sys/time.h b/src/user/lib/include/sys/time.h
deleted file mode 100644
index e69de29..0000000
--- a/src/user/lib/include/sys/time.h
+++ /dev/null
diff --git a/src/user/lib/include/sys/times.h b/src/user/lib/include/sys/times.h
deleted file mode 100644
index 4a8d3ef..0000000
--- a/src/user/lib/include/sys/times.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-#include <bits/panic.h>
-
-struct tms {
- clock_t tms_utime;
- clock_t tms_stime;
- clock_t tms_cutime;
- clock_t tms_cstime;
-};
-
-static inline clock_t times(struct tms *buf) {
- __libc_panic("unimplemented");
-}
diff --git a/src/user/lib/include/sys/types.h b/src/user/lib/include/sys/types.h
deleted file mode 100644
index faf656a..0000000
--- a/src/user/lib/include/sys/types.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#pragma once
-#include <stddef.h>
-#include <stdint.h>
-
-typedef long long off_t;
-typedef int64_t time_t;
-typedef uint64_t clock_t;
-typedef int mode_t;
-
-typedef int dev_t;
-typedef int ino_t;
-typedef int mode_t;
-typedef int nlink_t;
-typedef int uid_t;
-typedef int gid_t;
-typedef int blksize_t;
-typedef int blkcnt_t;
-typedef int pid_t;
diff --git a/src/user/lib/include/sys/wait.h b/src/user/lib/include/sys/wait.h
deleted file mode 100644
index cff407e..0000000
--- a/src/user/lib/include/sys/wait.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-#include <sys/types.h>
-
-#define WIFSTOPPED(x) 0
-#define WEXITSTATUS(x) ((x)&0xFF)
-#define WIFEXITED(x) 1
-#define WSTOPSIG(x) 0
-#define WTERMSIG(x) 0
-
-#define WNOHANG 0
-#define WUNTRACED 0
-
-pid_t wait3(int *wstatus, int opts, struct rusage *rusage);
diff --git a/src/user/lib/include/termios.h b/src/user/lib/include/termios.h
deleted file mode 100644
index e69de29..0000000
--- a/src/user/lib/include/termios.h
+++ /dev/null
diff --git a/src/user/lib/include/thread.h b/src/user/lib/include/thread.h
deleted file mode 100644
index 5a5ddc0..0000000
--- a/src/user/lib/include/thread.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-#include <stdlib.h>
-
-void thread_creates(int flags, void (*fn)(void*), void *arg, void *stack);
-
-static inline void thread_create(int flags, void (*fn)(void*), void *arg) {
- /* error checking is for WIMPS. */
- thread_creates(flags, fn, arg, malloc(4096) + 4096);
-}
diff --git a/src/user/lib/include/time.h b/src/user/lib/include/time.h
deleted file mode 100644
index 5d03664..0000000
--- a/src/user/lib/include/time.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#pragma once
-#include <sys/types.h>
-
-#define CLOCKS_PER_SEC 1000000
-
-struct tm {
- int tm_sec; /* Seconds [0,60]. */
- int tm_min; /* Minutes [0,59]. */
- int tm_hour; /* Hour [0,23]. */
- int tm_mday; /* Day of month [1,31]. */
- int tm_mon; /* Month of year [0,11]. */
- int tm_year; /* Years since 1900. */
- int tm_wday; /* Day of week [0,6] (Sunday =0). */
- int tm_yday; /* Day of year [0,365]. */
- int tm_isdst; /* Daylight Savings flag. */
-};
-
-struct timespec {
- time_t tv_sec;
- long long tv_nsec;
-};
-
-time_t time(time_t *tloc);
-clock_t clock(void);
-
-struct tm *gmtime(const time_t *timer);
-struct tm *localtime(const time_t *timer);
-time_t mktime(struct tm *timeptr);
-
-double difftime(time_t time1, time_t time0);
-
-size_t strftime(
- char *restrict s, size_t maxsize,
- const char *restrict format, const struct tm *restrict timeptr);
diff --git a/src/user/lib/include/unistd.h b/src/user/lib/include/unistd.h
deleted file mode 100644
index 005e79c..0000000
--- a/src/user/lib/include/unistd.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#pragma once
-#include <camellia/types.h> // TODO only needed because of hid_t
-#include <sys/types.h>
-#include <getopt.h>
-
-// TODO custom stdint.h, ssize_t doesn't belong here
-typedef long long ssize_t;
-
-extern char **environ;
-
-int fork(void);
-pid_t vfork(void);
-int close(hid_t h);
-_Noreturn void _exit(int);
-
-ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize);
-int link(const char *path1, const char *path2);
-int unlink(const char *path);
-int symlink(const char *path1, const char *path2);
-int isatty(int fd);
-
-int execv(const char *path, char *const argv[]);
-int execve(const char *path, char *const argv[], char *const envp[]);
-
-int chdir(const char *path);
-char *getcwd(char *buf, size_t size);
-
-uid_t getuid(void);
-uid_t geteuid(void);
-gid_t getgid(void);
-gid_t getegid(void);
-
-int chown(const char *path, uid_t owner, gid_t group);
-
-int setpgid(pid_t pid, pid_t pgid);
-pid_t tcgetpgrp(int fd);
-int tcsetpgrp(int fd, pid_t pgrp);
-pid_t getpgrp(void);
-pid_t getpid(void);
-pid_t getppid(void);
-
-int getgroups(int size, gid_t list[]);
-
-ssize_t read(int fd, void *buf, size_t count);
-ssize_t write(int fd, const void *buf, size_t count);
-int pipe(int pipefd[2]);
-int dup2(int oldfd, int newfd);
-
-/* Converts a relative path to an absolute one, simplifying it if possible.
- * If in == NULL - return the length of cwd. Doesn't include the trailing slash,
- * except for the root dir. Includes the null byte.
- * If size isn't enough to fit the path, returns the amount of bytes needed to fit
- * it, including the null byte.
- *
- * Note that some errors are only detected if *out != NULL, so you must check the return
- * value twice.
- * @return 0 on failure, length of the path otherwise */
-size_t absolutepath(char *out, const char *in, size_t size);
-
-// TODO put in an internal libc header
-void __setinitialcwd(const char *c);
-
-void intr_set(void (*fn)(void));
-void intr_default(void);
diff --git a/src/user/lib/intr.s b/src/user/lib/intr.s
deleted file mode 100644
index 008387d..0000000
--- a/src/user/lib/intr.s
+++ /dev/null
@@ -1,20 +0,0 @@
-.section .text
-.global intr_trampoline
-.type intr_trampoline, @function
-intr_trampoline:
- push %rax
- push %rdx
- call *_intr(%rip)
- pop %rdx
- pop %rax
- pop tmprip(%rip)
- pop %rsp
- jmp *tmprip(%rip)
-
-.section .bss
-tmprip:
- .skip 8
-
-.global _intr
-_intr:
- .skip 8
diff --git a/src/user/lib/math.c b/src/user/lib/math.c
deleted file mode 100644
index 4f8eda4..0000000
--- a/src/user/lib/math.c
+++ /dev/null
@@ -1,27 +0,0 @@
-#include <math.h>
-#include <bits/panic.h>
-
-// TODO port a libm
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-double acos(double x) { __libc_panic("unimplemented"); }
-double asin(double x) { __libc_panic("unimplemented"); }
-double atan2(double x, double y) { __libc_panic("unimplemented"); }
-double cos(double x) { __libc_panic("unimplemented"); }
-double cosh(double x) { __libc_panic("unimplemented"); }
-double sin(double x) { __libc_panic("unimplemented"); }
-double sinh(double x) { __libc_panic("unimplemented"); }
-double tan(double x) { __libc_panic("unimplemented"); }
-double tanh(double x) { __libc_panic("unimplemented"); }
-
-double fabs(double x) { __libc_panic("unimplemented"); }
-double floor(double x) { __libc_panic("unimplemented"); }
-double ceil(double x) { __libc_panic("unimplemented"); }
-double log(double x) { __libc_panic("unimplemented"); }
-double log2(double x) { __libc_panic("unimplemented"); }
-double log10(double x) { __libc_panic("unimplemented"); }
-double exp(double x) { __libc_panic("unimplemented"); }
-double fmod(double x, double y) { __libc_panic("unimplemented"); }
-double frexp(double num, int *exp) { __libc_panic("unimplemented"); }
-double ldexp(double x, int exp) { __libc_panic("unimplemented"); }
-double pow(double x, double y) { __libc_panic("unimplemented"); }
-double sqrt(double x) { __libc_panic("unimplemented"); }
diff --git a/src/user/lib/mman.c b/src/user/lib/mman.c
deleted file mode 100644
index 32eeb2a..0000000
--- a/src/user/lib/mman.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/* mmap() emulation */
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <sys/mman.h>
-
-void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off) {
- (void)fd; (void) off;
- if ((flags & MMAP_UNSUPPORTED) == MMAP_UNSUPPORTED ||
- (prot & MMAP_UNSUPPORTED) == MMAP_UNSUPPORTED ||
- !(flags & MAP_ANONYMOUS))
- {
- errno = ENOSYS;
- return NULL;
- }
-
- void *p = _sys_memflag(addr, len, MEMFLAG_FINDFREE | MEMFLAG_PRESENT);
- if (!p) errno = ENOMEM;
- return p;
-}
-
-int munmap(void *addr, size_t len) {
- _sys_memflag(addr, len, 0);
- return 0;
-}
diff --git a/src/user/lib/printf.c b/src/user/lib/printf.c
deleted file mode 100644
index ad1fd06..0000000
--- a/src/user/lib/printf.c
+++ /dev/null
@@ -1,56 +0,0 @@
-#include <camellia/syscalls.h>
-#include <shared/printf.h>
-#include <stdio.h>
-#include <string.h>
-
-
-static void backend_file(void *arg, const char *buf, size_t len) {
- fwrite(buf, 1, len, arg);
-}
-
-int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap) {
- return __printf_internal(fmt, ap, backend_file, f);
-}
-
-
-int printf(const char *restrict fmt, ...) {
- int ret;
- va_list argp;
- va_start(argp, fmt);
- ret = vprintf(fmt, argp);
- va_end(argp);
- return ret;
-}
-
-int fprintf(FILE *restrict f, const char *restrict fmt, ...) {
- int ret;
- va_list argp;
- va_start(argp, fmt);
- ret = vfprintf(f, fmt, argp);
- va_end(argp);
- return ret;
-}
-
-int sprintf(char *restrict s, const char *restrict fmt, ...) {
- int ret;
- va_list argp;
- va_start(argp, fmt);
- ret = vsnprintf(s, ~0, fmt, argp);
- va_end(argp);
- return ret;
-}
-
-int vprintf(const char *restrict fmt, va_list ap) {
- return vfprintf(stdout, fmt, ap);
-}
-
-int _klogf(const char *fmt, ...) {
- char buf[256];
- int ret;
- va_list argp;
- va_start(argp, fmt);
- ret = vsnprintf(buf, sizeof buf, fmt, argp);
- va_end(argp);
- _sys_debug_klog(buf, ret);
- return ret;
-}
diff --git a/src/user/lib/pwd.c b/src/user/lib/pwd.c
deleted file mode 100644
index d7bf2af..0000000
--- a/src/user/lib/pwd.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <grp.h>
-#include <pwd.h>
-#include <string.h>
-
-struct passwd *
-getpwuid(uid_t uid)
-{
- static struct passwd p;
- memset(&p, 0, sizeof p);
- p.pw_name = "unnamed";
- p.pw_uid = uid;
- return &p;
-}
-
-struct group *
-getgrgid(gid_t gid)
-{
- static struct group g;
- memset(&g, 0, sizeof g);
- g.gr_name = "unnamed";
- g.gr_gid = gid;
- return &g;
-}
diff --git a/src/user/lib/setjmp.s b/src/user/lib/setjmp.s
deleted file mode 100644
index 29292da..0000000
--- a/src/user/lib/setjmp.s
+++ /dev/null
@@ -1,39 +0,0 @@
-.section .text
-.global setjmp
-.type setjmp, @function
-// int setjmp(jmp_buf env);
-setjmp:
- mov %rbx, 0(%rdi)
- mov %rbp, 16(%rdi)
- mov %r12, 24(%rdi)
- mov %r13, 32(%rdi)
- mov %r14, 40(%rdi)
- mov %r15, 48(%rdi)
- /* save registers as if after a ret */
- lea 8(%rsp), %rax
- mov %rax, 8(%rdi)
- mov (%rsp), %rax
- mov %rax, 56(%rdi)
- xor %rax, %rax
-
- mov 8(%rdi), %rsp
- jmp *56(%rdi)
-
- ret
-
-
-.global longjmp
-.type longjmp, @function
-// _Noreturn void longjmp(jmp_buf env, int val);
-longjmp:
- mov %rsi, %rax
- cmp $1, %rax /* carry set as for %rax - 1 - so, 1 only if %rax == 0 */
- adc $0, %rax
-1: mov 0(%rdi), %rbx
- mov 8(%rdi), %rsp
- mov 16(%rdi), %rbp
- mov 24(%rdi), %r12
- mov 32(%rdi), %r13
- mov 40(%rdi), %r14
- mov 48(%rdi), %r15
- jmp *56(%rdi)
diff --git a/src/user/lib/signal.c b/src/user/lib/signal.c
deleted file mode 100644
index 3200263..0000000
--- a/src/user/lib/signal.c
+++ /dev/null
@@ -1,100 +0,0 @@
-#include <bits/panic.h>
-#include <signal.h>
-
-const char *const sys_siglist[] = {
- NULL,
- "SIGHUP", /* 1 */
- "SIGINT", /* 2 */
- "SIGQUIT", /* 3 */
- "SIGILL", /* 4 */
- "SIGTRAP", /* 5 */
- "SIGABRT", /* 6 */
- "SIGFPE", /* 8 */
- "SIGKILL", /* 9 */
- "SIGSEGV", /* 11 */
- "SIGPIPE", /* 13 */
- "SIGALRM", /* 14 */
- "SIGTERM", /* 15 */
- "SIGCONT", /* 16 */
- "SIGPIPE", /* 17 */
- "SIGTSTP", /* 18 */
- "SIGTTIN", /* 19 */
- "SIGTTOU", /* 20 */
- "SIGWINCH", /* 21 */
- "SIGCHLD", /* 22 */
-};
-
-static struct sigaction sigaction_default = {};
-static struct sigaction *sigaction_current[] = {
- NULL,
- &sigaction_default, /* 1 */
- &sigaction_default, /* 2 */
- &sigaction_default, /* 3 */
- &sigaction_default, /* 4 */
- &sigaction_default, /* 5 */
- &sigaction_default, /* 6 */
- &sigaction_default, /* 8 */
- &sigaction_default, /* 9 */
- &sigaction_default, /* 11 */
- &sigaction_default, /* 13 */
- &sigaction_default, /* 14 */
- &sigaction_default, /* 15 */
- &sigaction_default, /* 16 */
- &sigaction_default, /* 17 */
- &sigaction_default, /* 18 */
- &sigaction_default, /* 19 */
- &sigaction_default, /* 20 */
- &sigaction_default, /* 21 */
- &sigaction_default, /* 22 */
-};
-
-int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact) {
- const int siglen = sizeof(sigaction_current) / sizeof(sigaction_current[0]);
- if (sig >= siglen) {
- return errno = EINVAL, -1;
- }
- if (oldact) {
- oldact = sigaction_current[sig];
- }
- if (act) {
- if (sig == SIGKILL) {
- return errno = EINVAL, -1;
- }
- sigaction_current[sig] = (void*)act;
- }
- return 0;
-}
-
-int sigemptyset(sigset_t *set) {
- (void)set;
- return 0;
-}
-
-int sigfillset(sigset_t *set) {
- (void)set;
- return 0;
-}
-
-int sigprocmask(int how, const sigset_t *set, const sigset_t *oldset) {
- return 0;
-}
-
-int sigsuspend(const sigset_t *mask) {
- (void)mask;
- __libc_panic("unimplemented");
-}
-
-int signal(int sig, void (*func)(int)) {
- (void)sig; (void)func;
- return errno = ENOSYS, SIG_ERR;
-}
-
-int kill(pid_t pid, int sig) {
- (void)pid; (void)sig;
- __libc_panic("unimplemented");
-}
-
-int raise(int sig) {
- (void)sig;
- __libc_panic("unimplemented");
-}
diff --git a/src/user/lib/stdio/file.c b/src/user/lib/stdio/file.c
deleted file mode 100644
index efaf013..0000000
--- a/src/user/lib/stdio/file.c
+++ /dev/null
@@ -1,359 +0,0 @@
-#include "file.h"
-#include <bits/panic.h>
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/param.h>
-#include <unistd.h>
-
-static FILE _stdin_null = { .fd = STDIN_FILENO };
-static FILE _stdout_null = { .fd = STDOUT_FILENO };
-static FILE _stderr_null = { .fd = STDERR_FILENO };
-FILE *const stdin = &_stdin_null;
-FILE *const stdout = &_stdout_null;
-FILE *const stderr = &_stderr_null;
-
-
-FILE *fopen(const char *path, const char *mode) {
- FILE *f;
- hid_t h;
- int flags = 0;
- if (!path) {
- errno = 1;
- return NULL;
- } else if (path[0] == '!') {
- /* special handling for "!files" */
- path++;
- if (!strcmp(path, "stdin")) return file_clone(stdin, mode);
- if (!strcmp(path, "stdout")) return file_clone(stdout, mode);
- if (!strcmp(path, "stderr")) return file_clone(stderr, mode);
- errno = ENOENT;
- return NULL;
- }
-
- if (strchr(mode, 'e')) {
- /* camellia extension: open as executable */
- flags |= OPEN_EXEC;
- } else if (strchr(mode, 'r')) {
- flags |= OPEN_READ;
- if (strchr(mode, '+'))
- flags |= OPEN_WRITE;
- } else {
- flags |= OPEN_WRITE | OPEN_CREATE;
- }
-
- h = camellia_open(path, flags);
- if (h < 0) return NULL;
-
- if (mode[0] == 'w')
- _sys_write(h, NULL, 0, 0, WRITE_TRUNCATE);
-
- f = fdopen(h, mode);
- if (!f) close(h);
- setvbuf(f, NULL, _IOFBF, 0);
- return f;
-}
-
- FILE *freopen(const char *path, const char *mode, FILE *f) {
- /* partially based on the musl implementation of freopen */
- FILE *f2;
- if (!path) goto fail;
- f2 = fopen(path, mode);
- if (!f2) goto fail;
-
- if (f->fd == f2->fd) {
- f2->fd = -1;
- } else {
- if (_sys_dup(f2->fd, f->fd, 0) < 0) goto fail2;
- }
- f->pos = f2->pos;
- f->eof = f2->eof;
- fclose(f2);
- return f;
-
-fail2:
- fclose(f2);
-fail:
- fclose(f);
- return NULL;
-}
-
-FILE *fdopen(int fd, const char *mode) {
- FILE *f;
- f = calloc(1, sizeof *f);
- if (f) {
- f->fd = fd;
- f->pos = mode[0] == 'a' ? -1 : 0;
- }
- return f;
-}
-
-FILE *file_clone(const FILE *f, const char *mode) {
- hid_t h = _sys_dup(f->fd, -1, 0);
- FILE *f2;
- if (h < 0) return NULL;
-
- f2 = fdopen(h, mode);
- if (!f2) {
- close(h);
- return NULL;
- }
- f2->pos = f->pos;
- f2->eof = f->eof;
- f2->fd = h;
- return f2;
-}
-
-// TODO popen / pclose
-FILE *popen(const char *cmd, const char *mode) {
- (void)cmd; (void)mode;
- errno = ENOSYS;
- return NULL;
-}
-
-int pclose(FILE *f) {
- (void)f;
- errno = ENOSYS;
- return -1;
-}
-
-// TODO tmpfile()
-FILE *tmpfile(void) {
- errno = ENOSYS;
- return NULL;
-}
-
-
-int fextflags(FILE *f, int extflags) {
- int old = f->extflags;
- f->extflags = extflags;
- return old;
-}
-
-int setvbuf(FILE *restrict f, char *restrict buf, int type, size_t size) {
- if (type == _IONBF) {
- free(f->readbuf);
- f->readbuf = NULL;
- return 0;
- } else if (type == _IOFBF && buf == NULL) {
- (void) size;
- f->rblen = 0;
- f->rbcap = BUFSIZ;
- f->readbuf = malloc(f->rbcap);
- return f->readbuf ? 0 : -1;
- } else {
- return errno = ENOSYS, -1;
- }
-}
-
-static void fadvance(long amt, FILE *f) {
- bool pos_neg = f->pos < 0;
- f->pos += amt;
- if (pos_neg && f->pos >= 0)
- f->pos = -1;
-}
-
-size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict f) {
- size_t total = size*nitems, pos = 0;
- unsigned char *buf = ptr;
-
- if (f->fd < 0) {
- errno = EBADF;
- return 0;
- }
- if (size == 0) {
- return 0;
- }
-
- while (pos < total) {
- long res = 0;
- if (f->readbuf) {
- if (0 == f->rblen && total - pos < (f->rbcap >> 1)) {
- res = _sys_read(f->fd, f->readbuf, f->rbcap, f->pos);
- if (res < 0) {
- f->error = true;
- errno = -res;
- break;
- } else if (res == 0) {
- f->eof = true;
- break;
- } else {
- f->rblen = res;
- }
- }
- if (0 < f->rblen) {
- res = MIN(total - pos, f->rblen);
- memcpy(buf + pos, f->readbuf, res);
- f->rblen -= res;
- memmove(f->readbuf, f->readbuf + res, f->rblen);
- }
- }
- if (res == 0) {
- /* no cache hit */
- res = _sys_read(f->fd, buf + pos, total - pos, f->pos);
- if (res < 0) {
- f->error = true;
- errno = -res;
- break;
- } else if (res == 0) {
- f->eof = true;
- break;
- }
- }
- pos += res;
- fadvance(res, f);
- if (f->extflags & FEXT_NOFILL) break;
- }
- return pos == total ? nitems : (pos/size);
-}
-
-size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict f) {
- size_t total = size*nitems, pos = 0;
- const unsigned char *buf = ptr;
-
- if (f->fd < 0) {
- errno = EBADF;
- return 0;
- }
- if (size == 0)
- return 0;
-
- while (pos < total) {
- long res = _sys_write(f->fd, buf + pos, total - pos, f->pos, 0);
- if (res < 0) {
- f->error = true;
- errno = -res;
- return pos/size;
- } else if (res == 0) {
- f->eof = true;
- return pos/size;
- } else {
- pos += res;
- fadvance(res, f);
- }
- }
- return nitems;
-}
-
-int fputs(const char *s, FILE *f) {
- return fprintf(f, "%s\n", s);
-}
-
-char *fgets(char *buf, int size, FILE *f) {
- int pos, c;
- for (pos = 0; pos < size-1; ) {
- c = fgetc(f);
- if (c == EOF) break;
- buf[pos++] = c;
- if (c == '\n') break;
- }
- if (pos == 0 || f->error) {
- return NULL;
- } else {
- buf[pos] = '\0';
- return buf;
- }
-}
-
-int fgetc(FILE *f) {
- char c;
- size_t ret = fread(&c, 1, 1, f);
- return ret ? c : EOF;
-}
-int getc(FILE *f) { return fgetc(f); }
-
-int fputc(int c, FILE *f) {
- return fwrite(&c, 1, 1, f) ? c : EOF;
-}
-int putc(int c, FILE *f) { return fputc(c, f); }
-
-// TODO ungetc
-int ungetc(int c, FILE *f) {
- (void)c; (void)f;
- __libc_panic("unimplemented");
-}
-
-int fseek(FILE *f, long offset, int whence) {
- return fseeko(f, offset, whence);
-}
-
-int fseeko(FILE *f, off_t offset, int whence) {
- if (fflush(f))
- return -1;
-
- long base;
- switch (whence) {
- case SEEK_SET:
- base = 0;
- break;
- case SEEK_CUR:
- base = f->pos;
- // TODO untested
- if (f->readbuf) {
- base -= f->rblen;
- }
- break;
- case SEEK_END:
- base = _sys_getsize(f->fd);
- if (base < 0)
- base = -1;
- break;
- default:
- errno = EINVAL;
- return -1;
- }
- f->rblen = 0;
-
- if (base >= 0 && base + offset < 0) {
- /* underflow */
- errno = EINVAL;
- return -1;
- } else if (base < 0 && base + offset >= 0) {
- /* overflow - went from a negative offset (relative to EOF)
- * to a positive offset (from start of file).
- * can only happen when getsize() is unsupported */
- errno = EINVAL;
- return -1;
- }
- f->pos = base + offset;
- f->eof = false;
- return 0;
-}
-
-long ftell(FILE *f) {
- return ftello(f);
-}
-
-off_t ftello(FILE *f) {
- return f->pos;
-}
-
-int fclose(FILE *f) {
- fflush(f);
- if (f->fd > 0) close(f->fd);
- free(f->readbuf);
- if (f != &_stdin_null && f != &_stdout_null && f != &_stderr_null)
- free(f);
- return 0;
-}
-
-int fflush(FILE *f) {
- (void)f;
- return 0;
-}
-
-int feof(FILE *f) {
- return f->eof;
-}
-
-int ferror(FILE *f) {
- return f->error;
-}
-
-void clearerr(FILE *f) {
- f->error = false;
- f->eof = false;
-}
diff --git a/src/user/lib/stdio/file.h b/src/user/lib/stdio/file.h
deleted file mode 100644
index 3bd64a1..0000000
--- a/src/user/lib/stdio/file.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-#include <stdbool.h>
-#include <stdio.h>
-
-struct _LIBC_FILE {
- int fd;
- long pos;
- bool eof;
- bool error;
- int extflags;
-
- char *readbuf;
- size_t rblen, rbcap;
-};
diff --git a/src/user/lib/stdio/misc.c b/src/user/lib/stdio/misc.c
deleted file mode 100644
index 45144f3..0000000
--- a/src/user/lib/stdio/misc.c
+++ /dev/null
@@ -1,52 +0,0 @@
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-void perror(const char *s) {
- if (s) fprintf(stderr, "%s: ", s);
- fprintf(stderr, "%s\n", strerror(errno));
-}
-
-int puts(const char *s) {
- return printf("%s\n", s);
-}
-
-int getchar(void) {
- return fgetc(stdin);
-}
-
-int putchar(int c) {
- return fputc(c, stdout);
-}
-
-off_t lseek(int fd, off_t off, int whence) {
- (void)fd; (void)off; (void)whence;
- errno = ENOSYS;
- return -1;
-}
-
-int remove(const char *path) {
- return unlink(path);
-}
-
-// TODO! VFSOP_MOVE
-int rename(const char *old, const char *new) {
- (void)old; (void)new;
- errno = ENOSYS;
- return -1;
-}
-
-// TODO tmpnam
-char *tmpnam(char *s) {
- static char buf[L_tmpnam];
- if (!s) s = buf;
- strcpy(s, "/tmp/tmpnam");
- return s;
-}
-
-// TODO sscanf
-int sscanf(const char *restrict s, const char *restrict format, ...) {
- (void)s; (void)format;
- return 0;
-}
diff --git a/src/user/lib/stdlib.c b/src/user/lib/stdlib.c
deleted file mode 100644
index 1739230..0000000
--- a/src/user/lib/stdlib.c
+++ /dev/null
@@ -1,148 +0,0 @@
-#include <_proc.h>
-#include <bits/panic.h>
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <ctype.h>
-#include <errno.h>
-#include <string.h>
-
-_Noreturn void abort(void) {
- _sys_exit(1);
-}
-
-static const char *progname;
-const char *getprogname(void) {
- return progname;
-}
-void setprogname(const char *pg) {
- progname = pg;
- setproctitle(NULL);
-}
-
-void setproctitle(const char *fmt, ...) {
- // TODO bounds checking
- if (!fmt) {
- strcpy(_psdata_loc->desc, progname);
- return;
- }
- sprintf(_psdata_loc->desc, "%s: ", progname);
-
- va_list argp;
- va_start(argp, fmt);
- vsnprintf(_psdata_loc->desc + strlen(_psdata_loc->desc), 128, fmt, argp);
- va_end(argp);
-}
-
-int mkstemp(char *template) {
- // TODO randomize template
- hid_t h = camellia_open(template, OPEN_CREATE | OPEN_RW);
- if (h < 0) {
- errno = -h;
- return -1;
- }
- // TODO truncate
- return h;
-}
-
-// TODO process env
-char *getenv(const char *name) {
- (void)name;
- return NULL;
-}
-
-// TODO system()
-int system(const char *cmd) {
- (void)cmd;
- errno = ENOSYS;
- return -1;
-}
-
-int abs(int i) {
- return i < 0 ? -i : i;
-}
-
-int atoi(const char *s) {
- return strtol(s, NULL, 10);
-}
-
-double atof(const char *s) {
- (void)s;
- __libc_panic("unimplemented");
-}
-
-static unsigned long long
-strton(const char *restrict s, char **restrict end, int base, int *sign)
-{
- long res = 0;
-
- while (isspace(*s)) s++;
-
- if (sign) *sign = 1;
- if (*s == '+') {
- s++;
- } else if (*s == '-') {
- s++;
- if (sign) *sign = -1;
- }
-
- if (base == 0) {
- if (*s == '0') {
- s++;
- if (*s == 'x' || *s == 'X') {
- s++;
- base = 16;
- } else {
- base = 8;
- }
- } else {
- base = 10;
- }
- }
-
- for (;;) {
- unsigned char digit = *s;
- if ('0' <= digit && digit <= '9') digit -= '0';
- else if ('a' <= digit && digit <= 'z') digit -= 'a' - 10;
- else if ('A' <= digit && digit <= 'Z') digit -= 'A' - 10;
- else break;
-
- if (digit >= base) break;
- // TODO overflow check
- res *= base;
- res += digit;
-
- s++;
- }
- if (end) *end = (void*)s;
- return res;
-}
-
-long strtol(const char *restrict s, char **restrict end, int base) {
- int sign;
- long n = strton(s, end, base, &sign);
- return n * sign;
-}
-
-long long strtoll(const char *restrict s, char **restrict end, int base) {
- int sign;
- long long n = strton(s, end, base, &sign);
- return n * sign;
-}
-
-unsigned long strtoul(const char *restrict s, char **restrict end, int base) {
- return strton(s, end, base, NULL);
-}
-
-unsigned long long strtoull(const char *restrict s, char **restrict end, int base) {
- return strton(s, end, base, NULL);
-}
-
-double strtod(const char *restrict s, char **restrict end) {
- (void)s; (void)end;
- __libc_panic("unimplemented");
-}
-
-void qsort(void *base, size_t nmemb, size_t size, int (*cmp)(const void *a, const void *b)) {
- (void)base; (void)nmemb; (void)size; (void)cmp;
- __libc_panic("unimplemented");
-}
diff --git a/src/user/lib/string/strerror.c b/src/user/lib/string/strerror.c
deleted file mode 100644
index c838299..0000000
--- a/src/user/lib/string/strerror.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <string.h>
-
-static const char *errstr[] = {
-# define E(n, str) [n] = str,
-# include <__errno.h>
-# undef E
-};
-
-char *strerror(int n) {
- if (0 <= n && n * sizeof(*errstr) < sizeof(errstr) && errstr[n])
- return (char*)errstr[n];
- return "unknown error";
-}
diff --git a/src/user/lib/string/string.c b/src/user/lib/string/string.c
deleted file mode 100644
index c65d7c5..0000000
--- a/src/user/lib/string/string.c
+++ /dev/null
@@ -1,122 +0,0 @@
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-
-char *strchr(const char *s, int c) {
- for (; *s || c == 0; s++) {
- if (*s == c) return (char *)s;
- }
- return NULL;
-}
-
-char *strrchr(const char *s, int c) {
- for (int i = strlen(s) + 1; i >= 0; i--) {
- if (s[i] == c) return (char *)s + i;
- }
- return NULL;
-}
-
-size_t strspn(const char *s, const char *accept) {
- size_t l = 0;
- for (; s[l] && strchr(accept, s[l]); l++);
- return l;
-}
-
-size_t strcspn(const char *s, const char *reject) {
- size_t l = 0;
- for (; s[l] && !strchr(reject, s[l]); l++);
- return l;
-}
-
-char *strpbrk(const char *s1, const char *s2) {
- for (; *s1; s1++) {
- if (strchr(s2, *s1)) return (char*)s1;
- }
- return NULL;
-}
-
-char *strtok(char *restrict s, const char *restrict sep) {
- static char *state;
- return strtok_r(s, sep, &state);
-}
-
-char *strtok_r(char *restrict s, const char *restrict sep, char **restrict state) {
- char *end;
- if (!s) s = *state;
- s += strspn(s, sep); /* beginning of token */
- if (!*s) return NULL;
-
- end = s + strcspn(s, sep);
- if (*end) {
- *end = '\0';
- *state = end + 1;
- } else {
- *state = end;
- }
- return s;
-}
-
-int strncmp(const char *s1, const char *s2, size_t n) {
- for (size_t i = 0; i < n; i++) {
- if (s1[i] < s2[i]) return -1;
- if (s1[i] > s2[i]) return 1;
- }
- return 0;
-}
-
-int strcoll(const char *s1, const char *s2) {
- return strcmp(s1, s2);
-}
-
-// TODO implement strstr using Boyer-Moore
-char *strstr(const char *s1, const char *s2) {
- size_t l1 = strlen(s1), l2 = strlen(s2);
- for (; l2 <= l1; s1++, l1--) {
- if (memcmp(s1, s2, l2) == 0) return (char*)s1;
- }
- return NULL;
-}
-
-char *strcpy(char *restrict s1, const char *restrict s2) {
- while (*s2) *s1++ = *s2++;
- *s1 = *s2;
- return s1;
-}
-
-char *strncpy(char *restrict dst, const char *restrict src, size_t n) {
- for (size_t i = 0; i < n; i++) {
- dst[i] = src[i];
- if (dst[i] == '\0') return dst + i; // TODO fill with null bytes
- }
- return dst;
-}
-
-char *stpncpy(char *restrict dst, const char *restrict src, size_t n) {
- return stpncpy(dst, src, n) + n;
-}
-
-char *strdup(const char *s) {
- size_t len = strlen(s) + 1;
- char *buf = malloc(len);
- if (buf) memcpy(buf, s, len);
- return buf;
-}
-
-/* strings.h */
-int strcasecmp(const char *s1, const char *s2) {
- return strncasecmp(s1, s2, ~0);
-}
-
-int strncasecmp(const char *s1, const char *s2, size_t n) {
- for (size_t i = 0; i < n; i++) {
- char c1 = tolower(s1[i]), c2 = tolower(s2[i]);
- if (c1 == '\0' || c1 != c2) {
- if (c1 < c2) return -1;
- else if (c1 > c2) return 1;
- else return 0;
- }
- }
- return 0;
-}
diff --git a/src/user/lib/syscall.c b/src/user/lib/syscall.c
deleted file mode 100644
index 5196683..0000000
--- a/src/user/lib/syscall.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/* generated by syscall.c.awk
- * don't modify manually, instead run:
- * make src/user/lib/syscall.c
- */
-#include <camellia/syscalls.h>
-
-
-_Noreturn void _sys_exit(long ret) {
- _syscall(_SYS_EXIT, ret, 0, 0, 0, 0);
- __builtin_unreachable();
-}
-
-long _sys_await(void) {
- return _syscall(_SYS_AWAIT, 0, 0, 0, 0, 0);
-}
-
-long _sys_fork(int flags, hid_t __user *fs_front) {
- return _syscall(_SYS_FORK, (long)flags, (long)fs_front, 0, 0, 0);
-}
-
-hid_t _sys_open(const char __user *path, long len, int flags) {
- return (hid_t)_syscall(_SYS_OPEN, (long)path, len, (long)flags, 0, 0);
-}
-
-long _sys_mount(hid_t h, const char __user *path, long len) {
- return _syscall(_SYS_MOUNT, (long)h, (long)path, len, 0, 0);
-}
-
-hid_t _sys_dup(hid_t from, hid_t to, int flags) {
- return (hid_t)_syscall(_SYS_DUP, (long)from, (long)to, (long)flags, 0, 0);
-}
-
-long _sys_read(hid_t h, void __user *buf, size_t len, long offset) {
- return _syscall(_SYS_READ, (long)h, (long)buf, (long)len, offset, 0);
-}
-
-long _sys_write(hid_t h, const void __user *buf, size_t len, long offset, int flags) {
- return _syscall(_SYS_WRITE, (long)h, (long)buf, (long)len, offset, (long)flags);
-}
-
-long _sys_getsize(hid_t h) {
- return _syscall(_SYS_GETSIZE, (long)h, 0, 0, 0, 0);
-}
-
-long _sys_remove(hid_t h) {
- return _syscall(_SYS_REMOVE, (long)h, 0, 0, 0, 0);
-}
-
-long _sys_close(hid_t h) {
- return _syscall(_SYS_CLOSE, (long)h, 0, 0, 0, 0);
-}
-
-hid_t _sys_fs_wait(char __user *buf, long max_len, struct ufs_request __user *res) {
- return (hid_t)_syscall(_SYS_FS_WAIT, (long)buf, max_len, (long)res, 0, 0);
-}
-
-long _sys_fs_respond(hid_t hid, const void __user *buf, long ret, int flags) {
- return _syscall(_SYS_FS_RESPOND, (long)hid, (long)buf, ret, (long)flags, 0);
-}
-
-void __user *_sys_memflag(void __user *addr, size_t len, int flags) {
- return (void __user *)_syscall(_SYS_MEMFLAG, (long)addr, (long)len, (long)flags, 0, 0);
-}
-
-long _sys_pipe(hid_t __user user_ends[2], int flags) {
- return _syscall(_SYS_PIPE, (long)user_ends, (long)flags, 0, 0, 0);
-}
-
-void _sys_sleep(long ms) {
- return (void)_syscall(_SYS_SLEEP, ms, 0, 0, 0, 0);
-}
-
-void _sys_filicide(void) {
- return (void)_syscall(_SYS_FILICIDE, 0, 0, 0, 0, 0);
-}
-
-void _sys_intr(void) {
- return (void)_syscall(_SYS_INTR, 0, 0, 0, 0, 0);
-}
-
-void _sys_intr_set(void __user *ip) {
- return (void)_syscall(_SYS_INTR_SET, (long)ip, 0, 0, 0, 0);
-}
-
-uint32_t _sys_getpid(void) {
- return (uint32_t)_syscall(_SYS_GETPID, 0, 0, 0, 0, 0);
-}
-
-uint32_t _sys_getppid(void) {
- return (uint32_t)_syscall(_SYS_GETPPID, 0, 0, 0, 0, 0);
-}
-
-int _sys_wait2(int pid, int flags, struct sys_wait2 __user *out) {
- return (int)_syscall(_SYS_WAIT2, (long)pid, (long)flags, (long)out, 0, 0);
-}
-
-long _sys_execbuf(void __user *buf, size_t len) {
- return _syscall(_SYS_EXECBUF, (long)buf, (long)len, 0, 0, 0);
-}
-
-void _sys_debug_klog(const void __user *buf, size_t len) {
- return (void)_syscall(_SYS_DEBUG_KLOG, (long)buf, (long)len, 0, 0, 0);
-}
-
diff --git a/src/user/lib/syscall.c.awk b/src/user/lib/syscall.c.awk
deleted file mode 100644
index 591a6f0..0000000
--- a/src/user/lib/syscall.c.awk
+++ /dev/null
@@ -1,51 +0,0 @@
-BEGIN {
- print "\
-/* generated by syscall.c.awk\n\
- * don't modify manually, instead run:\n\
- * make src/user/lib/syscall.c\n\
- */\n\
-#include <camellia/syscalls.h>\n\
-\n";
-}
-
-/_syscall\(/ { next; } # skipping _syscall(), it's implemented elsewhere
-
-/\);/ {
- sub(/;/, " {");
- print $0;
-
- name = substr($0, match($0, /_sys_[^(]+/), RLENGTH);
- rets = substr($0, 0, RSTART - 1);
- sub(/ *$/, "", rets)
-
- params = substr($0, match($0, /\(.+\)/) + 1, RLENGTH - 2);
- gsub(/\[[^\]]\]/, "", params);
- if (params == "void") params = ""
-
- split(params, p, /,/);
- for (i = 0; i < 6; i += 1) {
- if (p[i]) {
- # p[i] is a parameter, convert it into an expression to pass to _syscall()
- sub(/^ */, "", p[i]); # strip
- split(p[i], words, / /);
- if (length(words) != 1) {
- var = words[length(words)];
- sub(/\*/, "", var);
- if (words[1] != "long") var = "(long)" var;
- }
- p[i] = var;
- } else {
- p[i] = 0;
- }
- }
-
- printf "\t";
- if (!index($0, "_Noreturn")) {
- printf "return ";
- if (rets != "long") printf "(%s)", rets;
- }
- printf "_syscall(%s, %s, %s, %s, %s, %s);\n", toupper(name), p[1], p[2], p[3], p[4], p[5];
- if (index($0, "_Noreturn")) print "\t__builtin_unreachable();";
-
- print "}\n";
-}
diff --git a/src/user/lib/syscall.s b/src/user/lib/syscall.s
deleted file mode 100644
index 07f5631..0000000
--- a/src/user/lib/syscall.s
+++ /dev/null
@@ -1,9 +0,0 @@
-.section .text
-.global _syscall
-.type _syscall, @function
-_syscall:
- push %r10
- mov %rcx, %r10
- syscall
- pop %r10
- ret
diff --git a/src/user/lib/sysstat.c b/src/user/lib/sysstat.c
deleted file mode 100644
index 97bb50b..0000000
--- a/src/user/lib/sysstat.c
+++ /dev/null
@@ -1,50 +0,0 @@
-#include <camellia.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-int fstat(int fd, struct stat *sb) {
- (void)fd;
- memset(sb, 0, sizeof sb);
- // TODO save info if it was a dir
- sb->st_mode = 0777 | S_IFREG;
- return 0;
-}
-
-int stat(const char *restrict path, struct stat *restrict sb) {
- int fd, ret;
- fd = camellia_open(path, OPEN_READ);
- if (fd < 0) {
- return -1;
- }
- ret = fstat(fd, sb);
- close(fd);
- return ret;
-}
-
-int lstat(const char *restrict path, struct stat *restrict sb) {
- // TODO assumes no symlink support
- return stat(path, sb);
-}
-
-int mkdir(const char *path, mode_t mode) {
- // TODO error when directory already exits
- // TODO fopen-like wrapper that calls open() with a processed path
- (void)mode;
- size_t plen = strlen(path);
- char *tmp = NULL;
- /* ensure trailing slash */
- if (plen >= 1 && path[plen - 1] != '/') {
- tmp = malloc(plen + 2);
- memcpy(tmp, path, plen);
- tmp[plen] = '/';
- tmp[plen + 1] = '\0';
- path = tmp;
- }
- FILE *f = fopen(path, "a"); /* sets errno */
- if (f) fclose(f);
- free(tmp);
- return f == NULL ? -1 : 0;
-}
diff --git a/src/user/lib/syswait.c b/src/user/lib/syswait.c
deleted file mode 100644
index ce80c7b..0000000
--- a/src/user/lib/syswait.c
+++ /dev/null
@@ -1,22 +0,0 @@
-#include <bits/panic.h>
-#include <camellia.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <sys/resource.h>
-#include <sys/wait.h>
-
-pid_t wait3(int *wstatus, int opts, struct rusage *rusage) {
- struct sys_wait2 res;
- if (opts || rusage) {
- __libc_panic("unimplemented");
- }
- pid_t ret = _sys_wait2(-1, 0, &res);
- if (ret < 0) {
- errno = -ret;
- return -1;
- }
- if (wstatus) {
- *wstatus = res.status & 0xFF;
- }
- return ret;
-}
diff --git a/src/user/lib/thread.S b/src/user/lib/thread.S
deleted file mode 100644
index 2900544..0000000
--- a/src/user/lib/thread.S
+++ /dev/null
@@ -1,40 +0,0 @@
-#define ASM_FILE 1
-#include <camellia/syscalls.h>
-#include <camellia/flags.h>
-
-.section .text
-.global thread_creates
-.type thread_creates, @function
-// void thread_creates(int flags, void (*fn)(void*), void *arg, void *stack);
-thread_creates:
- push %r12
- push %r13
- push %r14
-
- /* save fn, arg, stack */
- mov %rsi, %r12
- mov %rdx, %r13
- mov %rcx, %r14
-
- mov %rdi, %rsi
- or $(FORK_SHAREMEM | FORK_SHAREHANDLE), %rsi
- mov $_SYS_FORK, %rdi
- xor %rdx, %rdx
- syscall
-
- test %rax, %rax
- jz 1f
- /* in parent, return normally */
- pop %r14
- pop %r13
- pop %r12
- ret
-1: /* in child */
- mov %r14, %rsp
- mov %r13, %rdi
- call *%r12
-
- mov $_SYS_EXIT, %rdi
- xor %rsi, %rsi
- syscall
- hlt /* if all else fails... */
diff --git a/src/user/lib/time.c b/src/user/lib/time.c
deleted file mode 100644
index 4709ecd..0000000
--- a/src/user/lib/time.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <errno.h>
-#include <time.h>
-
-// TODO time
-time_t time(time_t *tloc) {
- time_t ret = 0;
- if (tloc) *tloc = ret;
- return ret;
-}
-
-clock_t clock(void) {
- return 0;
-}
-
-struct tm *gmtime(const time_t *timer) {
- (void)timer;
- errno = ENOSYS;
- return NULL;
-}
-
-struct tm *localtime(const time_t *timer) {
- (void)timer;
- errno = ENOSYS;
- return NULL;
-}
-
-time_t mktime(struct tm *timeptr) {
- (void)timeptr;
- return 0;
-}
-
-double difftime(time_t time1, time_t time0) {
- (void)time1; (void)time0;
- return 0;
-}
-
-size_t strftime(
- char *restrict s, size_t maxsize,
- const char *restrict format, const struct tm *restrict timeptr)
-{
- (void)s; (void)maxsize; (void)format; (void)timeptr;
- return 0;
-}
diff --git a/src/user/lib/unistd.c b/src/user/lib/unistd.c
deleted file mode 100644
index 578cadc..0000000
--- a/src/user/lib/unistd.c
+++ /dev/null
@@ -1,267 +0,0 @@
-#include <bits/panic.h>
-#include <camellia.h>
-#include <camellia/path.h>
-#include <camellia/syscalls.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <elfload.h>
-
-int errno = 0;
-static char *_environ[] = {NULL};
-char **environ = _environ;
-
-int fork(void) {
- return _sys_fork(0, NULL);
-}
-
-pid_t vfork(void) {
- // TODO vfork is implemented improperly and will break stuff
- return _sys_fork(0, NULL);
-}
-
-int close(hid_t h) {
- return _sys_close(h);
-}
-
-_Noreturn void exit(int c) {
- _sys_exit(c);
-}
-_Noreturn void _exit(int c) { exit(c); };
-
-ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize) {
- (void)path; (void)buf; (void)bufsize;
- errno = ENOSYS;
- return -1;
-}
-
-int link(const char *path1, const char *path2) {
- (void)path1; (void)path2;
- errno = ENOSYS;
- return -1;
-}
-
-int unlink(const char *path) {
- hid_t h = camellia_open(path, OPEN_WRITE);
- if (h < 0) return errno = -h, -1;
- long ret = _sys_remove(h);
- if (ret < 0) return errno = -ret, -1;
- return 0;
-}
-
-int symlink(const char *path1, const char *path2) {
- (void)path1; (void)path2;
- errno = ENOSYS;
- return -1;
-}
-
-// TODO isatty
-int isatty(int fd) {
- return fd <= 2 ? 1 : 0;
-}
-
-
-int execv(const char *path, char *const argv[]) {
- return execve(path, argv, NULL);
-}
-
-int execve(const char *path, char *const argv[], char *const envp[]) {
- FILE *file = fopen(path, "e");
- char hdr[4] = {0};
- if (!file)
- return -1;
-
- fread(hdr, 1, 4, file);
- fseek(file, 0, SEEK_SET);
-
- if (!memcmp("\x7f""ELF", hdr, 4)) {
- elf_execf(file, (void*)argv, (void*)envp);
- fclose(file);
- } else if (!memcmp("#!", hdr, 2)) {
- char buf[256];
- fseek(file, 2, SEEK_SET);
- if (fgets(buf, sizeof buf, file)) {
- const char *argv [] = {buf, path, NULL};
- char *endl = strchr(buf, '\n');
- if (endl) *endl = '\0';
- execve(buf, (void*)argv, envp);
- }
- }
-
- errno = EINVAL;
- return -1;
-}
-
-
-static const char *__initialcwd;
-static char *cwd = NULL, *cwd2 = NULL;
-static size_t cwdcapacity = 0;
-
-static const char *getrealcwd(void) {
- /* __initialcwd can't just be initialized with "/" because ld has seemingly
- * started to revolt against humanity and not process half the relocations
- * it sees. */
- if (cwd) return cwd;
- if (__initialcwd) return __initialcwd;
- return "/";
-}
-
-int chdir(const char *path) {
- hid_t h;
- char *tmp;
- size_t len = absolutepath(NULL, path, 0) + 1; /* +1 for the trailing slash */
- if (cwdcapacity < len) {
- cwdcapacity = len;
- if (cwd) {
- cwd = realloc(cwd, len);
- cwd2 = realloc(cwd2, len);
- } else {
- size_t initlen = strlen(__initialcwd) + 1;
- if (len < initlen)
- len = initlen;
- cwd = malloc(initlen);
- cwd2 = malloc(initlen);
- memcpy(cwd, __initialcwd, initlen);
- }
- }
- absolutepath(cwd2, path, cwdcapacity);
- len = strlen(cwd2);
- if (cwd2[len - 1] != '/') {
- cwd2[len] = '/';
- cwd2[len + 1] = '\0';
- }
-
- /* check if exists */
- h = camellia_open(cwd2, OPEN_READ);
- if (h < 0) return errno = ENOENT, -1;
- close(h);
-
- tmp = cwd;
- cwd = cwd2;
- cwd2 = tmp;
- return 0;
-}
-
-char *getcwd(char *buf, size_t capacity) {
- const char *realcwd = getrealcwd();
- size_t len = strlen(realcwd) + 1;
- if (capacity < len) {
- errno = capacity == 0 ? EINVAL : ERANGE;
- return NULL;
- }
- memcpy(buf, realcwd, len);
- return buf;
-}
-
-uid_t getuid(void) { return 0; }
-uid_t geteuid(void) { return 0; }
-gid_t getgid(void) { return 0; }
-gid_t getegid(void) { return 0; }
-
-int chown(const char *path, uid_t owner, gid_t group) {
- (void)path; (void)owner; (void)group;
- errno = ENOSYS;
- return -1;
-}
-
-int setpgid(pid_t pid, pid_t pgid) {
- (void)pid; (void)pgid;
- return errno = ENOSYS, -1;
-}
-
-pid_t tcgetpgrp(int fd) {
- (void)fd;
- return errno = ENOSYS, -1;
-}
-
-int tcsetpgrp(int fd, pid_t pgrp) {
- (void)fd; (void)pgrp;
- return errno = ENOSYS, -1;
-}
-
-pid_t getpgrp(void) {
- __libc_panic("unimplemented");
-}
-
-pid_t getpid(void) {
- return _sys_getpid();
-}
-
-pid_t getppid(void) {
- return _sys_getppid();
-}
-
-int getgroups(int size, gid_t list[]) {
- (void)size; (void)list;
- __libc_panic("unimplemented");
-}
-
-ssize_t read(int fd, void *buf, size_t count) {
- // TODO real file descriptor emulation - store offsets
- return _sys_read(fd, buf, count, -1);
-}
-
-ssize_t write(int fd, const void *buf, size_t count) {
- // TODO real file descriptor emulation - store offsets
- return _sys_write(fd, buf, count, -1, 0);
-}
-
-int pipe(int pipefd[2]) {
- (void)pipefd;
- __libc_panic("unimplemented");
-}
-
-int dup2(int oldfd, int newfd) {
- (void)oldfd; (void)newfd;
- __libc_panic("unimplemented");
-}
-
-size_t absolutepath(char *out, const char *in, size_t size) {
- const char *realcwd = getrealcwd();
- size_t len, pos = 0;
- if (!in) return strlen(realcwd) + 1;
-
- if (!(in[0] == '/')) {
- len = strlen(realcwd);
- if (pos + len <= size && out != realcwd)
- memcpy(out + pos, realcwd, len);
- pos += len;
-
- if (realcwd[len - 1] != '/') {
- if (pos + 1 <= size) out[pos] = '/';
- pos++;
- }
- }
-
- len = strlen(in);
- if (pos + len <= size)
- memcpy(out + pos, in, len);
- pos += len;
-
- if (pos <= size) {
- pos = path_simplify(out, out, pos);
- if (pos == 0) return 0;
- }
-
- if (pos + 1 <= size) out[pos] = '\0';
- pos++;
-
- return pos;
-}
-
-void __setinitialcwd(const char *s) {
- __initialcwd = s;
-}
-
-static void intr_null(void) { }
-
-extern void (*volatile _intr)(void);
-void intr_set(void (*fn)(void)) {
- _intr = fn ? fn : intr_null;
-}
-
-void intr_default(void) {
- exit(-1);
-}
diff --git a/src/user/lib/vendor/dlmalloc/malloc.c b/src/user/lib/vendor/dlmalloc/malloc.c
deleted file mode 100644
index 649cfbc..0000000
--- a/src/user/lib/vendor/dlmalloc/malloc.c
+++ /dev/null
@@ -1,6280 +0,0 @@
-/*
- This is a version (aka dlmalloc) of malloc/free/realloc written by
- Doug Lea and released to the public domain, as explained at
- http://creativecommons.org/publicdomain/zero/1.0/ Send questions,
- comments, complaints, performance data, etc to [email protected]
-
-* Version 2.8.6 Wed Aug 29 06:57:58 2012 Doug Lea
- Note: There may be an updated version of this malloc obtainable at
- ftp://gee.cs.oswego.edu/pub/misc/malloc.c
- Check before installing!
-
-* Quickstart
-
- This library is all in one file to simplify the most common usage:
- ftp it, compile it (-O3), and link it into another program. All of
- the compile-time options default to reasonable values for use on
- most platforms. You might later want to step through various
- compile-time and dynamic tuning options.
-
- For convenience, an include file for code using this malloc is at:
- ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.6.h
- You don't really need this .h file unless you call functions not
- defined in your system include files. The .h file contains only the
- excerpts from this file needed for using this malloc on ANSI C/C++
- systems, so long as you haven't changed compile-time options about
- naming and tuning parameters. If you do, then you can create your
- own malloc.h that does include all settings by cutting at the point
- indicated below. Note that you may already by default be using a C
- library containing a malloc that is based on some version of this
- malloc (for example in linux). You might still want to use the one
- in this file to customize settings or to avoid overheads associated
- with library versions.
-
-* Vital statistics:
-
- Supported pointer/size_t representation: 4 or 8 bytes
- size_t MUST be an unsigned type of the same width as
- pointers. (If you are using an ancient system that declares
- size_t as a signed type, or need it to be a different width
- than pointers, you can use a previous release of this malloc
- (e.g. 2.7.2) supporting these.)
-
- Alignment: 8 bytes (minimum)
- This suffices for nearly all current machines and C compilers.
- However, you can define MALLOC_ALIGNMENT to be wider than this
- if necessary (up to 128bytes), at the expense of using more space.
-
- Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes)
- 8 or 16 bytes (if 8byte sizes)
- Each malloced chunk has a hidden word of overhead holding size
- and status information, and additional cross-check word
- if FOOTERS is defined.
-
- Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead)
- 8-byte ptrs: 32 bytes (including overhead)
-
- Even a request for zero bytes (i.e., malloc(0)) returns a
- pointer to something of the minimum allocatable size.
- The maximum overhead wastage (i.e., number of extra bytes
- allocated than were requested in malloc) is less than or equal
- to the minimum size, except for requests >= mmap_threshold that
- are serviced via mmap(), where the worst case wastage is about
- 32 bytes plus the remainder from a system page (the minimal
- mmap unit); typically 4096 or 8192 bytes.
-
- Security: static-safe; optionally more or less
- The "security" of malloc refers to the ability of malicious
- code to accentuate the effects of errors (for example, freeing
- space that is not currently malloc'ed or overwriting past the
- ends of chunks) in code that calls malloc. This malloc
- guarantees not to modify any memory locations below the base of
- heap, i.e., static variables, even in the presence of usage
- errors. The routines additionally detect most improper frees
- and reallocs. All this holds as long as the static bookkeeping
- for malloc itself is not corrupted by some other means. This
- is only one aspect of security -- these checks do not, and
- cannot, detect all possible programming errors.
-
- If FOOTERS is defined nonzero, then each allocated chunk
- carries an additional check word to verify that it was malloced
- from its space. These check words are the same within each
- execution of a program using malloc, but differ across
- executions, so externally crafted fake chunks cannot be
- freed. This improves security by rejecting frees/reallocs that
- could corrupt heap memory, in addition to the checks preventing
- writes to statics that are always on. This may further improve
- security at the expense of time and space overhead. (Note that
- FOOTERS may also be worth using with MSPACES.)
-
- By default detected errors cause the program to abort (calling
- "abort()"). You can override this to instead proceed past
- errors by defining PROCEED_ON_ERROR. In this case, a bad free
- has no effect, and a malloc that encounters a bad address
- caused by user overwrites will ignore the bad address by
- dropping pointers and indices to all known memory. This may
- be appropriate for programs that should continue if at all
- possible in the face of programming errors, although they may
- run out of memory because dropped memory is never reclaimed.
-
- If you don't like either of these options, you can define
- CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything
- else. And if if you are sure that your program using malloc has
- no errors or vulnerabilities, you can define INSECURE to 1,
- which might (or might not) provide a small performance improvement.
-
- It is also possible to limit the maximum total allocatable
- space, using malloc_set_footprint_limit. This is not
- designed as a security feature in itself (calls to set limits
- are not screened or privileged), but may be useful as one
- aspect of a secure implementation.
-
- Thread-safety: NOT thread-safe unless USE_LOCKS defined non-zero
- When USE_LOCKS is defined, each public call to malloc, free,
- etc is surrounded with a lock. By default, this uses a plain
- pthread mutex, win32 critical section, or a spin-lock if if
- available for the platform and not disabled by setting
- USE_SPIN_LOCKS=0. However, if USE_RECURSIVE_LOCKS is defined,
- recursive versions are used instead (which are not required for
- base functionality but may be needed in layered extensions).
- Using a global lock is not especially fast, and can be a major
- bottleneck. It is designed only to provide minimal protection
- in concurrent environments, and to provide a basis for
- extensions. If you are using malloc in a concurrent program,
- consider instead using nedmalloc
- (http://www.nedprod.com/programs/portable/nedmalloc/) or
- ptmalloc (See http://www.malloc.de), which are derived from
- versions of this malloc.
-
- System requirements: Any combination of MORECORE and/or MMAP/MUNMAP
- This malloc can use unix sbrk or any emulation (invoked using
- the CALL_MORECORE macro) and/or mmap/munmap or any emulation
- (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system
- memory. On most unix systems, it tends to work best if both
- MORECORE and MMAP are enabled. On Win32, it uses emulations
- based on VirtualAlloc. It also uses common C library functions
- like memset.
-
- Compliance: I believe it is compliant with the Single Unix Specification
- (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably
- others as well.
-
-* Overview of algorithms
-
- This is not the fastest, most space-conserving, most portable, or
- most tunable malloc ever written. However it is among the fastest
- while also being among the most space-conserving, portable and
- tunable. Consistent balance across these factors results in a good
- general-purpose allocator for malloc-intensive programs.
-
- In most ways, this malloc is a best-fit allocator. Generally, it
- chooses the best-fitting existing chunk for a request, with ties
- broken in approximately least-recently-used order. (This strategy
- normally maintains low fragmentation.) However, for requests less
- than 256bytes, it deviates from best-fit when there is not an
- exactly fitting available chunk by preferring to use space adjacent
- to that used for the previous small request, as well as by breaking
- ties in approximately most-recently-used order. (These enhance
- locality of series of small allocations.) And for very large requests
- (>= 256Kb by default), it relies on system memory mapping
- facilities, if supported. (This helps avoid carrying around and
- possibly fragmenting memory used only for large chunks.)
-
- All operations (except malloc_stats and mallinfo) have execution
- times that are bounded by a constant factor of the number of bits in
- a size_t, not counting any clearing in calloc or copying in realloc,
- or actions surrounding MORECORE and MMAP that have times
- proportional to the number of non-contiguous regions returned by
- system allocation routines, which is often just 1. In real-time
- applications, you can optionally suppress segment traversals using
- NO_SEGMENT_TRAVERSAL, which assures bounded execution even when
- system allocators return non-contiguous spaces, at the typical
- expense of carrying around more memory and increased fragmentation.
-
- The implementation is not very modular and seriously overuses
- macros. Perhaps someday all C compilers will do as good a job
- inlining modular code as can now be done by brute-force expansion,
- but now, enough of them seem not to.
-
- Some compilers issue a lot of warnings about code that is
- dead/unreachable only on some platforms, and also about intentional
- uses of negation on unsigned types. All known cases of each can be
- ignored.
-
- For a longer but out of date high-level description, see
- http://gee.cs.oswego.edu/dl/html/malloc.html
-
-* MSPACES
- If MSPACES is defined, then in addition to malloc, free, etc.,
- this file also defines mspace_malloc, mspace_free, etc. These
- are versions of malloc routines that take an "mspace" argument
- obtained using create_mspace, to control all internal bookkeeping.
- If ONLY_MSPACES is defined, only these versions are compiled.
- So if you would like to use this allocator for only some allocations,
- and your system malloc for others, you can compile with
- ONLY_MSPACES and then do something like...
- static mspace mymspace = create_mspace(0,0); // for example
- #define mymalloc(bytes) mspace_malloc(mymspace, bytes)
-
- (Note: If you only need one instance of an mspace, you can instead
- use "USE_DL_PREFIX" to relabel the global malloc.)
-
- You can similarly create thread-local allocators by storing
- mspaces as thread-locals. For example:
- static __thread mspace tlms = 0;
- void* tlmalloc(size_t bytes) {
- if (tlms == 0) tlms = create_mspace(0, 0);
- return mspace_malloc(tlms, bytes);
- }
- void tlfree(void* mem) { mspace_free(tlms, mem); }
-
- Unless FOOTERS is defined, each mspace is completely independent.
- You cannot allocate from one and free to another (although
- conformance is only weakly checked, so usage errors are not always
- caught). If FOOTERS is defined, then each chunk carries around a tag
- indicating its originating mspace, and frees are directed to their
- originating spaces. Normally, this requires use of locks.
-
- ------------------------- Compile-time options ---------------------------
-
-Be careful in setting #define values for numerical constants of type
-size_t. On some systems, literal values are not automatically extended
-to size_t precision unless they are explicitly casted. You can also
-use the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below.
-
-WIN32 default: defined if _WIN32 defined
- Defining WIN32 sets up defaults for MS environment and compilers.
- Otherwise defaults are for unix. Beware that there seem to be some
- cases where this malloc might not be a pure drop-in replacement for
- Win32 malloc: Random-looking failures from Win32 GDI API's (eg;
- SetDIBits()) may be due to bugs in some video driver implementations
- when pixel buffers are malloc()ed, and the region spans more than
- one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb)
- default granularity, pixel buffers may straddle virtual allocation
- regions more often than when using the Microsoft allocator. You can
- avoid this by using VirtualAlloc() and VirtualFree() for all pixel
- buffers rather than using malloc(). If this is not possible,
- recompile this malloc with a larger DEFAULT_GRANULARITY. Note:
- in cases where MSC and gcc (cygwin) are known to differ on WIN32,
- conditions use _MSC_VER to distinguish them.
-
-DLMALLOC_EXPORT default: extern
- Defines how public APIs are declared. If you want to export via a
- Windows DLL, you might define this as
- #define DLMALLOC_EXPORT extern __declspec(dllexport)
- If you want a POSIX ELF shared object, you might use
- #define DLMALLOC_EXPORT extern __attribute__((visibility("default")))
-
-MALLOC_ALIGNMENT default: (size_t)(2 * sizeof(void *))
- Controls the minimum alignment for malloc'ed chunks. It must be a
- power of two and at least 8, even on machines for which smaller
- alignments would suffice. It may be defined as larger than this
- though. Note however that code and data structures are optimized for
- the case of 8-byte alignment.
-
-MSPACES default: 0 (false)
- If true, compile in support for independent allocation spaces.
- This is only supported if HAVE_MMAP is true.
-
-ONLY_MSPACES default: 0 (false)
- If true, only compile in mspace versions, not regular versions.
-
-USE_LOCKS default: 0 (false)
- Causes each call to each public routine to be surrounded with
- pthread or WIN32 mutex lock/unlock. (If set true, this can be
- overridden on a per-mspace basis for mspace versions.) If set to a
- non-zero value other than 1, locks are used, but their
- implementation is left out, so lock functions must be supplied manually,
- as described below.
-
-USE_SPIN_LOCKS default: 1 iff USE_LOCKS and spin locks available
- If true, uses custom spin locks for locking. This is currently
- supported only gcc >= 4.1, older gccs on x86 platforms, and recent
- MS compilers. Otherwise, posix locks or win32 critical sections are
- used.
-
-USE_RECURSIVE_LOCKS default: not defined
- If defined nonzero, uses recursive (aka reentrant) locks, otherwise
- uses plain mutexes. This is not required for malloc proper, but may
- be needed for layered allocators such as nedmalloc.
-
-LOCK_AT_FORK default: not defined
- If defined nonzero, performs pthread_atfork upon initialization
- to initialize child lock while holding parent lock. The implementation
- assumes that pthread locks (not custom locks) are being used. In other
- cases, you may need to customize the implementation.
-
-FOOTERS default: 0
- If true, provide extra checking and dispatching by placing
- information in the footers of allocated chunks. This adds
- space and time overhead.
-
-INSECURE default: 0
- If true, omit checks for usage errors and heap space overwrites.
-
-USE_DL_PREFIX default: NOT defined
- Causes compiler to prefix all public routines with the string 'dl'.
- This can be useful when you only want to use this malloc in one part
- of a program, using your regular system malloc elsewhere.
-
-MALLOC_INSPECT_ALL default: NOT defined
- If defined, compiles malloc_inspect_all and mspace_inspect_all, that
- perform traversal of all heap space. Unless access to these
- functions is otherwise restricted, you probably do not want to
- include them in secure implementations.
-
-ABORT default: defined as abort()
- Defines how to abort on failed checks. On most systems, a failed
- check cannot die with an "assert" or even print an informative
- message, because the underlying print routines in turn call malloc,
- which will fail again. Generally, the best policy is to simply call
- abort(). It's not very useful to do more than this because many
- errors due to overwriting will show up as address faults (null, odd
- addresses etc) rather than malloc-triggered checks, so will also
- abort. Also, most compilers know that abort() does not return, so
- can better optimize code conditionally calling it.
-
-PROCEED_ON_ERROR default: defined as 0 (false)
- Controls whether detected bad addresses cause them to bypassed
- rather than aborting. If set, detected bad arguments to free and
- realloc are ignored. And all bookkeeping information is zeroed out
- upon a detected overwrite of freed heap space, thus losing the
- ability to ever return it from malloc again, but enabling the
- application to proceed. If PROCEED_ON_ERROR is defined, the
- static variable malloc_corruption_error_count is compiled in
- and can be examined to see if errors have occurred. This option
- generates slower code than the default abort policy.
-
-DEBUG default: NOT defined
- The DEBUG setting is mainly intended for people trying to modify
- this code or diagnose problems when porting to new platforms.
- However, it may also be able to better isolate user errors than just
- using runtime checks. The assertions in the check routines spell
- out in more detail the assumptions and invariants underlying the
- algorithms. The checking is fairly extensive, and will slow down
- execution noticeably. Calling malloc_stats or mallinfo with DEBUG
- set will attempt to check every non-mmapped allocated and free chunk
- in the course of computing the summaries.
-
-ABORT_ON_ASSERT_FAILURE default: defined as 1 (true)
- Debugging assertion failures can be nearly impossible if your
- version of the assert macro causes malloc to be called, which will
- lead to a cascade of further failures, blowing the runtime stack.
- ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(),
- which will usually make debugging easier.
-
-MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32
- The action to take before "return 0" when malloc fails to be able to
- return memory because there is none available.
-
-HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES
- True if this system supports sbrk or an emulation of it.
-
-MORECORE default: sbrk
- The name of the sbrk-style system routine to call to obtain more
- memory. See below for guidance on writing custom MORECORE
- functions. The type of the argument to sbrk/MORECORE varies across
- systems. It cannot be size_t, because it supports negative
- arguments, so it is normally the signed type of the same width as
- size_t (sometimes declared as "intptr_t"). It doesn't much matter
- though. Internally, we only call it with arguments less than half
- the max value of a size_t, which should work across all reasonable
- possibilities, although sometimes generating compiler warnings.
-
-MORECORE_CONTIGUOUS default: 1 (true) if HAVE_MORECORE
- If true, take advantage of fact that consecutive calls to MORECORE
- with positive arguments always return contiguous increasing
- addresses. This is true of unix sbrk. It does not hurt too much to
- set it true anyway, since malloc copes with non-contiguities.
- Setting it false when definitely non-contiguous saves time
- and possibly wasted space it would take to discover this though.
-
-MORECORE_CANNOT_TRIM default: NOT defined
- True if MORECORE cannot release space back to the system when given
- negative arguments. This is generally necessary only if you are
- using a hand-crafted MORECORE function that cannot handle negative
- arguments.
-
-NO_SEGMENT_TRAVERSAL default: 0
- If non-zero, suppresses traversals of memory segments
- returned by either MORECORE or CALL_MMAP. This disables
- merging of segments that are contiguous, and selectively
- releasing them to the OS if unused, but bounds execution times.
-
-HAVE_MMAP default: 1 (true)
- True if this system supports mmap or an emulation of it. If so, and
- HAVE_MORECORE is not true, MMAP is used for all system
- allocation. If set and HAVE_MORECORE is true as well, MMAP is
- primarily used to directly allocate very large blocks. It is also
- used as a backup strategy in cases where MORECORE fails to provide
- space from system. Note: A single call to MUNMAP is assumed to be
- able to unmap memory that may have be allocated using multiple calls
- to MMAP, so long as they are adjacent.
-
-HAVE_MREMAP default: 1 on linux, else 0
- If true realloc() uses mremap() to re-allocate large blocks and
- extend or shrink allocation spaces.
-
-MMAP_CLEARS default: 1 except on WINCE.
- True if mmap clears memory so calloc doesn't need to. This is true
- for standard unix mmap using /dev/zero and on WIN32 except for WINCE.
-
-USE_BUILTIN_FFS default: 0 (i.e., not used)
- Causes malloc to use the builtin ffs() function to compute indices.
- Some compilers may recognize and intrinsify ffs to be faster than the
- supplied C version. Also, the case of x86 using gcc is special-cased
- to an asm instruction, so is already as fast as it can be, and so
- this setting has no effect. Similarly for Win32 under recent MS compilers.
- (On most x86s, the asm version is only slightly faster than the C version.)
-
-malloc_getpagesize default: derive from system includes, or 4096.
- The system page size. To the extent possible, this malloc manages
- memory from the system in page-size units. This may be (and
- usually is) a function rather than a constant. This is ignored
- if WIN32, where page size is determined using getSystemInfo during
- initialization.
-
-USE_DEV_RANDOM default: 0 (i.e., not used)
- Causes malloc to use /dev/random to initialize secure magic seed for
- stamping footers. Otherwise, the current time is used.
-
-NO_MALLINFO default: 0
- If defined, don't compile "mallinfo". This can be a simple way
- of dealing with mismatches between system declarations and
- those in this file.
-
-MALLINFO_FIELD_TYPE default: size_t
- The type of the fields in the mallinfo struct. This was originally
- defined as "int" in SVID etc, but is more usefully defined as
- size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set
-
-NO_MALLOC_STATS default: 0
- If defined, don't compile "malloc_stats". This avoids calls to
- fprintf and bringing in stdio dependencies you might not want.
-
-REALLOC_ZERO_BYTES_FREES default: not defined
- This should be set if a call to realloc with zero bytes should
- be the same as a call to free. Some people think it should. Otherwise,
- since this malloc returns a unique pointer for malloc(0), so does
- realloc(p, 0).
-
-LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H
-LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H
-LACKS_STDLIB_H LACKS_SCHED_H LACKS_TIME_H default: NOT defined unless on WIN32
- Define these if your system does not have these header files.
- You might need to manually insert some of the declarations they provide.
-
-DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS,
- system_info.dwAllocationGranularity in WIN32,
- otherwise 64K.
- Also settable using mallopt(M_GRANULARITY, x)
- The unit for allocating and deallocating memory from the system. On
- most systems with contiguous MORECORE, there is no reason to
- make this more than a page. However, systems with MMAP tend to
- either require or encourage larger granularities. You can increase
- this value to prevent system allocation functions to be called so
- often, especially if they are slow. The value must be at least one
- page and must be a power of two. Setting to 0 causes initialization
- to either page size or win32 region size. (Note: In previous
- versions of malloc, the equivalent of this option was called
- "TOP_PAD")
-
-DEFAULT_TRIM_THRESHOLD default: 2MB
- Also settable using mallopt(M_TRIM_THRESHOLD, x)
- The maximum amount of unused top-most memory to keep before
- releasing via malloc_trim in free(). Automatic trimming is mainly
- useful in long-lived programs using contiguous MORECORE. Because
- trimming via sbrk can be slow on some systems, and can sometimes be
- wasteful (in cases where programs immediately afterward allocate
- more large chunks) the value should be high enough so that your
- overall system performance would improve by releasing this much
- memory. As a rough guide, you might set to a value close to the
- average size of a process (program) running on your system.
- Releasing this much memory would allow such a process to run in
- memory. Generally, it is worth tuning trim thresholds when a
- program undergoes phases where several large chunks are allocated
- and released in ways that can reuse each other's storage, perhaps
- mixed with phases where there are no such chunks at all. The trim
- value must be greater than page size to have any useful effect. To
- disable trimming completely, you can set to MAX_SIZE_T. Note that the trick
- some people use of mallocing a huge space and then freeing it at
- program startup, in an attempt to reserve system memory, doesn't
- have the intended effect under automatic trimming, since that memory
- will immediately be returned to the system.
-
-DEFAULT_MMAP_THRESHOLD default: 256K
- Also settable using mallopt(M_MMAP_THRESHOLD, x)
- The request size threshold for using MMAP to directly service a
- request. Requests of at least this size that cannot be allocated
- using already-existing space will be serviced via mmap. (If enough
- normal freed space already exists it is used instead.) Using mmap
- segregates relatively large chunks of memory so that they can be
- individually obtained and released from the host system. A request
- serviced through mmap is never reused by any other request (at least
- not directly; the system may just so happen to remap successive
- requests to the same locations). Segregating space in this way has
- the benefits that: Mmapped space can always be individually released
- back to the system, which helps keep the system level memory demands
- of a long-lived program low. Also, mapped memory doesn't become
- `locked' between other chunks, as can happen with normally allocated
- chunks, which means that even trimming via malloc_trim would not
- release them. However, it has the disadvantage that the space
- cannot be reclaimed, consolidated, and then used to service later
- requests, as happens with normal chunks. The advantages of mmap
- nearly always outweigh disadvantages for "large" chunks, but the
- value of "large" may vary across systems. The default is an
- empirically derived value that works well in most systems. You can
- disable mmap by setting to MAX_SIZE_T.
-
-MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP
- The number of consolidated frees between checks to release
- unused segments when freeing. When using non-contiguous segments,
- especially with multiple mspaces, checking only for topmost space
- doesn't always suffice to trigger trimming. To compensate for this,
- free() will, with a period of MAX_RELEASE_CHECK_RATE (or the
- current number of segments, if greater) try to release unused
- segments to the OS when freeing chunks that result in
- consolidation. The best value for this parameter is a compromise
- between slowing down frees with relatively costly checks that
- rarely trigger versus holding on to unused memory. To effectively
- disable, set to MAX_SIZE_T. This may lead to a very slight speed
- improvement at the expense of carrying around more memory.
-*/
-
-/* Version identifier to allow people to support multiple versions */
-#ifndef DLMALLOC_VERSION
-#define DLMALLOC_VERSION 20806
-#endif /* DLMALLOC_VERSION */
-
-#ifndef DLMALLOC_EXPORT
-#define DLMALLOC_EXPORT extern
-#endif
-
-#ifndef WIN32
-#ifdef _WIN32
-#define WIN32 1
-#endif /* _WIN32 */
-#ifdef _WIN32_WCE
-#define LACKS_FCNTL_H
-#define WIN32 1
-#endif /* _WIN32_WCE */
-#endif /* WIN32 */
-#ifdef WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <tchar.h>
-#define HAVE_MMAP 1
-#define HAVE_MORECORE 0
-#define LACKS_UNISTD_H
-#define LACKS_SYS_PARAM_H
-#define LACKS_SYS_MMAN_H
-#define LACKS_STRING_H
-#define LACKS_STRINGS_H
-#define LACKS_SYS_TYPES_H
-#define LACKS_ERRNO_H
-#define LACKS_SCHED_H
-#ifndef MALLOC_FAILURE_ACTION
-#define MALLOC_FAILURE_ACTION
-#endif /* MALLOC_FAILURE_ACTION */
-#ifndef MMAP_CLEARS
-#ifdef _WIN32_WCE /* WINCE reportedly does not clear */
-#define MMAP_CLEARS 0
-#else
-#define MMAP_CLEARS 1
-#endif /* _WIN32_WCE */
-#endif /*MMAP_CLEARS */
-#endif /* WIN32 */
-
-#if defined(DARWIN) || defined(_DARWIN)
-/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */
-#ifndef HAVE_MORECORE
-#define HAVE_MORECORE 0
-#define HAVE_MMAP 1
-/* OSX allocators provide 16 byte alignment */
-#ifndef MALLOC_ALIGNMENT
-#define MALLOC_ALIGNMENT ((size_t)16U)
-#endif
-#endif /* HAVE_MORECORE */
-#endif /* DARWIN */
-
-#ifndef LACKS_SYS_TYPES_H
-#include <sys/types.h> /* For size_t */
-#endif /* LACKS_SYS_TYPES_H */
-
-/* The maximum possible size_t value has all bits set */
-#define MAX_SIZE_T (~(size_t)0)
-
-#ifndef USE_LOCKS /* ensure true if spin or recursive locks set */
-#define USE_LOCKS ((defined(USE_SPIN_LOCKS) && USE_SPIN_LOCKS != 0) || \
- (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0))
-#endif /* USE_LOCKS */
-
-#if USE_LOCKS /* Spin locks for gcc >= 4.1, older gcc on x86, MSC >= 1310 */
-#if ((defined(__GNUC__) && \
- ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) || \
- defined(__i386__) || defined(__x86_64__))) || \
- (defined(_MSC_VER) && _MSC_VER>=1310))
-#ifndef USE_SPIN_LOCKS
-#define USE_SPIN_LOCKS 1
-#endif /* USE_SPIN_LOCKS */
-#elif USE_SPIN_LOCKS
-#error "USE_SPIN_LOCKS defined without implementation"
-#endif /* ... locks available... */
-#elif !defined(USE_SPIN_LOCKS)
-#define USE_SPIN_LOCKS 0
-#endif /* USE_LOCKS */
-
-#ifndef ONLY_MSPACES
-#define ONLY_MSPACES 0
-#endif /* ONLY_MSPACES */
-#ifndef MSPACES
-#if ONLY_MSPACES
-#define MSPACES 1
-#else /* ONLY_MSPACES */
-#define MSPACES 0
-#endif /* ONLY_MSPACES */
-#endif /* MSPACES */
-#ifndef MALLOC_ALIGNMENT
-#define MALLOC_ALIGNMENT ((size_t)(2 * sizeof(void *)))
-#endif /* MALLOC_ALIGNMENT */
-#ifndef FOOTERS
-#define FOOTERS 0
-#endif /* FOOTERS */
-#ifndef ABORT
-#define ABORT abort()
-#endif /* ABORT */
-#ifndef ABORT_ON_ASSERT_FAILURE
-#define ABORT_ON_ASSERT_FAILURE 1
-#endif /* ABORT_ON_ASSERT_FAILURE */
-#ifndef PROCEED_ON_ERROR
-#define PROCEED_ON_ERROR 0
-#endif /* PROCEED_ON_ERROR */
-
-#ifndef INSECURE
-#define INSECURE 0
-#endif /* INSECURE */
-#ifndef MALLOC_INSPECT_ALL
-#define MALLOC_INSPECT_ALL 0
-#endif /* MALLOC_INSPECT_ALL */
-#ifndef HAVE_MMAP
-#define HAVE_MMAP 1
-#endif /* HAVE_MMAP */
-#ifndef MMAP_CLEARS
-#define MMAP_CLEARS 1
-#endif /* MMAP_CLEARS */
-#ifndef HAVE_MREMAP
-#ifdef linux
-#define HAVE_MREMAP 1
-#define _GNU_SOURCE /* Turns on mremap() definition */
-#else /* linux */
-#define HAVE_MREMAP 0
-#endif /* linux */
-#endif /* HAVE_MREMAP */
-#ifndef MALLOC_FAILURE_ACTION
-#define MALLOC_FAILURE_ACTION errno = ENOMEM;
-#endif /* MALLOC_FAILURE_ACTION */
-#ifndef HAVE_MORECORE
-#if ONLY_MSPACES
-#define HAVE_MORECORE 0
-#else /* ONLY_MSPACES */
-#define HAVE_MORECORE 1
-#endif /* ONLY_MSPACES */
-#endif /* HAVE_MORECORE */
-#if !HAVE_MORECORE
-#define MORECORE_CONTIGUOUS 0
-#else /* !HAVE_MORECORE */
-#define MORECORE_DEFAULT sbrk
-#ifndef MORECORE_CONTIGUOUS
-#define MORECORE_CONTIGUOUS 1
-#endif /* MORECORE_CONTIGUOUS */
-#endif /* HAVE_MORECORE */
-#ifndef DEFAULT_GRANULARITY
-#if (MORECORE_CONTIGUOUS || defined(WIN32))
-#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */
-#else /* MORECORE_CONTIGUOUS */
-#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U)
-#endif /* MORECORE_CONTIGUOUS */
-#endif /* DEFAULT_GRANULARITY */
-#ifndef DEFAULT_TRIM_THRESHOLD
-#ifndef MORECORE_CANNOT_TRIM
-#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U)
-#else /* MORECORE_CANNOT_TRIM */
-#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T
-#endif /* MORECORE_CANNOT_TRIM */
-#endif /* DEFAULT_TRIM_THRESHOLD */
-#ifndef DEFAULT_MMAP_THRESHOLD
-#if HAVE_MMAP
-#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U)
-#else /* HAVE_MMAP */
-#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
-#endif /* HAVE_MMAP */
-#endif /* DEFAULT_MMAP_THRESHOLD */
-#ifndef MAX_RELEASE_CHECK_RATE
-#if HAVE_MMAP
-#define MAX_RELEASE_CHECK_RATE 4095
-#else
-#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T
-#endif /* HAVE_MMAP */
-#endif /* MAX_RELEASE_CHECK_RATE */
-#ifndef USE_BUILTIN_FFS
-#define USE_BUILTIN_FFS 0
-#endif /* USE_BUILTIN_FFS */
-#ifndef USE_DEV_RANDOM
-#define USE_DEV_RANDOM 0
-#endif /* USE_DEV_RANDOM */
-#ifndef NO_MALLINFO
-#define NO_MALLINFO 0
-#endif /* NO_MALLINFO */
-#ifndef MALLINFO_FIELD_TYPE
-#define MALLINFO_FIELD_TYPE size_t
-#endif /* MALLINFO_FIELD_TYPE */
-#ifndef NO_MALLOC_STATS
-#define NO_MALLOC_STATS 0
-#endif /* NO_MALLOC_STATS */
-#ifndef NO_SEGMENT_TRAVERSAL
-#define NO_SEGMENT_TRAVERSAL 0
-#endif /* NO_SEGMENT_TRAVERSAL */
-
-/*
- mallopt tuning options. SVID/XPG defines four standard parameter
- numbers for mallopt, normally defined in malloc.h. None of these
- are used in this malloc, so setting them has no effect. But this
- malloc does support the following options.
-*/
-
-#define M_TRIM_THRESHOLD (-1)
-#define M_GRANULARITY (-2)
-#define M_MMAP_THRESHOLD (-3)
-
-/* ------------------------ Mallinfo declarations ------------------------ */
-
-#if !NO_MALLINFO
-/*
- This version of malloc supports the standard SVID/XPG mallinfo
- routine that returns a struct containing usage properties and
- statistics. It should work on any system that has a
- /usr/include/malloc.h defining struct mallinfo. The main
- declaration needed is the mallinfo struct that is returned (by-copy)
- by mallinfo(). The malloinfo struct contains a bunch of fields that
- are not even meaningful in this version of malloc. These fields are
- are instead filled by mallinfo() with other numbers that might be of
- interest.
-
- HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
- /usr/include/malloc.h file that includes a declaration of struct
- mallinfo. If so, it is included; else a compliant version is
- declared below. These must be precisely the same for mallinfo() to
- work. The original SVID version of this struct, defined on most
- systems with mallinfo, declares all fields as ints. But some others
- define as unsigned long. If your system defines the fields using a
- type of different width than listed here, you MUST #include your
- system version and #define HAVE_USR_INCLUDE_MALLOC_H.
-*/
-
-/* #define HAVE_USR_INCLUDE_MALLOC_H */
-
-#ifdef HAVE_USR_INCLUDE_MALLOC_H
-#include "/usr/include/malloc.h"
-#else /* HAVE_USR_INCLUDE_MALLOC_H */
-#ifndef STRUCT_MALLINFO_DECLARED
-/* HP-UX (and others?) redefines mallinfo unless _STRUCT_MALLINFO is defined */
-#define _STRUCT_MALLINFO
-#define STRUCT_MALLINFO_DECLARED 1
-struct mallinfo {
- MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */
- MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */
- MALLINFO_FIELD_TYPE smblks; /* always 0 */
- MALLINFO_FIELD_TYPE hblks; /* always 0 */
- MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */
- MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */
- MALLINFO_FIELD_TYPE fsmblks; /* always 0 */
- MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
- MALLINFO_FIELD_TYPE fordblks; /* total free space */
- MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
-};
-#endif /* STRUCT_MALLINFO_DECLARED */
-#endif /* HAVE_USR_INCLUDE_MALLOC_H */
-#endif /* NO_MALLINFO */
-
-/*
- Try to persuade compilers to inline. The most critical functions for
- inlining are defined as macros, so these aren't used for them.
-*/
-
-#ifndef FORCEINLINE
- #if defined(__GNUC__)
-#define FORCEINLINE __inline __attribute__ ((always_inline))
- #elif defined(_MSC_VER)
- #define FORCEINLINE __forceinline
- #endif
-#endif
-#ifndef NOINLINE
- #if defined(__GNUC__)
- #define NOINLINE __attribute__ ((noinline))
- #elif defined(_MSC_VER)
- #define NOINLINE __declspec(noinline)
- #else
- #define NOINLINE
- #endif
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#ifndef FORCEINLINE
- #define FORCEINLINE inline
-#endif
-#endif /* __cplusplus */
-#ifndef FORCEINLINE
- #define FORCEINLINE
-#endif
-
-#if !ONLY_MSPACES
-
-/* ------------------- Declarations of public routines ------------------- */
-
-#ifndef USE_DL_PREFIX
-#define dlcalloc calloc
-#define dlfree free
-#define dlmalloc malloc
-#define dlmemalign memalign
-#define dlposix_memalign posix_memalign
-#define dlrealloc realloc
-#define dlrealloc_in_place realloc_in_place
-#define dlvalloc valloc
-#define dlpvalloc pvalloc
-#define dlmallinfo mallinfo
-#define dlmallopt mallopt
-#define dlmalloc_trim malloc_trim
-#define dlmalloc_stats malloc_stats
-#define dlmalloc_usable_size malloc_usable_size
-#define dlmalloc_footprint malloc_footprint
-#define dlmalloc_max_footprint malloc_max_footprint
-#define dlmalloc_footprint_limit malloc_footprint_limit
-#define dlmalloc_set_footprint_limit malloc_set_footprint_limit
-#define dlmalloc_inspect_all malloc_inspect_all
-#define dlindependent_calloc independent_calloc
-#define dlindependent_comalloc independent_comalloc
-#define dlbulk_free bulk_free
-#endif /* USE_DL_PREFIX */
-
-/*
- malloc(size_t n)
- Returns a pointer to a newly allocated chunk of at least n bytes, or
- null if no space is available, in which case errno is set to ENOMEM
- on ANSI C systems.
-
- If n is zero, malloc returns a minimum-sized chunk. (The minimum
- size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
- systems.) Note that size_t is an unsigned type, so calls with
- arguments that would be negative if signed are interpreted as
- requests for huge amounts of space, which will often fail. The
- maximum supported value of n differs across systems, but is in all
- cases less than the maximum representable value of a size_t.
-*/
-DLMALLOC_EXPORT void* dlmalloc(size_t);
-
-/*
- free(void* p)
- Releases the chunk of memory pointed to by p, that had been previously
- allocated using malloc or a related routine such as realloc.
- It has no effect if p is null. If p was not malloced or already
- freed, free(p) will by default cause the current program to abort.
-*/
-DLMALLOC_EXPORT void dlfree(void*);
-
-/*
- calloc(size_t n_elements, size_t element_size);
- Returns a pointer to n_elements * element_size bytes, with all locations
- set to zero.
-*/
-DLMALLOC_EXPORT void* dlcalloc(size_t, size_t);
-
-/*
- realloc(void* p, size_t n)
- Returns a pointer to a chunk of size n that contains the same data
- as does chunk p up to the minimum of (n, p's size) bytes, or null
- if no space is available.
-
- The returned pointer may or may not be the same as p. The algorithm
- prefers extending p in most cases when possible, otherwise it
- employs the equivalent of a malloc-copy-free sequence.
-
- If p is null, realloc is equivalent to malloc.
-
- If space is not available, realloc returns null, errno is set (if on
- ANSI) and p is NOT freed.
-
- if n is for fewer bytes than already held by p, the newly unused
- space is lopped off and freed if possible. realloc with a size
- argument of zero (re)allocates a minimum-sized chunk.
-
- The old unix realloc convention of allowing the last-free'd chunk
- to be used as an argument to realloc is not supported.
-*/
-DLMALLOC_EXPORT void* dlrealloc(void*, size_t);
-
-/*
- realloc_in_place(void* p, size_t n)
- Resizes the space allocated for p to size n, only if this can be
- done without moving p (i.e., only if there is adjacent space
- available if n is greater than p's current allocated size, or n is
- less than or equal to p's size). This may be used instead of plain
- realloc if an alternative allocation strategy is needed upon failure
- to expand space; for example, reallocation of a buffer that must be
- memory-aligned or cleared. You can use realloc_in_place to trigger
- these alternatives only when needed.
-
- Returns p if successful; otherwise null.
-*/
-DLMALLOC_EXPORT void* dlrealloc_in_place(void*, size_t);
-
-/*
- memalign(size_t alignment, size_t n);
- Returns a pointer to a newly allocated chunk of n bytes, aligned
- in accord with the alignment argument.
-
- The alignment argument should be a power of two. If the argument is
- not a power of two, the nearest greater power is used.
- 8-byte alignment is guaranteed by normal malloc calls, so don't
- bother calling memalign with an argument of 8 or less.
-
- Overreliance on memalign is a sure way to fragment space.
-*/
-DLMALLOC_EXPORT void* dlmemalign(size_t, size_t);
-
-/*
- int posix_memalign(void** pp, size_t alignment, size_t n);
- Allocates a chunk of n bytes, aligned in accord with the alignment
- argument. Differs from memalign only in that it (1) assigns the
- allocated memory to *pp rather than returning it, (2) fails and
- returns EINVAL if the alignment is not a power of two (3) fails and
- returns ENOMEM if memory cannot be allocated.
-*/
-DLMALLOC_EXPORT int dlposix_memalign(void**, size_t, size_t);
-
-/*
- valloc(size_t n);
- Equivalent to memalign(pagesize, n), where pagesize is the page
- size of the system. If the pagesize is unknown, 4096 is used.
-*/
-DLMALLOC_EXPORT void* dlvalloc(size_t);
-
-/*
- mallopt(int parameter_number, int parameter_value)
- Sets tunable parameters The format is to provide a
- (parameter-number, parameter-value) pair. mallopt then sets the
- corresponding parameter to the argument value if it can (i.e., so
- long as the value is meaningful), and returns 1 if successful else
- 0. To workaround the fact that mallopt is specified to use int,
- not size_t parameters, the value -1 is specially treated as the
- maximum unsigned size_t value.
-
- SVID/XPG/ANSI defines four standard param numbers for mallopt,
- normally defined in malloc.h. None of these are use in this malloc,
- so setting them has no effect. But this malloc also supports other
- options in mallopt. See below for details. Briefly, supported
- parameters are as follows (listed defaults are for "typical"
- configurations).
-
- Symbol param # default allowed param values
- M_TRIM_THRESHOLD -1 2*1024*1024 any (-1 disables)
- M_GRANULARITY -2 page size any power of 2 >= page size
- M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support)
-*/
-DLMALLOC_EXPORT int dlmallopt(int, int);
-
-/*
- malloc_footprint();
- Returns the number of bytes obtained from the system. The total
- number of bytes allocated by malloc, realloc etc., is less than this
- value. Unlike mallinfo, this function returns only a precomputed
- result, so can be called frequently to monitor memory consumption.
- Even if locks are otherwise defined, this function does not use them,
- so results might not be up to date.
-*/
-DLMALLOC_EXPORT size_t dlmalloc_footprint(void);
-
-/*
- malloc_max_footprint();
- Returns the maximum number of bytes obtained from the system. This
- value will be greater than current footprint if deallocated space
- has been reclaimed by the system. The peak number of bytes allocated
- by malloc, realloc etc., is less than this value. Unlike mallinfo,
- this function returns only a precomputed result, so can be called
- frequently to monitor memory consumption. Even if locks are
- otherwise defined, this function does not use them, so results might
- not be up to date.
-*/
-DLMALLOC_EXPORT size_t dlmalloc_max_footprint(void);
-
-/*
- malloc_footprint_limit();
- Returns the number of bytes that the heap is allowed to obtain from
- the system, returning the last value returned by
- malloc_set_footprint_limit, or the maximum size_t value if
- never set. The returned value reflects a permission. There is no
- guarantee that this number of bytes can actually be obtained from
- the system.
-*/
-DLMALLOC_EXPORT size_t dlmalloc_footprint_limit();
-
-/*
- malloc_set_footprint_limit();
- Sets the maximum number of bytes to obtain from the system, causing
- failure returns from malloc and related functions upon attempts to
- exceed this value. The argument value may be subject to page
- rounding to an enforceable limit; this actual value is returned.
- Using an argument of the maximum possible size_t effectively
- disables checks. If the argument is less than or equal to the
- current malloc_footprint, then all future allocations that require
- additional system memory will fail. However, invocation cannot
- retroactively deallocate existing used memory.
-*/
-DLMALLOC_EXPORT size_t dlmalloc_set_footprint_limit(size_t bytes);
-
-#if MALLOC_INSPECT_ALL
-/*
- malloc_inspect_all(void(*handler)(void *start,
- void *end,
- size_t used_bytes,
- void* callback_arg),
- void* arg);
- Traverses the heap and calls the given handler for each managed
- region, skipping all bytes that are (or may be) used for bookkeeping
- purposes. Traversal does not include include chunks that have been
- directly memory mapped. Each reported region begins at the start
- address, and continues up to but not including the end address. The
- first used_bytes of the region contain allocated data. If
- used_bytes is zero, the region is unallocated. The handler is
- invoked with the given callback argument. If locks are defined, they
- are held during the entire traversal. It is a bad idea to invoke
- other malloc functions from within the handler.
-
- For example, to count the number of in-use chunks with size greater
- than 1000, you could write:
- static int count = 0;
- void count_chunks(void* start, void* end, size_t used, void* arg) {
- if (used >= 1000) ++count;
- }
- then:
- malloc_inspect_all(count_chunks, NULL);
-
- malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined.
-*/
-DLMALLOC_EXPORT void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),
- void* arg);
-
-#endif /* MALLOC_INSPECT_ALL */
-
-#if !NO_MALLINFO
-/*
- mallinfo()
- Returns (by copy) a struct containing various summary statistics:
-
- arena: current total non-mmapped bytes allocated from system
- ordblks: the number of free chunks
- smblks: always zero.
- hblks: current number of mmapped regions
- hblkhd: total bytes held in mmapped regions
- usmblks: the maximum total allocated space. This will be greater
- than current total if trimming has occurred.
- fsmblks: always zero
- uordblks: current total allocated space (normal or mmapped)
- fordblks: total free space
- keepcost: the maximum number of bytes that could ideally be released
- back to system via malloc_trim. ("ideally" means that
- it ignores page restrictions etc.)
-
- Because these fields are ints, but internal bookkeeping may
- be kept as longs, the reported values may wrap around zero and
- thus be inaccurate.
-*/
-DLMALLOC_EXPORT struct mallinfo dlmallinfo(void);
-#endif /* NO_MALLINFO */
-
-/*
- independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
-
- independent_calloc is similar to calloc, but instead of returning a
- single cleared space, it returns an array of pointers to n_elements
- independent elements that can hold contents of size elem_size, each
- of which starts out cleared, and can be independently freed,
- realloc'ed etc. The elements are guaranteed to be adjacently
- allocated (this is not guaranteed to occur with multiple callocs or
- mallocs), which may also improve cache locality in some
- applications.
-
- The "chunks" argument is optional (i.e., may be null, which is
- probably the most typical usage). If it is null, the returned array
- is itself dynamically allocated and should also be freed when it is
- no longer needed. Otherwise, the chunks array must be of at least
- n_elements in length. It is filled in with the pointers to the
- chunks.
-
- In either case, independent_calloc returns this pointer array, or
- null if the allocation failed. If n_elements is zero and "chunks"
- is null, it returns a chunk representing an array with zero elements
- (which should be freed if not wanted).
-
- Each element must be freed when it is no longer needed. This can be
- done all at once using bulk_free.
-
- independent_calloc simplifies and speeds up implementations of many
- kinds of pools. It may also be useful when constructing large data
- structures that initially have a fixed number of fixed-sized nodes,
- but the number is not known at compile time, and some of the nodes
- may later need to be freed. For example:
-
- struct Node { int item; struct Node* next; };
-
- struct Node* build_list() {
- struct Node** pool;
- int n = read_number_of_nodes_needed();
- if (n <= 0) return 0;
- pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
- if (pool == 0) die();
- // organize into a linked list...
- struct Node* first = pool[0];
- for (i = 0; i < n-1; ++i)
- pool[i]->next = pool[i+1];
- free(pool); // Can now free the array (or not, if it is needed later)
- return first;
- }
-*/
-DLMALLOC_EXPORT void** dlindependent_calloc(size_t, size_t, void**);
-
-/*
- independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
-
- independent_comalloc allocates, all at once, a set of n_elements
- chunks with sizes indicated in the "sizes" array. It returns
- an array of pointers to these elements, each of which can be
- independently freed, realloc'ed etc. The elements are guaranteed to
- be adjacently allocated (this is not guaranteed to occur with
- multiple callocs or mallocs), which may also improve cache locality
- in some applications.
-
- The "chunks" argument is optional (i.e., may be null). If it is null
- the returned array is itself dynamically allocated and should also
- be freed when it is no longer needed. Otherwise, the chunks array
- must be of at least n_elements in length. It is filled in with the
- pointers to the chunks.
-
- In either case, independent_comalloc returns this pointer array, or
- null if the allocation failed. If n_elements is zero and chunks is
- null, it returns a chunk representing an array with zero elements
- (which should be freed if not wanted).
-
- Each element must be freed when it is no longer needed. This can be
- done all at once using bulk_free.
-
- independent_comallac differs from independent_calloc in that each
- element may have a different size, and also that it does not
- automatically clear elements.
-
- independent_comalloc can be used to speed up allocation in cases
- where several structs or objects must always be allocated at the
- same time. For example:
-
- struct Head { ... }
- struct Foot { ... }
-
- void send_message(char* msg) {
- int msglen = strlen(msg);
- size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
- void* chunks[3];
- if (independent_comalloc(3, sizes, chunks) == 0)
- die();
- struct Head* head = (struct Head*)(chunks[0]);
- char* body = (char*)(chunks[1]);
- struct Foot* foot = (struct Foot*)(chunks[2]);
- // ...
- }
-
- In general though, independent_comalloc is worth using only for
- larger values of n_elements. For small values, you probably won't
- detect enough difference from series of malloc calls to bother.
-
- Overuse of independent_comalloc can increase overall memory usage,
- since it cannot reuse existing noncontiguous small chunks that
- might be available for some of the elements.
-*/
-DLMALLOC_EXPORT void** dlindependent_comalloc(size_t, size_t*, void**);
-
-/*
- bulk_free(void* array[], size_t n_elements)
- Frees and clears (sets to null) each non-null pointer in the given
- array. This is likely to be faster than freeing them one-by-one.
- If footers are used, pointers that have been allocated in different
- mspaces are not freed or cleared, and the count of all such pointers
- is returned. For large arrays of pointers with poor locality, it
- may be worthwhile to sort this array before calling bulk_free.
-*/
-DLMALLOC_EXPORT size_t dlbulk_free(void**, size_t n_elements);
-
-/*
- pvalloc(size_t n);
- Equivalent to valloc(minimum-page-that-holds(n)), that is,
- round up n to nearest pagesize.
- */
-DLMALLOC_EXPORT void* dlpvalloc(size_t);
-
-/*
- malloc_trim(size_t pad);
-
- If possible, gives memory back to the system (via negative arguments
- to sbrk) if there is unused memory at the `high' end of the malloc
- pool or in unused MMAP segments. You can call this after freeing
- large blocks of memory to potentially reduce the system-level memory
- requirements of a program. However, it cannot guarantee to reduce
- memory. Under some allocation patterns, some large free blocks of
- memory will be locked between two used chunks, so they cannot be
- given back to the system.
-
- The `pad' argument to malloc_trim represents the amount of free
- trailing space to leave untrimmed. If this argument is zero, only
- the minimum amount of memory to maintain internal data structures
- will be left. Non-zero arguments can be supplied to maintain enough
- trailing space to service future expected allocations without having
- to re-obtain memory from the system.
-
- Malloc_trim returns 1 if it actually released any memory, else 0.
-*/
-DLMALLOC_EXPORT int dlmalloc_trim(size_t);
-
-/*
- malloc_stats();
- Prints on stderr the amount of space obtained from the system (both
- via sbrk and mmap), the maximum amount (which may be more than
- current if malloc_trim and/or munmap got called), and the current
- number of bytes allocated via malloc (or realloc, etc) but not yet
- freed. Note that this is the number of bytes allocated, not the
- number requested. It will be larger than the number requested
- because of alignment and bookkeeping overhead. Because it includes
- alignment wastage as being in use, this figure may be greater than
- zero even when no user-level chunks are allocated.
-
- The reported current and maximum system memory can be inaccurate if
- a program makes other calls to system memory allocation functions
- (normally sbrk) outside of malloc.
-
- malloc_stats prints only the most commonly interesting statistics.
- More information can be obtained by calling mallinfo.
-*/
-DLMALLOC_EXPORT void dlmalloc_stats(void);
-
-/*
- malloc_usable_size(void* p);
-
- Returns the number of bytes you can actually use in
- an allocated chunk, which may be more than you requested (although
- often not) due to alignment and minimum size constraints.
- You can use this many bytes without worrying about
- overwriting other allocated objects. This is not a particularly great
- programming practice. malloc_usable_size can be more useful in
- debugging and assertions, for example:
-
- p = malloc(n);
- assert(malloc_usable_size(p) >= 256);
-*/
-size_t dlmalloc_usable_size(void*);
-
-#endif /* ONLY_MSPACES */
-
-#if MSPACES
-
-/*
- mspace is an opaque type representing an independent
- region of space that supports mspace_malloc, etc.
-*/
-typedef void* mspace;
-
-/*
- create_mspace creates and returns a new independent space with the
- given initial capacity, or, if 0, the default granularity size. It
- returns null if there is no system memory available to create the
- space. If argument locked is non-zero, the space uses a separate
- lock to control access. The capacity of the space will grow
- dynamically as needed to service mspace_malloc requests. You can
- control the sizes of incremental increases of this space by
- compiling with a different DEFAULT_GRANULARITY or dynamically
- setting with mallopt(M_GRANULARITY, value).
-*/
-DLMALLOC_EXPORT mspace create_mspace(size_t capacity, int locked);
-
-/*
- destroy_mspace destroys the given space, and attempts to return all
- of its memory back to the system, returning the total number of
- bytes freed. After destruction, the results of access to all memory
- used by the space become undefined.
-*/
-DLMALLOC_EXPORT size_t destroy_mspace(mspace msp);
-
-/*
- create_mspace_with_base uses the memory supplied as the initial base
- of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
- space is used for bookkeeping, so the capacity must be at least this
- large. (Otherwise 0 is returned.) When this initial space is
- exhausted, additional memory will be obtained from the system.
- Destroying this space will deallocate all additionally allocated
- space (if possible) but not the initial base.
-*/
-DLMALLOC_EXPORT mspace create_mspace_with_base(void* base, size_t capacity, int locked);
-
-/*
- mspace_track_large_chunks controls whether requests for large chunks
- are allocated in their own untracked mmapped regions, separate from
- others in this mspace. By default large chunks are not tracked,
- which reduces fragmentation. However, such chunks are not
- necessarily released to the system upon destroy_mspace. Enabling
- tracking by setting to true may increase fragmentation, but avoids
- leakage when relying on destroy_mspace to release all memory
- allocated using this space. The function returns the previous
- setting.
-*/
-DLMALLOC_EXPORT int mspace_track_large_chunks(mspace msp, int enable);
-
-
-/*
- mspace_malloc behaves as malloc, but operates within
- the given space.
-*/
-DLMALLOC_EXPORT void* mspace_malloc(mspace msp, size_t bytes);
-
-/*
- mspace_free behaves as free, but operates within
- the given space.
-
- If compiled with FOOTERS==1, mspace_free is not actually needed.
- free may be called instead of mspace_free because freed chunks from
- any space are handled by their originating spaces.
-*/
-DLMALLOC_EXPORT void mspace_free(mspace msp, void* mem);
-
-/*
- mspace_realloc behaves as realloc, but operates within
- the given space.
-
- If compiled with FOOTERS==1, mspace_realloc is not actually
- needed. realloc may be called instead of mspace_realloc because
- realloced chunks from any space are handled by their originating
- spaces.
-*/
-DLMALLOC_EXPORT void* mspace_realloc(mspace msp, void* mem, size_t newsize);
-
-/*
- mspace_calloc behaves as calloc, but operates within
- the given space.
-*/
-DLMALLOC_EXPORT void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
-
-/*
- mspace_memalign behaves as memalign, but operates within
- the given space.
-*/
-DLMALLOC_EXPORT void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
-
-/*
- mspace_independent_calloc behaves as independent_calloc, but
- operates within the given space.
-*/
-DLMALLOC_EXPORT void** mspace_independent_calloc(mspace msp, size_t n_elements,
- size_t elem_size, void* chunks[]);
-
-/*
- mspace_independent_comalloc behaves as independent_comalloc, but
- operates within the given space.
-*/
-DLMALLOC_EXPORT void** mspace_independent_comalloc(mspace msp, size_t n_elements,
- size_t sizes[], void* chunks[]);
-
-/*
- mspace_footprint() returns the number of bytes obtained from the
- system for this space.
-*/
-DLMALLOC_EXPORT size_t mspace_footprint(mspace msp);
-
-/*
- mspace_max_footprint() returns the peak number of bytes obtained from the
- system for this space.
-*/
-DLMALLOC_EXPORT size_t mspace_max_footprint(mspace msp);
-
-
-#if !NO_MALLINFO
-/*
- mspace_mallinfo behaves as mallinfo, but reports properties of
- the given space.
-*/
-DLMALLOC_EXPORT struct mallinfo mspace_mallinfo(mspace msp);
-#endif /* NO_MALLINFO */
-
-/*
- malloc_usable_size(void* p) behaves the same as malloc_usable_size;
-*/
-DLMALLOC_EXPORT size_t mspace_usable_size(const void* mem);
-
-/*
- mspace_malloc_stats behaves as malloc_stats, but reports
- properties of the given space.
-*/
-DLMALLOC_EXPORT void mspace_malloc_stats(mspace msp);
-
-/*
- mspace_trim behaves as malloc_trim, but
- operates within the given space.
-*/
-DLMALLOC_EXPORT int mspace_trim(mspace msp, size_t pad);
-
-/*
- An alias for mallopt.
-*/
-DLMALLOC_EXPORT int mspace_mallopt(int, int);
-
-#endif /* MSPACES */
-
-#ifdef __cplusplus
-} /* end of extern "C" */
-#endif /* __cplusplus */
-
-/*
- ========================================================================
- To make a fully customizable malloc.h header file, cut everything
- above this line, put into file malloc.h, edit to suit, and #include it
- on the next line, as well as in programs that use this malloc.
- ========================================================================
-*/
-
-/* #include "malloc.h" */
-
-/*------------------------------ internal #includes ---------------------- */
-
-#ifdef _MSC_VER
-#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
-#endif /* _MSC_VER */
-#if !NO_MALLOC_STATS
-#include <stdio.h> /* for printing in malloc_stats */
-#endif /* NO_MALLOC_STATS */
-#ifndef LACKS_ERRNO_H
-#include <errno.h> /* for MALLOC_FAILURE_ACTION */
-#endif /* LACKS_ERRNO_H */
-#ifdef DEBUG
-#if ABORT_ON_ASSERT_FAILURE
-#undef assert
-#define assert(x) if(!(x)) ABORT
-#else /* ABORT_ON_ASSERT_FAILURE */
-#include <assert.h>
-#endif /* ABORT_ON_ASSERT_FAILURE */
-#else /* DEBUG */
-#ifndef assert
-#define assert(x)
-#endif
-#define DEBUG 0
-#endif /* DEBUG */
-#if !defined(WIN32) && !defined(LACKS_TIME_H)
-#include <time.h> /* for magic initialization */
-#endif /* WIN32 */
-#ifndef LACKS_STDLIB_H
-#include <stdlib.h> /* for abort() */
-#endif /* LACKS_STDLIB_H */
-#ifndef LACKS_STRING_H
-#include <string.h> /* for memset etc */
-#endif /* LACKS_STRING_H */
-#if USE_BUILTIN_FFS
-#ifndef LACKS_STRINGS_H
-#include <strings.h> /* for ffs */
-#endif /* LACKS_STRINGS_H */
-#endif /* USE_BUILTIN_FFS */
-#if HAVE_MMAP
-#ifndef LACKS_SYS_MMAN_H
-/* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */
-#if (defined(linux) && !defined(__USE_GNU))
-#define __USE_GNU 1
-#include <sys/mman.h> /* for mmap */
-#undef __USE_GNU
-#else
-#include <sys/mman.h> /* for mmap */
-#endif /* linux */
-#endif /* LACKS_SYS_MMAN_H */
-#ifndef LACKS_FCNTL_H
-#include <fcntl.h>
-#endif /* LACKS_FCNTL_H */
-#endif /* HAVE_MMAP */
-#ifndef LACKS_UNISTD_H
-#include <unistd.h> /* for sbrk, sysconf */
-#else /* LACKS_UNISTD_H */
-#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
-extern void* sbrk(ptrdiff_t);
-#endif /* FreeBSD etc */
-#endif /* LACKS_UNISTD_H */
-
-/* Declarations for locking */
-#if USE_LOCKS
-#ifndef WIN32
-#if defined (__SVR4) && defined (__sun) /* solaris */
-#include <thread.h>
-#elif !defined(LACKS_SCHED_H)
-#include <sched.h>
-#endif /* solaris or LACKS_SCHED_H */
-#if (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0) || !USE_SPIN_LOCKS
-#include <pthread.h>
-#endif /* USE_RECURSIVE_LOCKS ... */
-#elif defined(_MSC_VER)
-#ifndef _M_AMD64
-/* These are already defined on AMD64 builds */
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp);
-LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* _M_AMD64 */
-#pragma intrinsic (_InterlockedCompareExchange)
-#pragma intrinsic (_InterlockedExchange)
-#define interlockedcompareexchange _InterlockedCompareExchange
-#define interlockedexchange _InterlockedExchange
-#elif defined(WIN32) && defined(__GNUC__)
-#define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b)
-#define interlockedexchange __sync_lock_test_and_set
-#endif /* Win32 */
-#else /* USE_LOCKS */
-#endif /* USE_LOCKS */
-
-#ifndef LOCK_AT_FORK
-#define LOCK_AT_FORK 0
-#endif
-
-/* Declarations for bit scanning on win32 */
-#if defined(_MSC_VER) && _MSC_VER>=1300
-#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-unsigned char _BitScanForward(unsigned long *index, unsigned long mask);
-unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#define BitScanForward _BitScanForward
-#define BitScanReverse _BitScanReverse
-#pragma intrinsic(_BitScanForward)
-#pragma intrinsic(_BitScanReverse)
-#endif /* BitScanForward */
-#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */
-
-#ifndef WIN32
-#ifndef malloc_getpagesize
-# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
-# ifndef _SC_PAGE_SIZE
-# define _SC_PAGE_SIZE _SC_PAGESIZE
-# endif
-# endif
-# ifdef _SC_PAGE_SIZE
-# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
-# else
-# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
- extern size_t getpagesize();
-# define malloc_getpagesize getpagesize()
-# else
-# ifdef WIN32 /* use supplied emulation of getpagesize */
-# define malloc_getpagesize getpagesize()
-# else
-# ifndef LACKS_SYS_PARAM_H
-# include <sys/param.h>
-# endif
-# ifdef EXEC_PAGESIZE
-# define malloc_getpagesize EXEC_PAGESIZE
-# else
-# ifdef NBPG
-# ifndef CLSIZE
-# define malloc_getpagesize NBPG
-# else
-# define malloc_getpagesize (NBPG * CLSIZE)
-# endif
-# else
-# ifdef NBPC
-# define malloc_getpagesize NBPC
-# else
-# ifdef PAGESIZE
-# define malloc_getpagesize PAGESIZE
-# else /* just guess */
-# define malloc_getpagesize ((size_t)4096U)
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-#endif
-#endif
-
-/* ------------------- size_t and alignment properties -------------------- */
-
-/* The byte and bit size of a size_t */
-#define SIZE_T_SIZE (sizeof(size_t))
-#define SIZE_T_BITSIZE (sizeof(size_t) << 3)
-
-/* Some constants coerced to size_t */
-/* Annoying but necessary to avoid errors on some platforms */
-#define SIZE_T_ZERO ((size_t)0)
-#define SIZE_T_ONE ((size_t)1)
-#define SIZE_T_TWO ((size_t)2)
-#define SIZE_T_FOUR ((size_t)4)
-#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1)
-#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2)
-#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)
-#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U)
-
-/* The bit mask value corresponding to MALLOC_ALIGNMENT */
-#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE)
-
-/* True if address a has acceptable alignment */
-#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)
-
-/* the number of bytes to offset an address to align it */
-#define align_offset(A)\
- ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\
- ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))
-
-/* -------------------------- MMAP preliminaries ------------------------- */
-
-/*
- If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and
- checks to fail so compiler optimizer can delete code rather than
- using so many "#if"s.
-*/
-
-
-/* MORECORE and MMAP must return MFAIL on failure */
-#define MFAIL ((void*)(MAX_SIZE_T))
-#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */
-
-#if HAVE_MMAP
-
-#ifndef WIN32
-#define MUNMAP_DEFAULT(a, s) munmap((a), (s))
-#define MMAP_PROT (PROT_READ|PROT_WRITE)
-#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
-#define MAP_ANONYMOUS MAP_ANON
-#endif /* MAP_ANON */
-#ifdef MAP_ANONYMOUS
-#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS)
-#define MMAP_DEFAULT(s) mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)
-#else /* MAP_ANONYMOUS */
-/*
- Nearly all versions of mmap support MAP_ANONYMOUS, so the following
- is unlikely to be needed, but is supplied just in case.
-*/
-#define MMAP_FLAGS (MAP_PRIVATE)
-static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
-#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \
- (dev_zero_fd = open("/dev/zero", O_RDWR), \
- mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \
- mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))
-#endif /* MAP_ANONYMOUS */
-
-#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s)
-
-#else /* WIN32 */
-
-/* Win32 MMAP via VirtualAlloc */
-static FORCEINLINE void* win32mmap(size_t size) {
- void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
- return (ptr != 0)? ptr: MFAIL;
-}
-
-/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */
-static FORCEINLINE void* win32direct_mmap(size_t size) {
- void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,
- PAGE_READWRITE);
- return (ptr != 0)? ptr: MFAIL;
-}
-
-/* This function supports releasing coalesed segments */
-static FORCEINLINE int win32munmap(void* ptr, size_t size) {
- MEMORY_BASIC_INFORMATION minfo;
- char* cptr = (char*)ptr;
- while (size) {
- if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0)
- return -1;
- if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr ||
- minfo.State != MEM_COMMIT || minfo.RegionSize > size)
- return -1;
- if (VirtualFree(cptr, 0, MEM_RELEASE) == 0)
- return -1;
- cptr += minfo.RegionSize;
- size -= minfo.RegionSize;
- }
- return 0;
-}
-
-#define MMAP_DEFAULT(s) win32mmap(s)
-#define MUNMAP_DEFAULT(a, s) win32munmap((a), (s))
-#define DIRECT_MMAP_DEFAULT(s) win32direct_mmap(s)
-#endif /* WIN32 */
-#endif /* HAVE_MMAP */
-
-#if HAVE_MREMAP
-#ifndef WIN32
-#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv))
-#endif /* WIN32 */
-#endif /* HAVE_MREMAP */
-
-/**
- * Define CALL_MORECORE
- */
-#if HAVE_MORECORE
- #ifdef MORECORE
- #define CALL_MORECORE(S) MORECORE(S)
- #else /* MORECORE */
- #define CALL_MORECORE(S) MORECORE_DEFAULT(S)
- #endif /* MORECORE */
-#else /* HAVE_MORECORE */
- #define CALL_MORECORE(S) MFAIL
-#endif /* HAVE_MORECORE */
-
-/**
- * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP
- */
-#if HAVE_MMAP
- #define USE_MMAP_BIT (SIZE_T_ONE)
-
- #ifdef MMAP
- #define CALL_MMAP(s) MMAP(s)
- #else /* MMAP */
- #define CALL_MMAP(s) MMAP_DEFAULT(s)
- #endif /* MMAP */
- #ifdef MUNMAP
- #define CALL_MUNMAP(a, s) MUNMAP((a), (s))
- #else /* MUNMAP */
- #define CALL_MUNMAP(a, s) MUNMAP_DEFAULT((a), (s))
- #endif /* MUNMAP */
- #ifdef DIRECT_MMAP
- #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s)
- #else /* DIRECT_MMAP */
- #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s)
- #endif /* DIRECT_MMAP */
-#else /* HAVE_MMAP */
- #define USE_MMAP_BIT (SIZE_T_ZERO)
-
- #define MMAP(s) MFAIL
- #define MUNMAP(a, s) (-1)
- #define DIRECT_MMAP(s) MFAIL
- #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s)
- #define CALL_MMAP(s) MMAP(s)
- #define CALL_MUNMAP(a, s) MUNMAP((a), (s))
-#endif /* HAVE_MMAP */
-
-/**
- * Define CALL_MREMAP
- */
-#if HAVE_MMAP && HAVE_MREMAP
- #ifdef MREMAP
- #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv))
- #else /* MREMAP */
- #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv))
- #endif /* MREMAP */
-#else /* HAVE_MMAP && HAVE_MREMAP */
- #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL
-#endif /* HAVE_MMAP && HAVE_MREMAP */
-
-/* mstate bit set if continguous morecore disabled or failed */
-#define USE_NONCONTIGUOUS_BIT (4U)
-
-/* segment bit set in create_mspace_with_base */
-#define EXTERN_BIT (8U)
-
-
-/* --------------------------- Lock preliminaries ------------------------ */
-
-/*
- When locks are defined, there is one global lock, plus
- one per-mspace lock.
-
- The global lock_ensures that mparams.magic and other unique
- mparams values are initialized only once. It also protects
- sequences of calls to MORECORE. In many cases sys_alloc requires
- two calls, that should not be interleaved with calls by other
- threads. This does not protect against direct calls to MORECORE
- by other threads not using this lock, so there is still code to
- cope the best we can on interference.
-
- Per-mspace locks surround calls to malloc, free, etc.
- By default, locks are simple non-reentrant mutexes.
-
- Because lock-protected regions generally have bounded times, it is
- OK to use the supplied simple spinlocks. Spinlocks are likely to
- improve performance for lightly contended applications, but worsen
- performance under heavy contention.
-
- If USE_LOCKS is > 1, the definitions of lock routines here are
- bypassed, in which case you will need to define the type MLOCK_T,
- and at least INITIAL_LOCK, DESTROY_LOCK, ACQUIRE_LOCK, RELEASE_LOCK
- and TRY_LOCK. You must also declare a
- static MLOCK_T malloc_global_mutex = { initialization values };.
-
-*/
-
-#if !USE_LOCKS
-#define USE_LOCK_BIT (0U)
-#define INITIAL_LOCK(l) (0)
-#define DESTROY_LOCK(l) (0)
-#define ACQUIRE_MALLOC_GLOBAL_LOCK()
-#define RELEASE_MALLOC_GLOBAL_LOCK()
-
-#else
-#if USE_LOCKS > 1
-/* ----------------------- User-defined locks ------------------------ */
-/* Define your own lock implementation here */
-/* #define INITIAL_LOCK(lk) ... */
-/* #define DESTROY_LOCK(lk) ... */
-/* #define ACQUIRE_LOCK(lk) ... */
-/* #define RELEASE_LOCK(lk) ... */
-/* #define TRY_LOCK(lk) ... */
-/* static MLOCK_T malloc_global_mutex = ... */
-
-#elif USE_SPIN_LOCKS
-
-/* First, define CAS_LOCK and CLEAR_LOCK on ints */
-/* Note CAS_LOCK defined to return 0 on success */
-
-#if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
-#define CAS_LOCK(sl) __sync_lock_test_and_set(sl, 1)
-#define CLEAR_LOCK(sl) __sync_lock_release(sl)
-
-#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
-/* Custom spin locks for older gcc on x86 */
-static FORCEINLINE int x86_cas_lock(int *sl) {
- int ret;
- int val = 1;
- int cmp = 0;
- __asm__ __volatile__ ("lock; cmpxchgl %1, %2"
- : "=a" (ret)
- : "r" (val), "m" (*(sl)), "0"(cmp)
- : "memory", "cc");
- return ret;
-}
-
-static FORCEINLINE void x86_clear_lock(int* sl) {
- assert(*sl != 0);
- int prev = 0;
- int ret;
- __asm__ __volatile__ ("lock; xchgl %0, %1"
- : "=r" (ret)
- : "m" (*(sl)), "0"(prev)
- : "memory");
-}
-
-#define CAS_LOCK(sl) x86_cas_lock(sl)
-#define CLEAR_LOCK(sl) x86_clear_lock(sl)
-
-#else /* Win32 MSC */
-#define CAS_LOCK(sl) interlockedexchange(sl, (LONG)1)
-#define CLEAR_LOCK(sl) interlockedexchange (sl, (LONG)0)
-
-#endif /* ... gcc spins locks ... */
-
-/* How to yield for a spin lock */
-#define SPINS_PER_YIELD 63
-#if defined(_MSC_VER)
-#define SLEEP_EX_DURATION 50 /* delay for yield/sleep */
-#define SPIN_LOCK_YIELD SleepEx(SLEEP_EX_DURATION, FALSE)
-#elif defined (__SVR4) && defined (__sun) /* solaris */
-#define SPIN_LOCK_YIELD thr_yield();
-#elif !defined(LACKS_SCHED_H)
-#define SPIN_LOCK_YIELD sched_yield();
-#else
-#define SPIN_LOCK_YIELD
-#endif /* ... yield ... */
-
-#if !defined(USE_RECURSIVE_LOCKS) || USE_RECURSIVE_LOCKS == 0
-/* Plain spin locks use single word (embedded in malloc_states) */
-static int spin_acquire_lock(int *sl) {
- int spins = 0;
- while (*(volatile int *)sl != 0 || CAS_LOCK(sl)) {
- if ((++spins & SPINS_PER_YIELD) == 0) {
- SPIN_LOCK_YIELD;
- }
- }
- return 0;
-}
-
-#define MLOCK_T int
-#define TRY_LOCK(sl) !CAS_LOCK(sl)
-#define RELEASE_LOCK(sl) CLEAR_LOCK(sl)
-#define ACQUIRE_LOCK(sl) (CAS_LOCK(sl)? spin_acquire_lock(sl) : 0)
-#define INITIAL_LOCK(sl) (*sl = 0)
-#define DESTROY_LOCK(sl) (0)
-static MLOCK_T malloc_global_mutex = 0;
-
-#else /* USE_RECURSIVE_LOCKS */
-/* types for lock owners */
-#ifdef WIN32
-#define THREAD_ID_T DWORD
-#define CURRENT_THREAD GetCurrentThreadId()
-#define EQ_OWNER(X,Y) ((X) == (Y))
-#else
-/*
- Note: the following assume that pthread_t is a type that can be
- initialized to (casted) zero. If this is not the case, you will need to
- somehow redefine these or not use spin locks.
-*/
-#define THREAD_ID_T pthread_t
-#define CURRENT_THREAD pthread_self()
-#define EQ_OWNER(X,Y) pthread_equal(X, Y)
-#endif
-
-struct malloc_recursive_lock {
- int sl;
- unsigned int c;
- THREAD_ID_T threadid;
-};
-
-#define MLOCK_T struct malloc_recursive_lock
-static MLOCK_T malloc_global_mutex = { 0, 0, (THREAD_ID_T)0};
-
-static FORCEINLINE void recursive_release_lock(MLOCK_T *lk) {
- assert(lk->sl != 0);
- if (--lk->c == 0) {
- CLEAR_LOCK(&lk->sl);
- }
-}
-
-static FORCEINLINE int recursive_acquire_lock(MLOCK_T *lk) {
- THREAD_ID_T mythreadid = CURRENT_THREAD;
- int spins = 0;
- for (;;) {
- if (*((volatile int *)(&lk->sl)) == 0) {
- if (!CAS_LOCK(&lk->sl)) {
- lk->threadid = mythreadid;
- lk->c = 1;
- return 0;
- }
- }
- else if (EQ_OWNER(lk->threadid, mythreadid)) {
- ++lk->c;
- return 0;
- }
- if ((++spins & SPINS_PER_YIELD) == 0) {
- SPIN_LOCK_YIELD;
- }
- }
-}
-
-static FORCEINLINE int recursive_try_lock(MLOCK_T *lk) {
- THREAD_ID_T mythreadid = CURRENT_THREAD;
- if (*((volatile int *)(&lk->sl)) == 0) {
- if (!CAS_LOCK(&lk->sl)) {
- lk->threadid = mythreadid;
- lk->c = 1;
- return 1;
- }
- }
- else if (EQ_OWNER(lk->threadid, mythreadid)) {
- ++lk->c;
- return 1;
- }
- return 0;
-}
-
-#define RELEASE_LOCK(lk) recursive_release_lock(lk)
-#define TRY_LOCK(lk) recursive_try_lock(lk)
-#define ACQUIRE_LOCK(lk) recursive_acquire_lock(lk)
-#define INITIAL_LOCK(lk) ((lk)->threadid = (THREAD_ID_T)0, (lk)->sl = 0, (lk)->c = 0)
-#define DESTROY_LOCK(lk) (0)
-#endif /* USE_RECURSIVE_LOCKS */
-
-#elif defined(WIN32) /* Win32 critical sections */
-#define MLOCK_T CRITICAL_SECTION
-#define ACQUIRE_LOCK(lk) (EnterCriticalSection(lk), 0)
-#define RELEASE_LOCK(lk) LeaveCriticalSection(lk)
-#define TRY_LOCK(lk) TryEnterCriticalSection(lk)
-#define INITIAL_LOCK(lk) (!InitializeCriticalSectionAndSpinCount((lk), 0x80000000|4000))
-#define DESTROY_LOCK(lk) (DeleteCriticalSection(lk), 0)
-#define NEED_GLOBAL_LOCK_INIT
-
-static MLOCK_T malloc_global_mutex;
-static volatile LONG malloc_global_mutex_status;
-
-/* Use spin loop to initialize global lock */
-static void init_malloc_global_mutex() {
- for (;;) {
- long stat = malloc_global_mutex_status;
- if (stat > 0)
- return;
- /* transition to < 0 while initializing, then to > 0) */
- if (stat == 0 &&
- interlockedcompareexchange(&malloc_global_mutex_status, (LONG)-1, (LONG)0) == 0) {
- InitializeCriticalSection(&malloc_global_mutex);
- interlockedexchange(&malloc_global_mutex_status, (LONG)1);
- return;
- }
- SleepEx(0, FALSE);
- }
-}
-
-#else /* pthreads-based locks */
-#define MLOCK_T pthread_mutex_t
-#define ACQUIRE_LOCK(lk) pthread_mutex_lock(lk)
-#define RELEASE_LOCK(lk) pthread_mutex_unlock(lk)
-#define TRY_LOCK(lk) (!pthread_mutex_trylock(lk))
-#define INITIAL_LOCK(lk) pthread_init_lock(lk)
-#define DESTROY_LOCK(lk) pthread_mutex_destroy(lk)
-
-#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 && defined(linux) && !defined(PTHREAD_MUTEX_RECURSIVE)
-/* Cope with old-style linux recursive lock initialization by adding */
-/* skipped internal declaration from pthread.h */
-extern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr,
- int __kind));
-#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
-#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y)
-#endif /* USE_RECURSIVE_LOCKS ... */
-
-static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static int pthread_init_lock (MLOCK_T *lk) {
- pthread_mutexattr_t attr;
- if (pthread_mutexattr_init(&attr)) return 1;
-#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0
- if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1;
-#endif
- if (pthread_mutex_init(lk, &attr)) return 1;
- if (pthread_mutexattr_destroy(&attr)) return 1;
- return 0;
-}
-
-#endif /* ... lock types ... */
-
-/* Common code for all lock types */
-#define USE_LOCK_BIT (2U)
-
-#ifndef ACQUIRE_MALLOC_GLOBAL_LOCK
-#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex);
-#endif
-
-#ifndef RELEASE_MALLOC_GLOBAL_LOCK
-#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex);
-#endif
-
-#endif /* USE_LOCKS */
-
-/* ----------------------- Chunk representations ------------------------ */
-
-/*
- (The following includes lightly edited explanations by Colin Plumb.)
-
- The malloc_chunk declaration below is misleading (but accurate and
- necessary). It declares a "view" into memory allowing access to
- necessary fields at known offsets from a given base.
-
- Chunks of memory are maintained using a `boundary tag' method as
- originally described by Knuth. (See the paper by Paul Wilson
- ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such
- techniques.) Sizes of free chunks are stored both in the front of
- each chunk and at the end. This makes consolidating fragmented
- chunks into bigger chunks fast. The head fields also hold bits
- representing whether chunks are free or in use.
-
- Here are some pictures to make it clearer. They are "exploded" to
- show that the state of a chunk can be thought of as extending from
- the high 31 bits of the head field of its header through the
- prev_foot and PINUSE_BIT bit of the following chunk header.
-
- A chunk that's in use looks like:
-
- chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Size of previous chunk (if P = 0) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
- | Size of this chunk 1| +-+
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | |
- +- -+
- | |
- +- -+
- | :
- +- size - sizeof(size_t) available payload bytes -+
- : |
- chunk-> +- -+
- | |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|
- | Size of next chunk (may or may not be in use) | +-+
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
- And if it's free, it looks like this:
-
- chunk-> +- -+
- | User payload (must be in use, or we would have merged!) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
- | Size of this chunk 0| +-+
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Next pointer |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Prev pointer |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | :
- +- size - sizeof(struct chunk) unused bytes -+
- : |
- chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Size of this chunk |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|
- | Size of next chunk (must be in use, or we would have merged)| +-+
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | :
- +- User payload -+
- : |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |0|
- +-+
- Note that since we always merge adjacent free chunks, the chunks
- adjacent to a free chunk must be in use.
-
- Given a pointer to a chunk (which can be derived trivially from the
- payload pointer) we can, in O(1) time, find out whether the adjacent
- chunks are free, and if so, unlink them from the lists that they
- are on and merge them with the current chunk.
-
- Chunks always begin on even word boundaries, so the mem portion
- (which is returned to the user) is also on an even word boundary, and
- thus at least double-word aligned.
-
- The P (PINUSE_BIT) bit, stored in the unused low-order bit of the
- chunk size (which is always a multiple of two words), is an in-use
- bit for the *previous* chunk. If that bit is *clear*, then the
- word before the current chunk size contains the previous chunk
- size, and can be used to find the front of the previous chunk.
- The very first chunk allocated always has this bit set, preventing
- access to non-existent (or non-owned) memory. If pinuse is set for
- any given chunk, then you CANNOT determine the size of the
- previous chunk, and might even get a memory addressing fault when
- trying to do so.
-
- The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of
- the chunk size redundantly records whether the current chunk is
- inuse (unless the chunk is mmapped). This redundancy enables usage
- checks within free and realloc, and reduces indirection when freeing
- and consolidating chunks.
-
- Each freshly allocated chunk must have both cinuse and pinuse set.
- That is, each allocated chunk borders either a previously allocated
- and still in-use chunk, or the base of its memory arena. This is
- ensured by making all allocations from the `lowest' part of any
- found chunk. Further, no free chunk physically borders another one,
- so each free chunk is known to be preceded and followed by either
- inuse chunks or the ends of memory.
-
- Note that the `foot' of the current chunk is actually represented
- as the prev_foot of the NEXT chunk. This makes it easier to
- deal with alignments etc but can be very confusing when trying
- to extend or adapt this code.
-
- The exceptions to all this are
-
- 1. The special chunk `top' is the top-most available chunk (i.e.,
- the one bordering the end of available memory). It is treated
- specially. Top is never included in any bin, is used only if
- no other chunk is available, and is released back to the
- system if it is very large (see M_TRIM_THRESHOLD). In effect,
- the top chunk is treated as larger (and thus less well
- fitting) than any other available chunk. The top chunk
- doesn't update its trailing size field since there is no next
- contiguous chunk that would have to index off it. However,
- space is still allocated for it (TOP_FOOT_SIZE) to enable
- separation or merging when space is extended.
-
- 3. Chunks allocated via mmap, have both cinuse and pinuse bits
- cleared in their head fields. Because they are allocated
- one-by-one, each must carry its own prev_foot field, which is
- also used to hold the offset this chunk has within its mmapped
- region, which is needed to preserve alignment. Each mmapped
- chunk is trailed by the first two fields of a fake next-chunk
- for sake of usage checks.
-
-*/
-
-struct malloc_chunk {
- size_t prev_foot; /* Size of previous chunk (if free). */
- size_t head; /* Size and inuse bits. */
- struct malloc_chunk* fd; /* double links -- used only if free. */
- struct malloc_chunk* bk;
-};
-
-typedef struct malloc_chunk mchunk;
-typedef struct malloc_chunk* mchunkptr;
-typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */
-typedef unsigned int bindex_t; /* Described below */
-typedef unsigned int binmap_t; /* Described below */
-typedef unsigned int flag_t; /* The type of various bit flag sets */
-
-/* ------------------- Chunks sizes and alignments ----------------------- */
-
-#define MCHUNK_SIZE (sizeof(mchunk))
-
-#if FOOTERS
-#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
-#else /* FOOTERS */
-#define CHUNK_OVERHEAD (SIZE_T_SIZE)
-#endif /* FOOTERS */
-
-/* MMapped chunks need a second word of overhead ... */
-#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
-/* ... and additional padding for fake next-chunk at foot */
-#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES)
-
-/* The smallest size we can malloc is an aligned minimal chunk */
-#define MIN_CHUNK_SIZE\
- ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
-
-/* conversion from malloc headers to user pointers, and back */
-#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES))
-#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))
-/* chunk associated with aligned address A */
-#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A)))
-
-/* Bounds on request (not chunk) sizes. */
-#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2)
-#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)
-
-/* pad request bytes into a usable size */
-#define pad_request(req) \
- (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
-
-/* pad request, checking for minimum (but not maximum) */
-#define request2size(req) \
- (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))
-
-
-/* ------------------ Operations on head and foot fields ----------------- */
-
-/*
- The head field of a chunk is or'ed with PINUSE_BIT when previous
- adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in
- use, unless mmapped, in which case both bits are cleared.
-
- FLAG4_BIT is not used by this malloc, but might be useful in extensions.
-*/
-
-#define PINUSE_BIT (SIZE_T_ONE)
-#define CINUSE_BIT (SIZE_T_TWO)
-#define FLAG4_BIT (SIZE_T_FOUR)
-#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT)
-#define FLAG_BITS (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT)
-
-/* Head value for fenceposts */
-#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE)
-
-/* extraction of fields from head words */
-#define cinuse(p) ((p)->head & CINUSE_BIT)
-#define pinuse(p) ((p)->head & PINUSE_BIT)
-#define flag4inuse(p) ((p)->head & FLAG4_BIT)
-#define is_inuse(p) (((p)->head & INUSE_BITS) != PINUSE_BIT)
-#define is_mmapped(p) (((p)->head & INUSE_BITS) == 0)
-
-#define chunksize(p) ((p)->head & ~(FLAG_BITS))
-
-#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT)
-#define set_flag4(p) ((p)->head |= FLAG4_BIT)
-#define clear_flag4(p) ((p)->head &= ~FLAG4_BIT)
-
-/* Treat space at ptr +/- offset as a chunk */
-#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
-#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))
-
-/* Ptr to next or previous physical malloc_chunk. */
-#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS)))
-#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))
-
-/* extract next chunk's pinuse bit */
-#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT)
-
-/* Get/set size at footer */
-#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot)
-#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))
-
-/* Set size, pinuse bit, and foot */
-#define set_size_and_pinuse_of_free_chunk(p, s)\
- ((p)->head = (s|PINUSE_BIT), set_foot(p, s))
-
-/* Set size, pinuse bit, foot, and clear next pinuse */
-#define set_free_with_pinuse(p, s, n)\
- (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))
-
-/* Get the internal overhead associated with chunk p */
-#define overhead_for(p)\
- (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD)
-
-/* Return true if malloced space is not necessarily cleared */
-#if MMAP_CLEARS
-#define calloc_must_clear(p) (!is_mmapped(p))
-#else /* MMAP_CLEARS */
-#define calloc_must_clear(p) (1)
-#endif /* MMAP_CLEARS */
-
-/* ---------------------- Overlaid data structures ----------------------- */
-
-/*
- When chunks are not in use, they are treated as nodes of either
- lists or trees.
-
- "Small" chunks are stored in circular doubly-linked lists, and look
- like this:
-
- chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Size of previous chunk |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- `head:' | Size of chunk, in bytes |P|
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Forward pointer to next chunk in list |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Back pointer to previous chunk in list |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Unused space (may be 0 bytes long) .
- . .
- . |
-nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- `foot:' | Size of chunk, in bytes |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
- Larger chunks are kept in a form of bitwise digital trees (aka
- tries) keyed on chunksizes. Because malloc_tree_chunks are only for
- free chunks greater than 256 bytes, their size doesn't impose any
- constraints on user chunk sizes. Each node looks like:
-
- chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Size of previous chunk |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- `head:' | Size of chunk, in bytes |P|
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Forward pointer to next chunk of same size |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Back pointer to previous chunk of same size |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Pointer to left child (child[0]) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Pointer to right child (child[1]) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Pointer to parent |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | bin index of this chunk |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Unused space .
- . |
-nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- `foot:' | Size of chunk, in bytes |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
- Each tree holding treenodes is a tree of unique chunk sizes. Chunks
- of the same size are arranged in a circularly-linked list, with only
- the oldest chunk (the next to be used, in our FIFO ordering)
- actually in the tree. (Tree members are distinguished by a non-null
- parent pointer.) If a chunk with the same size an an existing node
- is inserted, it is linked off the existing node using pointers that
- work in the same way as fd/bk pointers of small chunks.
-
- Each tree contains a power of 2 sized range of chunk sizes (the
- smallest is 0x100 <= x < 0x180), which is is divided in half at each
- tree level, with the chunks in the smaller half of the range (0x100
- <= x < 0x140 for the top nose) in the left subtree and the larger
- half (0x140 <= x < 0x180) in the right subtree. This is, of course,
- done by inspecting individual bits.
-
- Using these rules, each node's left subtree contains all smaller
- sizes than its right subtree. However, the node at the root of each
- subtree has no particular ordering relationship to either. (The
- dividing line between the subtree sizes is based on trie relation.)
- If we remove the last chunk of a given size from the interior of the
- tree, we need to replace it with a leaf node. The tree ordering
- rules permit a node to be replaced by any leaf below it.
-
- The smallest chunk in a tree (a common operation in a best-fit
- allocator) can be found by walking a path to the leftmost leaf in
- the tree. Unlike a usual binary tree, where we follow left child
- pointers until we reach a null, here we follow the right child
- pointer any time the left one is null, until we reach a leaf with
- both child pointers null. The smallest chunk in the tree will be
- somewhere along that path.
-
- The worst case number of steps to add, find, or remove a node is
- bounded by the number of bits differentiating chunks within
- bins. Under current bin calculations, this ranges from 6 up to 21
- (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case
- is of course much better.
-*/
-
-struct malloc_tree_chunk {
- /* The first four fields must be compatible with malloc_chunk */
- size_t prev_foot;
- size_t head;
- struct malloc_tree_chunk* fd;
- struct malloc_tree_chunk* bk;
-
- struct malloc_tree_chunk* child[2];
- struct malloc_tree_chunk* parent;
- bindex_t index;
-};
-
-typedef struct malloc_tree_chunk tchunk;
-typedef struct malloc_tree_chunk* tchunkptr;
-typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */
-
-/* A little helper macro for trees */
-#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])
-
-/* ----------------------------- Segments -------------------------------- */
-
-/*
- Each malloc space may include non-contiguous segments, held in a
- list headed by an embedded malloc_segment record representing the
- top-most space. Segments also include flags holding properties of
- the space. Large chunks that are directly allocated by mmap are not
- included in this list. They are instead independently created and
- destroyed without otherwise keeping track of them.
-
- Segment management mainly comes into play for spaces allocated by
- MMAP. Any call to MMAP might or might not return memory that is
- adjacent to an existing segment. MORECORE normally contiguously
- extends the current space, so this space is almost always adjacent,
- which is simpler and faster to deal with. (This is why MORECORE is
- used preferentially to MMAP when both are available -- see
- sys_alloc.) When allocating using MMAP, we don't use any of the
- hinting mechanisms (inconsistently) supported in various
- implementations of unix mmap, or distinguish reserving from
- committing memory. Instead, we just ask for space, and exploit
- contiguity when we get it. It is probably possible to do
- better than this on some systems, but no general scheme seems
- to be significantly better.
-
- Management entails a simpler variant of the consolidation scheme
- used for chunks to reduce fragmentation -- new adjacent memory is
- normally prepended or appended to an existing segment. However,
- there are limitations compared to chunk consolidation that mostly
- reflect the fact that segment processing is relatively infrequent
- (occurring only when getting memory from system) and that we
- don't expect to have huge numbers of segments:
-
- * Segments are not indexed, so traversal requires linear scans. (It
- would be possible to index these, but is not worth the extra
- overhead and complexity for most programs on most platforms.)
- * New segments are only appended to old ones when holding top-most
- memory; if they cannot be prepended to others, they are held in
- different segments.
-
- Except for the top-most segment of an mstate, each segment record
- is kept at the tail of its segment. Segments are added by pushing
- segment records onto the list headed by &mstate.seg for the
- containing mstate.
-
- Segment flags control allocation/merge/deallocation policies:
- * If EXTERN_BIT set, then we did not allocate this segment,
- and so should not try to deallocate or merge with others.
- (This currently holds only for the initial segment passed
- into create_mspace_with_base.)
- * If USE_MMAP_BIT set, the segment may be merged with
- other surrounding mmapped segments and trimmed/de-allocated
- using munmap.
- * If neither bit is set, then the segment was obtained using
- MORECORE so can be merged with surrounding MORECORE'd segments
- and deallocated/trimmed using MORECORE with negative arguments.
-*/
-
-struct malloc_segment {
- char* base; /* base address */
- size_t size; /* allocated size */
- struct malloc_segment* next; /* ptr to next segment */
- flag_t sflags; /* mmap and extern flag */
-};
-
-#define is_mmapped_segment(S) ((S)->sflags & USE_MMAP_BIT)
-#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT)
-
-typedef struct malloc_segment msegment;
-typedef struct malloc_segment* msegmentptr;
-
-/* ---------------------------- malloc_state ----------------------------- */
-
-/*
- A malloc_state holds all of the bookkeeping for a space.
- The main fields are:
-
- Top
- The topmost chunk of the currently active segment. Its size is
- cached in topsize. The actual size of topmost space is
- topsize+TOP_FOOT_SIZE, which includes space reserved for adding
- fenceposts and segment records if necessary when getting more
- space from the system. The size at which to autotrim top is
- cached from mparams in trim_check, except that it is disabled if
- an autotrim fails.
-
- Designated victim (dv)
- This is the preferred chunk for servicing small requests that
- don't have exact fits. It is normally the chunk split off most
- recently to service another small request. Its size is cached in
- dvsize. The link fields of this chunk are not maintained since it
- is not kept in a bin.
-
- SmallBins
- An array of bin headers for free chunks. These bins hold chunks
- with sizes less than MIN_LARGE_SIZE bytes. Each bin contains
- chunks of all the same size, spaced 8 bytes apart. To simplify
- use in double-linked lists, each bin header acts as a malloc_chunk
- pointing to the real first node, if it exists (else pointing to
- itself). This avoids special-casing for headers. But to avoid
- waste, we allocate only the fd/bk pointers of bins, and then use
- repositioning tricks to treat these as the fields of a chunk.
-
- TreeBins
- Treebins are pointers to the roots of trees holding a range of
- sizes. There are 2 equally spaced treebins for each power of two
- from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything
- larger.
-
- Bin maps
- There is one bit map for small bins ("smallmap") and one for
- treebins ("treemap). Each bin sets its bit when non-empty, and
- clears the bit when empty. Bit operations are then used to avoid
- bin-by-bin searching -- nearly all "search" is done without ever
- looking at bins that won't be selected. The bit maps
- conservatively use 32 bits per map word, even if on 64bit system.
- For a good description of some of the bit-based techniques used
- here, see Henry S. Warren Jr's book "Hacker's Delight" (and
- supplement at http://hackersdelight.org/). Many of these are
- intended to reduce the branchiness of paths through malloc etc, as
- well as to reduce the number of memory locations read or written.
-
- Segments
- A list of segments headed by an embedded malloc_segment record
- representing the initial space.
-
- Address check support
- The least_addr field is the least address ever obtained from
- MORECORE or MMAP. Attempted frees and reallocs of any address less
- than this are trapped (unless INSECURE is defined).
-
- Magic tag
- A cross-check field that should always hold same value as mparams.magic.
-
- Max allowed footprint
- The maximum allowed bytes to allocate from system (zero means no limit)
-
- Flags
- Bits recording whether to use MMAP, locks, or contiguous MORECORE
-
- Statistics
- Each space keeps track of current and maximum system memory
- obtained via MORECORE or MMAP.
-
- Trim support
- Fields holding the amount of unused topmost memory that should trigger
- trimming, and a counter to force periodic scanning to release unused
- non-topmost segments.
-
- Locking
- If USE_LOCKS is defined, the "mutex" lock is acquired and released
- around every public call using this mspace.
-
- Extension support
- A void* pointer and a size_t field that can be used to help implement
- extensions to this malloc.
-*/
-
-/* Bin types, widths and sizes */
-#define NSMALLBINS (32U)
-#define NTREEBINS (32U)
-#define SMALLBIN_SHIFT (3U)
-#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT)
-#define TREEBIN_SHIFT (8U)
-#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT)
-#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE)
-#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)
-
-struct malloc_state {
- binmap_t smallmap;
- binmap_t treemap;
- size_t dvsize;
- size_t topsize;
- char* least_addr;
- mchunkptr dv;
- mchunkptr top;
- size_t trim_check;
- size_t release_checks;
- size_t magic;
- mchunkptr smallbins[(NSMALLBINS+1)*2];
- tbinptr treebins[NTREEBINS];
- size_t footprint;
- size_t max_footprint;
- size_t footprint_limit; /* zero means no limit */
- flag_t mflags;
-#if USE_LOCKS
- MLOCK_T mutex; /* locate lock among fields that rarely change */
-#endif /* USE_LOCKS */
- msegment seg;
- void* extp; /* Unused but available for extensions */
- size_t exts;
-};
-
-typedef struct malloc_state* mstate;
-
-/* ------------- Global malloc_state and malloc_params ------------------- */
-
-/*
- malloc_params holds global properties, including those that can be
- dynamically set using mallopt. There is a single instance, mparams,
- initialized in init_mparams. Note that the non-zeroness of "magic"
- also serves as an initialization flag.
-*/
-
-struct malloc_params {
- size_t magic;
- size_t page_size;
- size_t granularity;
- size_t mmap_threshold;
- size_t trim_threshold;
- flag_t default_mflags;
-};
-
-static struct malloc_params mparams;
-
-/* Ensure mparams initialized */
-#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams())
-
-#if !ONLY_MSPACES
-
-/* The global malloc_state used for all non-"mspace" calls */
-static struct malloc_state _gm_;
-#define gm (&_gm_)
-#define is_global(M) ((M) == &_gm_)
-
-#endif /* !ONLY_MSPACES */
-
-#define is_initialized(M) ((M)->top != 0)
-
-/* -------------------------- system alloc setup ------------------------- */
-
-/* Operations on mflags */
-
-#define use_lock(M) ((M)->mflags & USE_LOCK_BIT)
-#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT)
-#if USE_LOCKS
-#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT)
-#else
-#define disable_lock(M)
-#endif
-
-#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT)
-#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT)
-#if HAVE_MMAP
-#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT)
-#else
-#define disable_mmap(M)
-#endif
-
-#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT)
-#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT)
-
-#define set_lock(M,L)\
- ((M)->mflags = (L)?\
- ((M)->mflags | USE_LOCK_BIT) :\
- ((M)->mflags & ~USE_LOCK_BIT))
-
-/* page-align a size */
-#define page_align(S)\
- (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE))
-
-/* granularity-align a size */
-#define granularity_align(S)\
- (((S) + (mparams.granularity - SIZE_T_ONE))\
- & ~(mparams.granularity - SIZE_T_ONE))
-
-
-/* For mmap, use granularity alignment on windows, else page-align */
-#ifdef WIN32
-#define mmap_align(S) granularity_align(S)
-#else
-#define mmap_align(S) page_align(S)
-#endif
-
-/* For sys_alloc, enough padding to ensure can malloc request on success */
-#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT)
-
-#define is_page_aligned(S)\
- (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)
-#define is_granularity_aligned(S)\
- (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)
-
-/* True if segment S holds address A */
-#define segment_holds(S, A)\
- ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
-
-/* Return segment holding given address */
-static msegmentptr segment_holding(mstate m, char* addr) {
- msegmentptr sp = &m->seg;
- for (;;) {
- if (addr >= sp->base && addr < sp->base + sp->size)
- return sp;
- if ((sp = sp->next) == 0)
- return 0;
- }
-}
-
-/* Return true if segment contains a segment link */
-static int has_segment_link(mstate m, msegmentptr ss) {
- msegmentptr sp = &m->seg;
- for (;;) {
- if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)
- return 1;
- if ((sp = sp->next) == 0)
- return 0;
- }
-}
-
-#ifndef MORECORE_CANNOT_TRIM
-#define should_trim(M,s) ((s) > (M)->trim_check)
-#else /* MORECORE_CANNOT_TRIM */
-#define should_trim(M,s) (0)
-#endif /* MORECORE_CANNOT_TRIM */
-
-/*
- TOP_FOOT_SIZE is padding at the end of a segment, including space
- that may be needed to place segment records and fenceposts when new
- noncontiguous segments are added.
-*/
-#define TOP_FOOT_SIZE\
- (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE)
-
-
-/* ------------------------------- Hooks -------------------------------- */
-
-/*
- PREACTION should be defined to return 0 on success, and nonzero on
- failure. If you are not using locking, you can redefine these to do
- anything you like.
-*/
-
-#if USE_LOCKS
-#define PREACTION(M) ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0)
-#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }
-#else /* USE_LOCKS */
-
-#ifndef PREACTION
-#define PREACTION(M) (0)
-#endif /* PREACTION */
-
-#ifndef POSTACTION
-#define POSTACTION(M)
-#endif /* POSTACTION */
-
-#endif /* USE_LOCKS */
-
-/*
- CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.
- USAGE_ERROR_ACTION is triggered on detected bad frees and
- reallocs. The argument p is an address that might have triggered the
- fault. It is ignored by the two predefined actions, but might be
- useful in custom actions that try to help diagnose errors.
-*/
-
-#if PROCEED_ON_ERROR
-
-/* A count of the number of corruption errors causing resets */
-int malloc_corruption_error_count;
-
-/* default corruption action */
-static void reset_on_error(mstate m);
-
-#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m)
-#define USAGE_ERROR_ACTION(m, p)
-
-#else /* PROCEED_ON_ERROR */
-
-#ifndef CORRUPTION_ERROR_ACTION
-#define CORRUPTION_ERROR_ACTION(m) ABORT
-#endif /* CORRUPTION_ERROR_ACTION */
-
-#ifndef USAGE_ERROR_ACTION
-#define USAGE_ERROR_ACTION(m,p) ABORT
-#endif /* USAGE_ERROR_ACTION */
-
-#endif /* PROCEED_ON_ERROR */
-
-
-/* -------------------------- Debugging setup ---------------------------- */
-
-#if ! DEBUG
-
-#define check_free_chunk(M,P)
-#define check_inuse_chunk(M,P)
-#define check_malloced_chunk(M,P,N)
-#define check_mmapped_chunk(M,P)
-#define check_malloc_state(M)
-#define check_top_chunk(M,P)
-
-#else /* DEBUG */
-#define check_free_chunk(M,P) do_check_free_chunk(M,P)
-#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P)
-#define check_top_chunk(M,P) do_check_top_chunk(M,P)
-#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)
-#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P)
-#define check_malloc_state(M) do_check_malloc_state(M)
-
-static void do_check_any_chunk(mstate m, mchunkptr p);
-static void do_check_top_chunk(mstate m, mchunkptr p);
-static void do_check_mmapped_chunk(mstate m, mchunkptr p);
-static void do_check_inuse_chunk(mstate m, mchunkptr p);
-static void do_check_free_chunk(mstate m, mchunkptr p);
-static void do_check_malloced_chunk(mstate m, void* mem, size_t s);
-static void do_check_tree(mstate m, tchunkptr t);
-static void do_check_treebin(mstate m, bindex_t i);
-static void do_check_smallbin(mstate m, bindex_t i);
-static void do_check_malloc_state(mstate m);
-static int bin_find(mstate m, mchunkptr x);
-static size_t traverse_and_check(mstate m);
-#endif /* DEBUG */
-
-/* ---------------------------- Indexing Bins ---------------------------- */
-
-#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)
-#define small_index(s) (bindex_t)((s) >> SMALLBIN_SHIFT)
-#define small_index2size(i) ((i) << SMALLBIN_SHIFT)
-#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE))
-
-/* addressing by index. See above about smallbin repositioning */
-#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1])))
-#define treebin_at(M,i) (&((M)->treebins[i]))
-
-/* assign tree index for size S to variable I. Use x86 asm if possible */
-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-#define compute_tree_index(S, I)\
-{\
- unsigned int X = S >> TREEBIN_SHIFT;\
- if (X == 0)\
- I = 0;\
- else if (X > 0xFFFF)\
- I = NTREEBINS-1;\
- else {\
- unsigned int K = (unsigned) sizeof(X)*__CHAR_BIT__ - 1 - (unsigned) __builtin_clz(X); \
- I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
- }\
-}
-
-#elif defined (__INTEL_COMPILER)
-#define compute_tree_index(S, I)\
-{\
- size_t X = S >> TREEBIN_SHIFT;\
- if (X == 0)\
- I = 0;\
- else if (X > 0xFFFF)\
- I = NTREEBINS-1;\
- else {\
- unsigned int K = _bit_scan_reverse (X); \
- I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
- }\
-}
-
-#elif defined(_MSC_VER) && _MSC_VER>=1300
-#define compute_tree_index(S, I)\
-{\
- size_t X = S >> TREEBIN_SHIFT;\
- if (X == 0)\
- I = 0;\
- else if (X > 0xFFFF)\
- I = NTREEBINS-1;\
- else {\
- unsigned int K;\
- _BitScanReverse((DWORD *) &K, (DWORD) X);\
- I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
- }\
-}
-
-#else /* GNUC */
-#define compute_tree_index(S, I)\
-{\
- size_t X = S >> TREEBIN_SHIFT;\
- if (X == 0)\
- I = 0;\
- else if (X > 0xFFFF)\
- I = NTREEBINS-1;\
- else {\
- unsigned int Y = (unsigned int)X;\
- unsigned int N = ((Y - 0x100) >> 16) & 8;\
- unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\
- N += K;\
- N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\
- K = 14 - N + ((Y <<= K) >> 15);\
- I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\
- }\
-}
-#endif /* GNUC */
-
-/* Bit representing maximum resolved size in a treebin at i */
-#define bit_for_tree_index(i) \
- (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)
-
-/* Shift placing maximum resolved bit in a treebin at i as sign bit */
-#define leftshift_for_tree_index(i) \
- ((i == NTREEBINS-1)? 0 : \
- ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))
-
-/* The size of the smallest chunk held in bin with index i */
-#define minsize_for_tree_index(i) \
- ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \
- (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))
-
-
-/* ------------------------ Operations on bin maps ----------------------- */
-
-/* bit corresponding to given index */
-#define idx2bit(i) ((binmap_t)(1) << (i))
-
-/* Mark/Clear bits with given index */
-#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i))
-#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i))
-#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i))
-
-#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i))
-#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i))
-#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i))
-
-/* isolate the least set bit of a bitmap */
-#define least_bit(x) ((x) & -(x))
-
-/* mask with all bits to left of least bit of x on */
-#define left_bits(x) ((x<<1) | -(x<<1))
-
-/* mask with all bits to left of or equal to least bit of x on */
-#define same_or_left_bits(x) ((x) | -(x))
-
-/* index corresponding to given bit. Use x86 asm if possible */
-
-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-#define compute_bit2idx(X, I)\
-{\
- unsigned int J;\
- J = __builtin_ctz(X); \
- I = (bindex_t)J;\
-}
-
-#elif defined (__INTEL_COMPILER)
-#define compute_bit2idx(X, I)\
-{\
- unsigned int J;\
- J = _bit_scan_forward (X); \
- I = (bindex_t)J;\
-}
-
-#elif defined(_MSC_VER) && _MSC_VER>=1300
-#define compute_bit2idx(X, I)\
-{\
- unsigned int J;\
- _BitScanForward((DWORD *) &J, X);\
- I = (bindex_t)J;\
-}
-
-#elif USE_BUILTIN_FFS
-#define compute_bit2idx(X, I) I = ffs(X)-1
-
-#else
-#define compute_bit2idx(X, I)\
-{\
- unsigned int Y = X - 1;\
- unsigned int K = Y >> (16-4) & 16;\
- unsigned int N = K; Y >>= K;\
- N += K = Y >> (8-3) & 8; Y >>= K;\
- N += K = Y >> (4-2) & 4; Y >>= K;\
- N += K = Y >> (2-1) & 2; Y >>= K;\
- N += K = Y >> (1-0) & 1; Y >>= K;\
- I = (bindex_t)(N + Y);\
-}
-#endif /* GNUC */
-
-
-/* ----------------------- Runtime Check Support ------------------------- */
-
-/*
- For security, the main invariant is that malloc/free/etc never
- writes to a static address other than malloc_state, unless static
- malloc_state itself has been corrupted, which cannot occur via
- malloc (because of these checks). In essence this means that we
- believe all pointers, sizes, maps etc held in malloc_state, but
- check all of those linked or offsetted from other embedded data
- structures. These checks are interspersed with main code in a way
- that tends to minimize their run-time cost.
-
- When FOOTERS is defined, in addition to range checking, we also
- verify footer fields of inuse chunks, which can be used guarantee
- that the mstate controlling malloc/free is intact. This is a
- streamlined version of the approach described by William Robertson
- et al in "Run-time Detection of Heap-based Overflows" LISA'03
- http://www.usenix.org/events/lisa03/tech/robertson.html The footer
- of an inuse chunk holds the xor of its mstate and a random seed,
- that is checked upon calls to free() and realloc(). This is
- (probabalistically) unguessable from outside the program, but can be
- computed by any code successfully malloc'ing any chunk, so does not
- itself provide protection against code that has already broken
- security through some other means. Unlike Robertson et al, we
- always dynamically check addresses of all offset chunks (previous,
- next, etc). This turns out to be cheaper than relying on hashes.
-*/
-
-#if !INSECURE
-/* Check if address a is at least as high as any from MORECORE or MMAP */
-#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)
-/* Check if address of next chunk n is higher than base chunk p */
-#define ok_next(p, n) ((char*)(p) < (char*)(n))
-/* Check if p has inuse status */
-#define ok_inuse(p) is_inuse(p)
-/* Check if p has its pinuse bit on */
-#define ok_pinuse(p) pinuse(p)
-
-#else /* !INSECURE */
-#define ok_address(M, a) (1)
-#define ok_next(b, n) (1)
-#define ok_inuse(p) (1)
-#define ok_pinuse(p) (1)
-#endif /* !INSECURE */
-
-#if (FOOTERS && !INSECURE)
-/* Check if (alleged) mstate m has expected magic field */
-#define ok_magic(M) ((M)->magic == mparams.magic)
-#else /* (FOOTERS && !INSECURE) */
-#define ok_magic(M) (1)
-#endif /* (FOOTERS && !INSECURE) */
-
-/* In gcc, use __builtin_expect to minimize impact of checks */
-#if !INSECURE
-#if defined(__GNUC__) && __GNUC__ >= 3
-#define RTCHECK(e) __builtin_expect(e, 1)
-#else /* GNUC */
-#define RTCHECK(e) (e)
-#endif /* GNUC */
-#else /* !INSECURE */
-#define RTCHECK(e) (1)
-#endif /* !INSECURE */
-
-/* macros to set up inuse chunks with or without footers */
-
-#if !FOOTERS
-
-#define mark_inuse_foot(M,p,s)
-
-/* Macros for setting head/foot of non-mmapped chunks */
-
-/* Set cinuse bit and pinuse bit of next chunk */
-#define set_inuse(M,p,s)\
- ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
- ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
-
-/* Set cinuse and pinuse of this chunk and pinuse of next chunk */
-#define set_inuse_and_pinuse(M,p,s)\
- ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
- ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
-
-/* Set size, cinuse and pinuse bit of this chunk */
-#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
- ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))
-
-#else /* FOOTERS */
-
-/* Set foot of inuse chunk to be xor of mstate and seed */
-#define mark_inuse_foot(M,p,s)\
- (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))
-
-#define get_mstate_for(p)\
- ((mstate)(((mchunkptr)((char*)(p) +\
- (chunksize(p))))->prev_foot ^ mparams.magic))
-
-#define set_inuse(M,p,s)\
- ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
- (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \
- mark_inuse_foot(M,p,s))
-
-#define set_inuse_and_pinuse(M,p,s)\
- ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
- (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\
- mark_inuse_foot(M,p,s))
-
-#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
- ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
- mark_inuse_foot(M, p, s))
-
-#endif /* !FOOTERS */
-
-/* ---------------------------- setting mparams -------------------------- */
-
-#if LOCK_AT_FORK
-static void pre_fork(void) { ACQUIRE_LOCK(&(gm)->mutex); }
-static void post_fork_parent(void) { RELEASE_LOCK(&(gm)->mutex); }
-static void post_fork_child(void) { INITIAL_LOCK(&(gm)->mutex); }
-#endif /* LOCK_AT_FORK */
-
-/* Initialize mparams */
-static int init_mparams(void) {
-#ifdef NEED_GLOBAL_LOCK_INIT
- if (malloc_global_mutex_status <= 0)
- init_malloc_global_mutex();
-#endif
-
- ACQUIRE_MALLOC_GLOBAL_LOCK();
- if (mparams.magic == 0) {
- size_t magic;
- size_t psize;
- size_t gsize;
-
-#ifndef WIN32
- psize = malloc_getpagesize;
- gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize);
-#else /* WIN32 */
- {
- SYSTEM_INFO system_info;
- GetSystemInfo(&system_info);
- psize = system_info.dwPageSize;
- gsize = ((DEFAULT_GRANULARITY != 0)?
- DEFAULT_GRANULARITY : system_info.dwAllocationGranularity);
- }
-#endif /* WIN32 */
-
- /* Sanity-check configuration:
- size_t must be unsigned and as wide as pointer type.
- ints must be at least 4 bytes.
- alignment must be at least 8.
- Alignment, min chunk size, and page size must all be powers of 2.
- */
- if ((sizeof(size_t) != sizeof(char*)) ||
- (MAX_SIZE_T < MIN_CHUNK_SIZE) ||
- (sizeof(int) < 4) ||
- (MALLOC_ALIGNMENT < (size_t)8U) ||
- ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) ||
- ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) ||
- ((gsize & (gsize-SIZE_T_ONE)) != 0) ||
- ((psize & (psize-SIZE_T_ONE)) != 0))
- ABORT;
- mparams.granularity = gsize;
- mparams.page_size = psize;
- mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD;
- mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD;
-#if MORECORE_CONTIGUOUS
- mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT;
-#else /* MORECORE_CONTIGUOUS */
- mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT;
-#endif /* MORECORE_CONTIGUOUS */
-
-#if !ONLY_MSPACES
- /* Set up lock for main malloc area */
- gm->mflags = mparams.default_mflags;
- (void)INITIAL_LOCK(&gm->mutex);
-#endif
-#if LOCK_AT_FORK
- pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child);
-#endif
-
- {
-#if USE_DEV_RANDOM
- int fd;
- unsigned char buf[sizeof(size_t)];
- /* Try to use /dev/urandom, else fall back on using time */
- if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 &&
- read(fd, buf, sizeof(buf)) == sizeof(buf)) {
- magic = *((size_t *) buf);
- close(fd);
- }
- else
-#endif /* USE_DEV_RANDOM */
-#ifdef WIN32
- magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U);
-#elif defined(LACKS_TIME_H)
- magic = (size_t)&magic ^ (size_t)0x55555555U;
-#else
- magic = (size_t)(time(0) ^ (size_t)0x55555555U);
-#endif
- magic |= (size_t)8U; /* ensure nonzero */
- magic &= ~(size_t)7U; /* improve chances of fault for bad values */
- /* Until memory modes commonly available, use volatile-write */
- (*(volatile size_t *)(&(mparams.magic))) = magic;
- }
- }
-
- RELEASE_MALLOC_GLOBAL_LOCK();
- return 1;
-}
-
-/* support for mallopt */
-static int change_mparam(int param_number, int value) {
- size_t val;
- ensure_initialization();
- val = (value == -1)? MAX_SIZE_T : (size_t)value;
- switch(param_number) {
- case M_TRIM_THRESHOLD:
- mparams.trim_threshold = val;
- return 1;
- case M_GRANULARITY:
- if (val >= mparams.page_size && ((val & (val-1)) == 0)) {
- mparams.granularity = val;
- return 1;
- }
- else
- return 0;
- case M_MMAP_THRESHOLD:
- mparams.mmap_threshold = val;
- return 1;
- default:
- return 0;
- }
-}
-
-#if DEBUG
-/* ------------------------- Debugging Support --------------------------- */
-
-/* Check properties of any chunk, whether free, inuse, mmapped etc */
-static void do_check_any_chunk(mstate m, mchunkptr p) {
- assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
- assert(ok_address(m, p));
-}
-
-/* Check properties of top chunk */
-static void do_check_top_chunk(mstate m, mchunkptr p) {
- msegmentptr sp = segment_holding(m, (char*)p);
- size_t sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */
- assert(sp != 0);
- assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
- assert(ok_address(m, p));
- assert(sz == m->topsize);
- assert(sz > 0);
- assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);
- assert(pinuse(p));
- assert(!pinuse(chunk_plus_offset(p, sz)));
-}
-
-/* Check properties of (inuse) mmapped chunks */
-static void do_check_mmapped_chunk(mstate m, mchunkptr p) {
- size_t sz = chunksize(p);
- size_t len = (sz + (p->prev_foot) + MMAP_FOOT_PAD);
- assert(is_mmapped(p));
- assert(use_mmap(m));
- assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
- assert(ok_address(m, p));
- assert(!is_small(sz));
- assert((len & (mparams.page_size-SIZE_T_ONE)) == 0);
- assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD);
- assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0);
-}
-
-/* Check properties of inuse chunks */
-static void do_check_inuse_chunk(mstate m, mchunkptr p) {
- do_check_any_chunk(m, p);
- assert(is_inuse(p));
- assert(next_pinuse(p));
- /* If not pinuse and not mmapped, previous chunk has OK offset */
- assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p);
- if (is_mmapped(p))
- do_check_mmapped_chunk(m, p);
-}
-
-/* Check properties of free chunks */
-static void do_check_free_chunk(mstate m, mchunkptr p) {
- size_t sz = chunksize(p);
- mchunkptr next = chunk_plus_offset(p, sz);
- do_check_any_chunk(m, p);
- assert(!is_inuse(p));
- assert(!next_pinuse(p));
- assert (!is_mmapped(p));
- if (p != m->dv && p != m->top) {
- if (sz >= MIN_CHUNK_SIZE) {
- assert((sz & CHUNK_ALIGN_MASK) == 0);
- assert(is_aligned(chunk2mem(p)));
- assert(next->prev_foot == sz);
- assert(pinuse(p));
- assert (next == m->top || is_inuse(next));
- assert(p->fd->bk == p);
- assert(p->bk->fd == p);
- }
- else /* markers are always of size SIZE_T_SIZE */
- assert(sz == SIZE_T_SIZE);
- }
-}
-
-/* Check properties of malloced chunks at the point they are malloced */
-static void do_check_malloced_chunk(mstate m, void* mem, size_t s) {
- if (mem != 0) {
- mchunkptr p = mem2chunk(mem);
- size_t sz = p->head & ~INUSE_BITS;
- do_check_inuse_chunk(m, p);
- assert((sz & CHUNK_ALIGN_MASK) == 0);
- assert(sz >= MIN_CHUNK_SIZE);
- assert(sz >= s);
- /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */
- assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE));
- }
-}
-
-/* Check a tree and its subtrees. */
-static void do_check_tree(mstate m, tchunkptr t) {
- tchunkptr head = 0;
- tchunkptr u = t;
- bindex_t tindex = t->index;
- size_t tsize = chunksize(t);
- bindex_t idx;
- compute_tree_index(tsize, idx);
- assert(tindex == idx);
- assert(tsize >= MIN_LARGE_SIZE);
- assert(tsize >= minsize_for_tree_index(idx));
- assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));
-
- do { /* traverse through chain of same-sized nodes */
- do_check_any_chunk(m, ((mchunkptr)u));
- assert(u->index == tindex);
- assert(chunksize(u) == tsize);
- assert(!is_inuse(u));
- assert(!next_pinuse(u));
- assert(u->fd->bk == u);
- assert(u->bk->fd == u);
- if (u->parent == 0) {
- assert(u->child[0] == 0);
- assert(u->child[1] == 0);
- }
- else {
- assert(head == 0); /* only one node on chain has parent */
- head = u;
- assert(u->parent != u);
- assert (u->parent->child[0] == u ||
- u->parent->child[1] == u ||
- *((tbinptr*)(u->parent)) == u);
- if (u->child[0] != 0) {
- assert(u->child[0]->parent == u);
- assert(u->child[0] != u);
- do_check_tree(m, u->child[0]);
- }
- if (u->child[1] != 0) {
- assert(u->child[1]->parent == u);
- assert(u->child[1] != u);
- do_check_tree(m, u->child[1]);
- }
- if (u->child[0] != 0 && u->child[1] != 0) {
- assert(chunksize(u->child[0]) < chunksize(u->child[1]));
- }
- }
- u = u->fd;
- } while (u != t);
- assert(head != 0);
-}
-
-/* Check all the chunks in a treebin. */
-static void do_check_treebin(mstate m, bindex_t i) {
- tbinptr* tb = treebin_at(m, i);
- tchunkptr t = *tb;
- int empty = (m->treemap & (1U << i)) == 0;
- if (t == 0)
- assert(empty);
- if (!empty)
- do_check_tree(m, t);
-}
-
-/* Check all the chunks in a smallbin. */
-static void do_check_smallbin(mstate m, bindex_t i) {
- sbinptr b = smallbin_at(m, i);
- mchunkptr p = b->bk;
- unsigned int empty = (m->smallmap & (1U << i)) == 0;
- if (p == b)
- assert(empty);
- if (!empty) {
- for (; p != b; p = p->bk) {
- size_t size = chunksize(p);
- mchunkptr q;
- /* each chunk claims to be free */
- do_check_free_chunk(m, p);
- /* chunk belongs in bin */
- assert(small_index(size) == i);
- assert(p->bk == b || chunksize(p->bk) == chunksize(p));
- /* chunk is followed by an inuse chunk */
- q = next_chunk(p);
- if (q->head != FENCEPOST_HEAD)
- do_check_inuse_chunk(m, q);
- }
- }
-}
-
-/* Find x in a bin. Used in other check functions. */
-static int bin_find(mstate m, mchunkptr x) {
- size_t size = chunksize(x);
- if (is_small(size)) {
- bindex_t sidx = small_index(size);
- sbinptr b = smallbin_at(m, sidx);
- if (smallmap_is_marked(m, sidx)) {
- mchunkptr p = b;
- do {
- if (p == x)
- return 1;
- } while ((p = p->fd) != b);
- }
- }
- else {
- bindex_t tidx;
- compute_tree_index(size, tidx);
- if (treemap_is_marked(m, tidx)) {
- tchunkptr t = *treebin_at(m, tidx);
- size_t sizebits = size << leftshift_for_tree_index(tidx);
- while (t != 0 && chunksize(t) != size) {
- t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
- sizebits <<= 1;
- }
- if (t != 0) {
- tchunkptr u = t;
- do {
- if (u == (tchunkptr)x)
- return 1;
- } while ((u = u->fd) != t);
- }
- }
- }
- return 0;
-}
-
-/* Traverse each chunk and check it; return total */
-static size_t traverse_and_check(mstate m) {
- size_t sum = 0;
- if (is_initialized(m)) {
- msegmentptr s = &m->seg;
- sum += m->topsize + TOP_FOOT_SIZE;
- while (s != 0) {
- mchunkptr q = align_as_chunk(s->base);
- mchunkptr lastq = 0;
- assert(pinuse(q));
- while (segment_holds(s, q) &&
- q != m->top && q->head != FENCEPOST_HEAD) {
- sum += chunksize(q);
- if (is_inuse(q)) {
- assert(!bin_find(m, q));
- do_check_inuse_chunk(m, q);
- }
- else {
- assert(q == m->dv || bin_find(m, q));
- assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */
- do_check_free_chunk(m, q);
- }
- lastq = q;
- q = next_chunk(q);
- }
- s = s->next;
- }
- }
- return sum;
-}
-
-
-/* Check all properties of malloc_state. */
-static void do_check_malloc_state(mstate m) {
- bindex_t i;
- size_t total;
- /* check bins */
- for (i = 0; i < NSMALLBINS; ++i)
- do_check_smallbin(m, i);
- for (i = 0; i < NTREEBINS; ++i)
- do_check_treebin(m, i);
-
- if (m->dvsize != 0) { /* check dv chunk */
- do_check_any_chunk(m, m->dv);
- assert(m->dvsize == chunksize(m->dv));
- assert(m->dvsize >= MIN_CHUNK_SIZE);
- assert(bin_find(m, m->dv) == 0);
- }
-
- if (m->top != 0) { /* check top chunk */
- do_check_top_chunk(m, m->top);
- /*assert(m->topsize == chunksize(m->top)); redundant */
- assert(m->topsize > 0);
- assert(bin_find(m, m->top) == 0);
- }
-
- total = traverse_and_check(m);
- assert(total <= m->footprint);
- assert(m->footprint <= m->max_footprint);
-}
-#endif /* DEBUG */
-
-/* ----------------------------- statistics ------------------------------ */
-
-#if !NO_MALLINFO
-static struct mallinfo internal_mallinfo(mstate m) {
- struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- ensure_initialization();
- if (!PREACTION(m)) {
- check_malloc_state(m);
- if (is_initialized(m)) {
- size_t nfree = SIZE_T_ONE; /* top always free */
- size_t mfree = m->topsize + TOP_FOOT_SIZE;
- size_t sum = mfree;
- msegmentptr s = &m->seg;
- while (s != 0) {
- mchunkptr q = align_as_chunk(s->base);
- while (segment_holds(s, q) &&
- q != m->top && q->head != FENCEPOST_HEAD) {
- size_t sz = chunksize(q);
- sum += sz;
- if (!is_inuse(q)) {
- mfree += sz;
- ++nfree;
- }
- q = next_chunk(q);
- }
- s = s->next;
- }
-
- nm.arena = sum;
- nm.ordblks = nfree;
- nm.hblkhd = m->footprint - sum;
- nm.usmblks = m->max_footprint;
- nm.uordblks = m->footprint - mfree;
- nm.fordblks = mfree;
- nm.keepcost = m->topsize;
- }
-
- POSTACTION(m);
- }
- return nm;
-}
-#endif /* !NO_MALLINFO */
-
-#if !NO_MALLOC_STATS
-static void internal_malloc_stats(mstate m) {
- ensure_initialization();
- if (!PREACTION(m)) {
- size_t maxfp = 0;
- size_t fp = 0;
- size_t used = 0;
- check_malloc_state(m);
- if (is_initialized(m)) {
- msegmentptr s = &m->seg;
- maxfp = m->max_footprint;
- fp = m->footprint;
- used = fp - (m->topsize + TOP_FOOT_SIZE);
-
- while (s != 0) {
- mchunkptr q = align_as_chunk(s->base);
- while (segment_holds(s, q) &&
- q != m->top && q->head != FENCEPOST_HEAD) {
- if (!is_inuse(q))
- used -= chunksize(q);
- q = next_chunk(q);
- }
- s = s->next;
- }
- }
- POSTACTION(m); /* drop lock */
- fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp));
- fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp));
- fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used));
- }
-}
-#endif /* NO_MALLOC_STATS */
-
-/* ----------------------- Operations on smallbins ----------------------- */
-
-/*
- Various forms of linking and unlinking are defined as macros. Even
- the ones for trees, which are very long but have very short typical
- paths. This is ugly but reduces reliance on inlining support of
- compilers.
-*/
-
-/* Link a free chunk into a smallbin */
-#define insert_small_chunk(M, P, S) {\
- bindex_t I = small_index(S);\
- mchunkptr B = smallbin_at(M, I);\
- mchunkptr F = B;\
- assert(S >= MIN_CHUNK_SIZE);\
- if (!smallmap_is_marked(M, I))\
- mark_smallmap(M, I);\
- else if (RTCHECK(ok_address(M, B->fd)))\
- F = B->fd;\
- else {\
- CORRUPTION_ERROR_ACTION(M);\
- }\
- B->fd = P;\
- F->bk = P;\
- P->fd = F;\
- P->bk = B;\
-}
-
-/* Unlink a chunk from a smallbin */
-#define unlink_small_chunk(M, P, S) {\
- mchunkptr F = P->fd;\
- mchunkptr B = P->bk;\
- bindex_t I = small_index(S);\
- assert(P != B);\
- assert(P != F);\
- assert(chunksize(P) == small_index2size(I));\
- if (RTCHECK(F == smallbin_at(M,I) || (ok_address(M, F) && F->bk == P))) { \
- if (B == F) {\
- clear_smallmap(M, I);\
- }\
- else if (RTCHECK(B == smallbin_at(M,I) ||\
- (ok_address(M, B) && B->fd == P))) {\
- F->bk = B;\
- B->fd = F;\
- }\
- else {\
- CORRUPTION_ERROR_ACTION(M);\
- }\
- }\
- else {\
- CORRUPTION_ERROR_ACTION(M);\
- }\
-}
-
-/* Unlink the first chunk from a smallbin */
-#define unlink_first_small_chunk(M, B, P, I) {\
- mchunkptr F = P->fd;\
- assert(P != B);\
- assert(P != F);\
- assert(chunksize(P) == small_index2size(I));\
- if (B == F) {\
- clear_smallmap(M, I);\
- }\
- else if (RTCHECK(ok_address(M, F) && F->bk == P)) {\
- F->bk = B;\
- B->fd = F;\
- }\
- else {\
- CORRUPTION_ERROR_ACTION(M);\
- }\
-}
-
-/* Replace dv node, binning the old one */
-/* Used only when dvsize known to be small */
-#define replace_dv(M, P, S) {\
- size_t DVS = M->dvsize;\
- assert(is_small(DVS));\
- if (DVS != 0) {\
- mchunkptr DV = M->dv;\
- insert_small_chunk(M, DV, DVS);\
- }\
- M->dvsize = S;\
- M->dv = P;\
-}
-
-/* ------------------------- Operations on trees ------------------------- */
-
-/* Insert chunk into tree */
-#define insert_large_chunk(M, X, S) {\
- tbinptr* H;\
- bindex_t I;\
- compute_tree_index(S, I);\
- H = treebin_at(M, I);\
- X->index = I;\
- X->child[0] = X->child[1] = 0;\
- if (!treemap_is_marked(M, I)) {\
- mark_treemap(M, I);\
- *H = X;\
- X->parent = (tchunkptr)H;\
- X->fd = X->bk = X;\
- }\
- else {\
- tchunkptr T = *H;\
- size_t K = S << leftshift_for_tree_index(I);\
- for (;;) {\
- if (chunksize(T) != S) {\
- tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\
- K <<= 1;\
- if (*C != 0)\
- T = *C;\
- else if (RTCHECK(ok_address(M, C))) {\
- *C = X;\
- X->parent = T;\
- X->fd = X->bk = X;\
- break;\
- }\
- else {\
- CORRUPTION_ERROR_ACTION(M);\
- break;\
- }\
- }\
- else {\
- tchunkptr F = T->fd;\
- if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\
- T->fd = F->bk = X;\
- X->fd = F;\
- X->bk = T;\
- X->parent = 0;\
- break;\
- }\
- else {\
- CORRUPTION_ERROR_ACTION(M);\
- break;\
- }\
- }\
- }\
- }\
-}
-
-/*
- Unlink steps:
-
- 1. If x is a chained node, unlink it from its same-sized fd/bk links
- and choose its bk node as its replacement.
- 2. If x was the last node of its size, but not a leaf node, it must
- be replaced with a leaf node (not merely one with an open left or
- right), to make sure that lefts and rights of descendents
- correspond properly to bit masks. We use the rightmost descendent
- of x. We could use any other leaf, but this is easy to locate and
- tends to counteract removal of leftmosts elsewhere, and so keeps
- paths shorter than minimally guaranteed. This doesn't loop much
- because on average a node in a tree is near the bottom.
- 3. If x is the base of a chain (i.e., has parent links) relink
- x's parent and children to x's replacement (or null if none).
-*/
-
-#define unlink_large_chunk(M, X) {\
- tchunkptr XP = X->parent;\
- tchunkptr R;\
- if (X->bk != X) {\
- tchunkptr F = X->fd;\
- R = X->bk;\
- if (RTCHECK(ok_address(M, F) && F->bk == X && R->fd == X)) {\
- F->bk = R;\
- R->fd = F;\
- }\
- else {\
- CORRUPTION_ERROR_ACTION(M);\
- }\
- }\
- else {\
- tchunkptr* RP;\
- if (((R = *(RP = &(X->child[1]))) != 0) ||\
- ((R = *(RP = &(X->child[0]))) != 0)) {\
- tchunkptr* CP;\
- while ((*(CP = &(R->child[1])) != 0) ||\
- (*(CP = &(R->child[0])) != 0)) {\
- R = *(RP = CP);\
- }\
- if (RTCHECK(ok_address(M, RP)))\
- *RP = 0;\
- else {\
- CORRUPTION_ERROR_ACTION(M);\
- }\
- }\
- }\
- if (XP != 0) {\
- tbinptr* H = treebin_at(M, X->index);\
- if (X == *H) {\
- if ((*H = R) == 0) \
- clear_treemap(M, X->index);\
- }\
- else if (RTCHECK(ok_address(M, XP))) {\
- if (XP->child[0] == X) \
- XP->child[0] = R;\
- else \
- XP->child[1] = R;\
- }\
- else\
- CORRUPTION_ERROR_ACTION(M);\
- if (R != 0) {\
- if (RTCHECK(ok_address(M, R))) {\
- tchunkptr C0, C1;\
- R->parent = XP;\
- if ((C0 = X->child[0]) != 0) {\
- if (RTCHECK(ok_address(M, C0))) {\
- R->child[0] = C0;\
- C0->parent = R;\
- }\
- else\
- CORRUPTION_ERROR_ACTION(M);\
- }\
- if ((C1 = X->child[1]) != 0) {\
- if (RTCHECK(ok_address(M, C1))) {\
- R->child[1] = C1;\
- C1->parent = R;\
- }\
- else\
- CORRUPTION_ERROR_ACTION(M);\
- }\
- }\
- else\
- CORRUPTION_ERROR_ACTION(M);\
- }\
- }\
-}
-
-/* Relays to large vs small bin operations */
-
-#define insert_chunk(M, P, S)\
- if (is_small(S)) insert_small_chunk(M, P, S)\
- else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }
-
-#define unlink_chunk(M, P, S)\
- if (is_small(S)) unlink_small_chunk(M, P, S)\
- else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }
-
-
-/* Relays to internal calls to malloc/free from realloc, memalign etc */
-
-#if ONLY_MSPACES
-#define internal_malloc(m, b) mspace_malloc(m, b)
-#define internal_free(m, mem) mspace_free(m,mem);
-#else /* ONLY_MSPACES */
-#if MSPACES
-#define internal_malloc(m, b)\
- ((m == gm)? dlmalloc(b) : mspace_malloc(m, b))
-#define internal_free(m, mem)\
- if (m == gm) dlfree(mem); else mspace_free(m,mem);
-#else /* MSPACES */
-#define internal_malloc(m, b) dlmalloc(b)
-#define internal_free(m, mem) dlfree(mem)
-#endif /* MSPACES */
-#endif /* ONLY_MSPACES */
-
-/* ----------------------- Direct-mmapping chunks ----------------------- */
-
-/*
- Directly mmapped chunks are set up with an offset to the start of
- the mmapped region stored in the prev_foot field of the chunk. This
- allows reconstruction of the required argument to MUNMAP when freed,
- and also allows adjustment of the returned chunk to meet alignment
- requirements (especially in memalign).
-*/
-
-/* Malloc using mmap */
-static void* mmap_alloc(mstate m, size_t nb) {
- size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
- if (m->footprint_limit != 0) {
- size_t fp = m->footprint + mmsize;
- if (fp <= m->footprint || fp > m->footprint_limit)
- return 0;
- }
- if (mmsize > nb) { /* Check for wrap around 0 */
- char* mm = (char*)(CALL_DIRECT_MMAP(mmsize));
- if (mm != CMFAIL) {
- size_t offset = align_offset(chunk2mem(mm));
- size_t psize = mmsize - offset - MMAP_FOOT_PAD;
- mchunkptr p = (mchunkptr)(mm + offset);
- p->prev_foot = offset;
- p->head = psize;
- mark_inuse_foot(m, p, psize);
- chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD;
- chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0;
-
- if (m->least_addr == 0 || mm < m->least_addr)
- m->least_addr = mm;
- if ((m->footprint += mmsize) > m->max_footprint)
- m->max_footprint = m->footprint;
- assert(is_aligned(chunk2mem(p)));
- check_mmapped_chunk(m, p);
- return chunk2mem(p);
- }
- }
- return 0;
-}
-
-/* Realloc using mmap */
-static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) {
- size_t oldsize = chunksize(oldp);
- (void)flags; /* placate people compiling -Wunused */
- if (is_small(nb)) /* Can't shrink mmap regions below small size */
- return 0;
- /* Keep old chunk if big enough but not too big */
- if (oldsize >= nb + SIZE_T_SIZE &&
- (oldsize - nb) <= (mparams.granularity << 1))
- return oldp;
- else {
- size_t offset = oldp->prev_foot;
- size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;
- size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
- char* cp = (char*)CALL_MREMAP((char*)oldp - offset,
- oldmmsize, newmmsize, flags);
- if (cp != CMFAIL) {
- mchunkptr newp = (mchunkptr)(cp + offset);
- size_t psize = newmmsize - offset - MMAP_FOOT_PAD;
- newp->head = psize;
- mark_inuse_foot(m, newp, psize);
- chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;
- chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0;
-
- if (cp < m->least_addr)
- m->least_addr = cp;
- if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)
- m->max_footprint = m->footprint;
- check_mmapped_chunk(m, newp);
- return newp;
- }
- }
- return 0;
-}
-
-
-/* -------------------------- mspace management -------------------------- */
-
-/* Initialize top chunk and its size */
-static void init_top(mstate m, mchunkptr p, size_t psize) {
- /* Ensure alignment */
- size_t offset = align_offset(chunk2mem(p));
- p = (mchunkptr)((char*)p + offset);
- psize -= offset;
-
- m->top = p;
- m->topsize = psize;
- p->head = psize | PINUSE_BIT;
- /* set size of fake trailing chunk holding overhead space only once */
- chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;
- m->trim_check = mparams.trim_threshold; /* reset on each update */
-}
-
-/* Initialize bins for a new mstate that is otherwise zeroed out */
-static void init_bins(mstate m) {
- /* Establish circular links for smallbins */
- bindex_t i;
- for (i = 0; i < NSMALLBINS; ++i) {
- sbinptr bin = smallbin_at(m,i);
- bin->fd = bin->bk = bin;
- }
-}
-
-#if PROCEED_ON_ERROR
-
-/* default corruption action */
-static void reset_on_error(mstate m) {
- int i;
- ++malloc_corruption_error_count;
- /* Reinitialize fields to forget about all memory */
- m->smallmap = m->treemap = 0;
- m->dvsize = m->topsize = 0;
- m->seg.base = 0;
- m->seg.size = 0;
- m->seg.next = 0;
- m->top = m->dv = 0;
- for (i = 0; i < NTREEBINS; ++i)
- *treebin_at(m, i) = 0;
- init_bins(m);
-}
-#endif /* PROCEED_ON_ERROR */
-
-/* Allocate chunk and prepend remainder with chunk in successor base. */
-static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
- size_t nb) {
- mchunkptr p = align_as_chunk(newbase);
- mchunkptr oldfirst = align_as_chunk(oldbase);
- size_t psize = (char*)oldfirst - (char*)p;
- mchunkptr q = chunk_plus_offset(p, nb);
- size_t qsize = psize - nb;
- set_size_and_pinuse_of_inuse_chunk(m, p, nb);
-
- assert((char*)oldfirst > (char*)q);
- assert(pinuse(oldfirst));
- assert(qsize >= MIN_CHUNK_SIZE);
-
- /* consolidate remainder with first chunk of old base */
- if (oldfirst == m->top) {
- size_t tsize = m->topsize += qsize;
- m->top = q;
- q->head = tsize | PINUSE_BIT;
- check_top_chunk(m, q);
- }
- else if (oldfirst == m->dv) {
- size_t dsize = m->dvsize += qsize;
- m->dv = q;
- set_size_and_pinuse_of_free_chunk(q, dsize);
- }
- else {
- if (!is_inuse(oldfirst)) {
- size_t nsize = chunksize(oldfirst);
- unlink_chunk(m, oldfirst, nsize);
- oldfirst = chunk_plus_offset(oldfirst, nsize);
- qsize += nsize;
- }
- set_free_with_pinuse(q, qsize, oldfirst);
- insert_chunk(m, q, qsize);
- check_free_chunk(m, q);
- }
-
- check_malloced_chunk(m, chunk2mem(p), nb);
- return chunk2mem(p);
-}
-
-/* Add a segment to hold a new noncontiguous region */
-static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {
- /* Determine locations and sizes of segment, fenceposts, old top */
- char* old_top = (char*)m->top;
- msegmentptr oldsp = segment_holding(m, old_top);
- char* old_end = oldsp->base + oldsp->size;
- size_t ssize = pad_request(sizeof(struct malloc_segment));
- char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
- size_t offset = align_offset(chunk2mem(rawsp));
- char* asp = rawsp + offset;
- char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp;
- mchunkptr sp = (mchunkptr)csp;
- msegmentptr ss = (msegmentptr)(chunk2mem(sp));
- mchunkptr tnext = chunk_plus_offset(sp, ssize);
- mchunkptr p = tnext;
- int nfences = 0;
-
- /* reset top to new space */
- init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
-
- /* Set up segment record */
- assert(is_aligned(ss));
- set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);
- *ss = m->seg; /* Push current record */
- m->seg.base = tbase;
- m->seg.size = tsize;
- m->seg.sflags = mmapped;
- m->seg.next = ss;
-
- /* Insert trailing fenceposts */
- for (;;) {
- mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);
- p->head = FENCEPOST_HEAD;
- ++nfences;
- if ((char*)(&(nextp->head)) < old_end)
- p = nextp;
- else
- break;
- }
- assert(nfences >= 2);
-
- /* Insert the rest of old top into a bin as an ordinary free chunk */
- if (csp != old_top) {
- mchunkptr q = (mchunkptr)old_top;
- size_t psize = csp - old_top;
- mchunkptr tn = chunk_plus_offset(q, psize);
- set_free_with_pinuse(q, psize, tn);
- insert_chunk(m, q, psize);
- }
-
- check_top_chunk(m, m->top);
-}
-
-/* -------------------------- System allocation -------------------------- */
-
-/* Get memory from system using MORECORE or MMAP */
-static void* sys_alloc(mstate m, size_t nb) {
- char* tbase = CMFAIL;
- size_t tsize = 0;
- flag_t mmap_flag = 0;
- size_t asize; /* allocation size */
-
- ensure_initialization();
-
- /* Directly map large chunks, but only if already initialized */
- if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize != 0) {
- void* mem = mmap_alloc(m, nb);
- if (mem != 0)
- return mem;
- }
-
- asize = granularity_align(nb + SYS_ALLOC_PADDING);
- if (asize <= nb)
- return 0; /* wraparound */
- if (m->footprint_limit != 0) {
- size_t fp = m->footprint + asize;
- if (fp <= m->footprint || fp > m->footprint_limit)
- return 0;
- }
-
- /*
- Try getting memory in any of three ways (in most-preferred to
- least-preferred order):
- 1. A call to MORECORE that can normally contiguously extend memory.
- (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or
- or main space is mmapped or a previous contiguous call failed)
- 2. A call to MMAP new space (disabled if not HAVE_MMAP).
- Note that under the default settings, if MORECORE is unable to
- fulfill a request, and HAVE_MMAP is true, then mmap is
- used as a noncontiguous system allocator. This is a useful backup
- strategy for systems with holes in address spaces -- in this case
- sbrk cannot contiguously expand the heap, but mmap may be able to
- find space.
- 3. A call to MORECORE that cannot usually contiguously extend memory.
- (disabled if not HAVE_MORECORE)
-
- In all cases, we need to request enough bytes from system to ensure
- we can malloc nb bytes upon success, so pad with enough space for
- top_foot, plus alignment-pad to make sure we don't lose bytes if
- not on boundary, and round this up to a granularity unit.
- */
-
- if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) {
- char* br = CMFAIL;
- size_t ssize = asize; /* sbrk call size */
- msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top);
- ACQUIRE_MALLOC_GLOBAL_LOCK();
-
- if (ss == 0) { /* First time through or recovery */
- char* base = (char*)CALL_MORECORE(0);
- if (base != CMFAIL) {
- size_t fp;
- /* Adjust to end on a page boundary */
- if (!is_page_aligned(base))
- ssize += (page_align((size_t)base) - (size_t)base);
- fp = m->footprint + ssize; /* recheck limits */
- if (ssize > nb && ssize < HALF_MAX_SIZE_T &&
- (m->footprint_limit == 0 ||
- (fp > m->footprint && fp <= m->footprint_limit)) &&
- (br = (char*)(CALL_MORECORE(ssize))) == base) {
- tbase = base;
- tsize = ssize;
- }
- }
- }
- else {
- /* Subtract out existing available top space from MORECORE request. */
- ssize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING);
- /* Use mem here only if it did continuously extend old space */
- if (ssize < HALF_MAX_SIZE_T &&
- (br = (char*)(CALL_MORECORE(ssize))) == ss->base+ss->size) {
- tbase = br;
- tsize = ssize;
- }
- }
-
- if (tbase == CMFAIL) { /* Cope with partial failure */
- if (br != CMFAIL) { /* Try to use/extend the space we did get */
- if (ssize < HALF_MAX_SIZE_T &&
- ssize < nb + SYS_ALLOC_PADDING) {
- size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - ssize);
- if (esize < HALF_MAX_SIZE_T) {
- char* end = (char*)CALL_MORECORE(esize);
- if (end != CMFAIL)
- ssize += esize;
- else { /* Can't use; try to release */
- (void) CALL_MORECORE(-ssize);
- br = CMFAIL;
- }
- }
- }
- }
- if (br != CMFAIL) { /* Use the space we did get */
- tbase = br;
- tsize = ssize;
- }
- else
- disable_contiguous(m); /* Don't try contiguous path in the future */
- }
-
- RELEASE_MALLOC_GLOBAL_LOCK();
- }
-
- if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */
- char* mp = (char*)(CALL_MMAP(asize));
- if (mp != CMFAIL) {
- tbase = mp;
- tsize = asize;
- mmap_flag = USE_MMAP_BIT;
- }
- }
-
- if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */
- if (asize < HALF_MAX_SIZE_T) {
- char* br = CMFAIL;
- char* end = CMFAIL;
- ACQUIRE_MALLOC_GLOBAL_LOCK();
- br = (char*)(CALL_MORECORE(asize));
- end = (char*)(CALL_MORECORE(0));
- RELEASE_MALLOC_GLOBAL_LOCK();
- if (br != CMFAIL && end != CMFAIL && br < end) {
- size_t ssize = end - br;
- if (ssize > nb + TOP_FOOT_SIZE) {
- tbase = br;
- tsize = ssize;
- }
- }
- }
- }
-
- if (tbase != CMFAIL) {
-
- if ((m->footprint += tsize) > m->max_footprint)
- m->max_footprint = m->footprint;
-
- if (!is_initialized(m)) { /* first-time initialization */
- if (m->least_addr == 0 || tbase < m->least_addr)
- m->least_addr = tbase;
- m->seg.base = tbase;
- m->seg.size = tsize;
- m->seg.sflags = mmap_flag;
- m->magic = mparams.magic;
- m->release_checks = MAX_RELEASE_CHECK_RATE;
- init_bins(m);
-#if !ONLY_MSPACES
- if (is_global(m))
- init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
- else
-#endif
- {
- /* Offset top by embedded malloc_state */
- mchunkptr mn = next_chunk(mem2chunk(m));
- init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE);
- }
- }
-
- else {
- /* Try to merge with an existing segment */
- msegmentptr sp = &m->seg;
- /* Only consider most recent segment if traversal suppressed */
- while (sp != 0 && tbase != sp->base + sp->size)
- sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
- if (sp != 0 &&
- !is_extern_segment(sp) &&
- (sp->sflags & USE_MMAP_BIT) == mmap_flag &&
- segment_holds(sp, m->top)) { /* append */
- sp->size += tsize;
- init_top(m, m->top, m->topsize + tsize);
- }
- else {
- if (tbase < m->least_addr)
- m->least_addr = tbase;
- sp = &m->seg;
- while (sp != 0 && sp->base != tbase + tsize)
- sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
- if (sp != 0 &&
- !is_extern_segment(sp) &&
- (sp->sflags & USE_MMAP_BIT) == mmap_flag) {
- char* oldbase = sp->base;
- sp->base = tbase;
- sp->size += tsize;
- return prepend_alloc(m, tbase, oldbase, nb);
- }
- else
- add_segment(m, tbase, tsize, mmap_flag);
- }
- }
-
- if (nb < m->topsize) { /* Allocate from new or extended top space */
- size_t rsize = m->topsize -= nb;
- mchunkptr p = m->top;
- mchunkptr r = m->top = chunk_plus_offset(p, nb);
- r->head = rsize | PINUSE_BIT;
- set_size_and_pinuse_of_inuse_chunk(m, p, nb);
- check_top_chunk(m, m->top);
- check_malloced_chunk(m, chunk2mem(p), nb);
- return chunk2mem(p);
- }
- }
-
- MALLOC_FAILURE_ACTION;
- return 0;
-}
-
-/* ----------------------- system deallocation -------------------------- */
-
-/* Unmap and unlink any mmapped segments that don't contain used chunks */
-static size_t release_unused_segments(mstate m) {
- size_t released = 0;
- int nsegs = 0;
- msegmentptr pred = &m->seg;
- msegmentptr sp = pred->next;
- while (sp != 0) {
- char* base = sp->base;
- size_t size = sp->size;
- msegmentptr next = sp->next;
- ++nsegs;
- if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {
- mchunkptr p = align_as_chunk(base);
- size_t psize = chunksize(p);
- /* Can unmap if first chunk holds entire segment and not pinned */
- if (!is_inuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) {
- tchunkptr tp = (tchunkptr)p;
- assert(segment_holds(sp, (char*)sp));
- if (p == m->dv) {
- m->dv = 0;
- m->dvsize = 0;
- }
- else {
- unlink_large_chunk(m, tp);
- }
- if (CALL_MUNMAP(base, size) == 0) {
- released += size;
- m->footprint -= size;
- /* unlink obsoleted record */
- sp = pred;
- sp->next = next;
- }
- else { /* back out if cannot unmap */
- insert_large_chunk(m, tp, psize);
- }
- }
- }
- if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */
- break;
- pred = sp;
- sp = next;
- }
- /* Reset check counter */
- m->release_checks = (((size_t) nsegs > (size_t) MAX_RELEASE_CHECK_RATE)?
- (size_t) nsegs : (size_t) MAX_RELEASE_CHECK_RATE);
- return released;
-}
-
-static int sys_trim(mstate m, size_t pad) {
- size_t released = 0;
- ensure_initialization();
- if (pad < MAX_REQUEST && is_initialized(m)) {
- pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */
-
- if (m->topsize > pad) {
- /* Shrink top space in granularity-size units, keeping at least one */
- size_t unit = mparams.granularity;
- size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit -
- SIZE_T_ONE) * unit;
- msegmentptr sp = segment_holding(m, (char*)m->top);
-
- if (!is_extern_segment(sp)) {
- if (is_mmapped_segment(sp)) {
- if (HAVE_MMAP &&
- sp->size >= extra &&
- !has_segment_link(m, sp)) { /* can't shrink if pinned */
- size_t newsize = sp->size - extra;
- (void)newsize; /* placate people compiling -Wunused-variable */
- /* Prefer mremap, fall back to munmap */
- if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) ||
- (CALL_MUNMAP(sp->base + newsize, extra) == 0)) {
- released = extra;
- }
- }
- }
- else if (HAVE_MORECORE) {
- if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
- extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;
- ACQUIRE_MALLOC_GLOBAL_LOCK();
- {
- /* Make sure end of memory is where we last set it. */
- char* old_br = (char*)(CALL_MORECORE(0));
- if (old_br == sp->base + sp->size) {
- char* rel_br = (char*)(CALL_MORECORE(-extra));
- char* new_br = (char*)(CALL_MORECORE(0));
- if (rel_br != CMFAIL && new_br < old_br)
- released = old_br - new_br;
- }
- }
- RELEASE_MALLOC_GLOBAL_LOCK();
- }
- }
-
- if (released != 0) {
- sp->size -= released;
- m->footprint -= released;
- init_top(m, m->top, m->topsize - released);
- check_top_chunk(m, m->top);
- }
- }
-
- /* Unmap any unused mmapped segments */
- if (HAVE_MMAP)
- released += release_unused_segments(m);
-
- /* On failure, disable autotrim to avoid repeated failed future calls */
- if (released == 0 && m->topsize > m->trim_check)
- m->trim_check = MAX_SIZE_T;
- }
-
- return (released != 0)? 1 : 0;
-}
-
-/* Consolidate and bin a chunk. Differs from exported versions
- of free mainly in that the chunk need not be marked as inuse.
-*/
-static void dispose_chunk(mstate m, mchunkptr p, size_t psize) {
- mchunkptr next = chunk_plus_offset(p, psize);
- if (!pinuse(p)) {
- mchunkptr prev;
- size_t prevsize = p->prev_foot;
- if (is_mmapped(p)) {
- psize += prevsize + MMAP_FOOT_PAD;
- if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
- m->footprint -= psize;
- return;
- }
- prev = chunk_minus_offset(p, prevsize);
- psize += prevsize;
- p = prev;
- if (RTCHECK(ok_address(m, prev))) { /* consolidate backward */
- if (p != m->dv) {
- unlink_chunk(m, p, prevsize);
- }
- else if ((next->head & INUSE_BITS) == INUSE_BITS) {
- m->dvsize = psize;
- set_free_with_pinuse(p, psize, next);
- return;
- }
- }
- else {
- CORRUPTION_ERROR_ACTION(m);
- return;
- }
- }
- if (RTCHECK(ok_address(m, next))) {
- if (!cinuse(next)) { /* consolidate forward */
- if (next == m->top) {
- size_t tsize = m->topsize += psize;
- m->top = p;
- p->head = tsize | PINUSE_BIT;
- if (p == m->dv) {
- m->dv = 0;
- m->dvsize = 0;
- }
- return;
- }
- else if (next == m->dv) {
- size_t dsize = m->dvsize += psize;
- m->dv = p;
- set_size_and_pinuse_of_free_chunk(p, dsize);
- return;
- }
- else {
- size_t nsize = chunksize(next);
- psize += nsize;
- unlink_chunk(m, next, nsize);
- set_size_and_pinuse_of_free_chunk(p, psize);
- if (p == m->dv) {
- m->dvsize = psize;
- return;
- }
- }
- }
- else {
- set_free_with_pinuse(p, psize, next);
- }
- insert_chunk(m, p, psize);
- }
- else {
- CORRUPTION_ERROR_ACTION(m);
- }
-}
-
-/* ---------------------------- malloc --------------------------- */
-
-/* allocate a large request from the best fitting chunk in a treebin */
-static void* tmalloc_large(mstate m, size_t nb) {
- tchunkptr v = 0;
- size_t rsize = -nb; /* Unsigned negation */
- tchunkptr t;
- bindex_t idx;
- compute_tree_index(nb, idx);
- if ((t = *treebin_at(m, idx)) != 0) {
- /* Traverse tree for this bin looking for node with size == nb */
- size_t sizebits = nb << leftshift_for_tree_index(idx);
- tchunkptr rst = 0; /* The deepest untaken right subtree */
- for (;;) {
- tchunkptr rt;
- size_t trem = chunksize(t) - nb;
- if (trem < rsize) {
- v = t;
- if ((rsize = trem) == 0)
- break;
- }
- rt = t->child[1];
- t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
- if (rt != 0 && rt != t)
- rst = rt;
- if (t == 0) {
- t = rst; /* set t to least subtree holding sizes > nb */
- break;
- }
- sizebits <<= 1;
- }
- }
- if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
- binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
- if (leftbits != 0) {
- bindex_t i;
- binmap_t leastbit = least_bit(leftbits);
- compute_bit2idx(leastbit, i);
- t = *treebin_at(m, i);
- }
- }
-
- while (t != 0) { /* find smallest of tree or subtree */
- size_t trem = chunksize(t) - nb;
- if (trem < rsize) {
- rsize = trem;
- v = t;
- }
- t = leftmost_child(t);
- }
-
- /* If dv is a better fit, return 0 so malloc will use it */
- if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {
- if (RTCHECK(ok_address(m, v))) { /* split */
- mchunkptr r = chunk_plus_offset(v, nb);
- assert(chunksize(v) == rsize + nb);
- if (RTCHECK(ok_next(v, r))) {
- unlink_large_chunk(m, v);
- if (rsize < MIN_CHUNK_SIZE)
- set_inuse_and_pinuse(m, v, (rsize + nb));
- else {
- set_size_and_pinuse_of_inuse_chunk(m, v, nb);
- set_size_and_pinuse_of_free_chunk(r, rsize);
- insert_chunk(m, r, rsize);
- }
- return chunk2mem(v);
- }
- }
- CORRUPTION_ERROR_ACTION(m);
- }
- return 0;
-}
-
-/* allocate a small request from the best fitting chunk in a treebin */
-static void* tmalloc_small(mstate m, size_t nb) {
- tchunkptr t, v;
- size_t rsize;
- bindex_t i;
- binmap_t leastbit = least_bit(m->treemap);
- compute_bit2idx(leastbit, i);
- v = t = *treebin_at(m, i);
- rsize = chunksize(t) - nb;
-
- while ((t = leftmost_child(t)) != 0) {
- size_t trem = chunksize(t) - nb;
- if (trem < rsize) {
- rsize = trem;
- v = t;
- }
- }
-
- if (RTCHECK(ok_address(m, v))) {
- mchunkptr r = chunk_plus_offset(v, nb);
- assert(chunksize(v) == rsize + nb);
- if (RTCHECK(ok_next(v, r))) {
- unlink_large_chunk(m, v);
- if (rsize < MIN_CHUNK_SIZE)
- set_inuse_and_pinuse(m, v, (rsize + nb));
- else {
- set_size_and_pinuse_of_inuse_chunk(m, v, nb);
- set_size_and_pinuse_of_free_chunk(r, rsize);
- replace_dv(m, r, rsize);
- }
- return chunk2mem(v);
- }
- }
-
- CORRUPTION_ERROR_ACTION(m);
- return 0;
-}
-
-#if !ONLY_MSPACES
-
-void* dlmalloc(size_t bytes) {
- /*
- Basic algorithm:
- If a small request (< 256 bytes minus per-chunk overhead):
- 1. If one exists, use a remainderless chunk in associated smallbin.
- (Remainderless means that there are too few excess bytes to
- represent as a chunk.)
- 2. If it is big enough, use the dv chunk, which is normally the
- chunk adjacent to the one used for the most recent small request.
- 3. If one exists, split the smallest available chunk in a bin,
- saving remainder in dv.
- 4. If it is big enough, use the top chunk.
- 5. If available, get memory from system and use it
- Otherwise, for a large request:
- 1. Find the smallest available binned chunk that fits, and use it
- if it is better fitting than dv chunk, splitting if necessary.
- 2. If better fitting than any binned chunk, use the dv chunk.
- 3. If it is big enough, use the top chunk.
- 4. If request size >= mmap threshold, try to directly mmap this chunk.
- 5. If available, get memory from system and use it
-
- The ugly goto's here ensure that postaction occurs along all paths.
- */
-
-#if USE_LOCKS
- ensure_initialization(); /* initialize in sys_alloc if not using locks */
-#endif
-
- if (!PREACTION(gm)) {
- void* mem;
- size_t nb;
- if (bytes <= MAX_SMALL_REQUEST) {
- bindex_t idx;
- binmap_t smallbits;
- nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
- idx = small_index(nb);
- smallbits = gm->smallmap >> idx;
-
- if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
- mchunkptr b, p;
- idx += ~smallbits & 1; /* Uses next bin if idx empty */
- b = smallbin_at(gm, idx);
- p = b->fd;
- assert(chunksize(p) == small_index2size(idx));
- unlink_first_small_chunk(gm, b, p, idx);
- set_inuse_and_pinuse(gm, p, small_index2size(idx));
- mem = chunk2mem(p);
- check_malloced_chunk(gm, mem, nb);
- goto postaction;
- }
-
- else if (nb > gm->dvsize) {
- if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
- mchunkptr b, p, r;
- size_t rsize;
- bindex_t i;
- binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
- binmap_t leastbit = least_bit(leftbits);
- compute_bit2idx(leastbit, i);
- b = smallbin_at(gm, i);
- p = b->fd;
- assert(chunksize(p) == small_index2size(i));
- unlink_first_small_chunk(gm, b, p, i);
- rsize = small_index2size(i) - nb;
- /* Fit here cannot be remainderless if 4byte sizes */
- if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
- set_inuse_and_pinuse(gm, p, small_index2size(i));
- else {
- set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
- r = chunk_plus_offset(p, nb);
- set_size_and_pinuse_of_free_chunk(r, rsize);
- replace_dv(gm, r, rsize);
- }
- mem = chunk2mem(p);
- check_malloced_chunk(gm, mem, nb);
- goto postaction;
- }
-
- else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) {
- check_malloced_chunk(gm, mem, nb);
- goto postaction;
- }
- }
- }
- else if (bytes >= MAX_REQUEST)
- nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
- else {
- nb = pad_request(bytes);
- if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {
- check_malloced_chunk(gm, mem, nb);
- goto postaction;
- }
- }
-
- if (nb <= gm->dvsize) {
- size_t rsize = gm->dvsize - nb;
- mchunkptr p = gm->dv;
- if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
- mchunkptr r = gm->dv = chunk_plus_offset(p, nb);
- gm->dvsize = rsize;
- set_size_and_pinuse_of_free_chunk(r, rsize);
- set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
- }
- else { /* exhaust dv */
- size_t dvs = gm->dvsize;
- gm->dvsize = 0;
- gm->dv = 0;
- set_inuse_and_pinuse(gm, p, dvs);
- }
- mem = chunk2mem(p);
- check_malloced_chunk(gm, mem, nb);
- goto postaction;
- }
-
- else if (nb < gm->topsize) { /* Split top */
- size_t rsize = gm->topsize -= nb;
- mchunkptr p = gm->top;
- mchunkptr r = gm->top = chunk_plus_offset(p, nb);
- r->head = rsize | PINUSE_BIT;
- set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
- mem = chunk2mem(p);
- check_top_chunk(gm, gm->top);
- check_malloced_chunk(gm, mem, nb);
- goto postaction;
- }
-
- mem = sys_alloc(gm, nb);
-
- postaction:
- POSTACTION(gm);
- return mem;
- }
-
- return 0;
-}
-
-/* ---------------------------- free --------------------------- */
-
-void dlfree(void* mem) {
- /*
- Consolidate freed chunks with preceeding or succeeding bordering
- free chunks, if they exist, and then place in a bin. Intermixed
- with special cases for top, dv, mmapped chunks, and usage errors.
- */
-
- if (mem != 0) {
- mchunkptr p = mem2chunk(mem);
-#if FOOTERS
- mstate fm = get_mstate_for(p);
- if (!ok_magic(fm)) {
- USAGE_ERROR_ACTION(fm, p);
- return;
- }
-#else /* FOOTERS */
-#define fm gm
-#endif /* FOOTERS */
- if (!PREACTION(fm)) {
- check_inuse_chunk(fm, p);
- if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {
- size_t psize = chunksize(p);
- mchunkptr next = chunk_plus_offset(p, psize);
- if (!pinuse(p)) {
- size_t prevsize = p->prev_foot;
- if (is_mmapped(p)) {
- psize += prevsize + MMAP_FOOT_PAD;
- if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
- fm->footprint -= psize;
- goto postaction;
- }
- else {
- mchunkptr prev = chunk_minus_offset(p, prevsize);
- psize += prevsize;
- p = prev;
- if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
- if (p != fm->dv) {
- unlink_chunk(fm, p, prevsize);
- }
- else if ((next->head & INUSE_BITS) == INUSE_BITS) {
- fm->dvsize = psize;
- set_free_with_pinuse(p, psize, next);
- goto postaction;
- }
- }
- else
- goto erroraction;
- }
- }
-
- if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
- if (!cinuse(next)) { /* consolidate forward */
- if (next == fm->top) {
- size_t tsize = fm->topsize += psize;
- fm->top = p;
- p->head = tsize | PINUSE_BIT;
- if (p == fm->dv) {
- fm->dv = 0;
- fm->dvsize = 0;
- }
- if (should_trim(fm, tsize))
- sys_trim(fm, 0);
- goto postaction;
- }
- else if (next == fm->dv) {
- size_t dsize = fm->dvsize += psize;
- fm->dv = p;
- set_size_and_pinuse_of_free_chunk(p, dsize);
- goto postaction;
- }
- else {
- size_t nsize = chunksize(next);
- psize += nsize;
- unlink_chunk(fm, next, nsize);
- set_size_and_pinuse_of_free_chunk(p, psize);
- if (p == fm->dv) {
- fm->dvsize = psize;
- goto postaction;
- }
- }
- }
- else
- set_free_with_pinuse(p, psize, next);
-
- if (is_small(psize)) {
- insert_small_chunk(fm, p, psize);
- check_free_chunk(fm, p);
- }
- else {
- tchunkptr tp = (tchunkptr)p;
- insert_large_chunk(fm, tp, psize);
- check_free_chunk(fm, p);
- if (--fm->release_checks == 0)
- release_unused_segments(fm);
- }
- goto postaction;
- }
- }
- erroraction:
- USAGE_ERROR_ACTION(fm, p);
- postaction:
- POSTACTION(fm);
- }
- }
-#if !FOOTERS
-#undef fm
-#endif /* FOOTERS */
-}
-
-void* dlcalloc(size_t n_elements, size_t elem_size) {
- void* mem;
- size_t req = 0;
- if (n_elements != 0) {
- req = n_elements * elem_size;
- if (((n_elements | elem_size) & ~(size_t)0xffff) &&
- (req / n_elements != elem_size))
- req = MAX_SIZE_T; /* force downstream failure on overflow */
- }
- mem = dlmalloc(req);
- if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
- memset(mem, 0, req);
- return mem;
-}
-
-#endif /* !ONLY_MSPACES */
-
-/* ------------ Internal support for realloc, memalign, etc -------------- */
-
-/* Try to realloc; only in-place unless can_move true */
-static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb,
- int can_move) {
- mchunkptr newp = 0;
- size_t oldsize = chunksize(p);
- mchunkptr next = chunk_plus_offset(p, oldsize);
- if (RTCHECK(ok_address(m, p) && ok_inuse(p) &&
- ok_next(p, next) && ok_pinuse(next))) {
- if (is_mmapped(p)) {
- newp = mmap_resize(m, p, nb, can_move);
- }
- else if (oldsize >= nb) { /* already big enough */
- size_t rsize = oldsize - nb;
- if (rsize >= MIN_CHUNK_SIZE) { /* split off remainder */
- mchunkptr r = chunk_plus_offset(p, nb);
- set_inuse(m, p, nb);
- set_inuse(m, r, rsize);
- dispose_chunk(m, r, rsize);
- }
- newp = p;
- }
- else if (next == m->top) { /* extend into top */
- if (oldsize + m->topsize > nb) {
- size_t newsize = oldsize + m->topsize;
- size_t newtopsize = newsize - nb;
- mchunkptr newtop = chunk_plus_offset(p, nb);
- set_inuse(m, p, nb);
- newtop->head = newtopsize |PINUSE_BIT;
- m->top = newtop;
- m->topsize = newtopsize;
- newp = p;
- }
- }
- else if (next == m->dv) { /* extend into dv */
- size_t dvs = m->dvsize;
- if (oldsize + dvs >= nb) {
- size_t dsize = oldsize + dvs - nb;
- if (dsize >= MIN_CHUNK_SIZE) {
- mchunkptr r = chunk_plus_offset(p, nb);
- mchunkptr n = chunk_plus_offset(r, dsize);
- set_inuse(m, p, nb);
- set_size_and_pinuse_of_free_chunk(r, dsize);
- clear_pinuse(n);
- m->dvsize = dsize;
- m->dv = r;
- }
- else { /* exhaust dv */
- size_t newsize = oldsize + dvs;
- set_inuse(m, p, newsize);
- m->dvsize = 0;
- m->dv = 0;
- }
- newp = p;
- }
- }
- else if (!cinuse(next)) { /* extend into next free chunk */
- size_t nextsize = chunksize(next);
- if (oldsize + nextsize >= nb) {
- size_t rsize = oldsize + nextsize - nb;
- unlink_chunk(m, next, nextsize);
- if (rsize < MIN_CHUNK_SIZE) {
- size_t newsize = oldsize + nextsize;
- set_inuse(m, p, newsize);
- }
- else {
- mchunkptr r = chunk_plus_offset(p, nb);
- set_inuse(m, p, nb);
- set_inuse(m, r, rsize);
- dispose_chunk(m, r, rsize);
- }
- newp = p;
- }
- }
- }
- else {
- USAGE_ERROR_ACTION(m, chunk2mem(p));
- }
- return newp;
-}
-
-static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
- void* mem = 0;
- if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
- alignment = MIN_CHUNK_SIZE;
- if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */
- size_t a = MALLOC_ALIGNMENT << 1;
- while (a < alignment) a <<= 1;
- alignment = a;
- }
- if (bytes >= MAX_REQUEST - alignment) {
- if (m != 0) { /* Test isn't needed but avoids compiler warning */
- MALLOC_FAILURE_ACTION;
- }
- }
- else {
- size_t nb = request2size(bytes);
- size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
- mem = internal_malloc(m, req);
- if (mem != 0) {
- mchunkptr p = mem2chunk(mem);
- if (PREACTION(m))
- return 0;
- if ((((size_t)(mem)) & (alignment - 1)) != 0) { /* misaligned */
- /*
- Find an aligned spot inside chunk. Since we need to give
- back leading space in a chunk of at least MIN_CHUNK_SIZE, if
- the first calculation places us at a spot with less than
- MIN_CHUNK_SIZE leader, we can move to the next aligned spot.
- We've allocated enough total room so that this is always
- possible.
- */
- char* br = (char*)mem2chunk((size_t)(((size_t)((char*)mem + alignment -
- SIZE_T_ONE)) &
- -alignment));
- char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?
- br : br+alignment;
- mchunkptr newp = (mchunkptr)pos;
- size_t leadsize = pos - (char*)(p);
- size_t newsize = chunksize(p) - leadsize;
-
- if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */
- newp->prev_foot = p->prev_foot + leadsize;
- newp->head = newsize;
- }
- else { /* Otherwise, give back leader, use the rest */
- set_inuse(m, newp, newsize);
- set_inuse(m, p, leadsize);
- dispose_chunk(m, p, leadsize);
- }
- p = newp;
- }
-
- /* Give back spare room at the end */
- if (!is_mmapped(p)) {
- size_t size = chunksize(p);
- if (size > nb + MIN_CHUNK_SIZE) {
- size_t remainder_size = size - nb;
- mchunkptr remainder = chunk_plus_offset(p, nb);
- set_inuse(m, p, nb);
- set_inuse(m, remainder, remainder_size);
- dispose_chunk(m, remainder, remainder_size);
- }
- }
-
- mem = chunk2mem(p);
- assert (chunksize(p) >= nb);
- assert(((size_t)mem & (alignment - 1)) == 0);
- check_inuse_chunk(m, p);
- POSTACTION(m);
- }
- }
- return mem;
-}
-
-/*
- Common support for independent_X routines, handling
- all of the combinations that can result.
- The opts arg has:
- bit 0 set if all elements are same size (using sizes[0])
- bit 1 set if elements should be zeroed
-*/
-static void** ialloc(mstate m,
- size_t n_elements,
- size_t* sizes,
- int opts,
- void* chunks[]) {
-
- size_t element_size; /* chunksize of each element, if all same */
- size_t contents_size; /* total size of elements */
- size_t array_size; /* request size of pointer array */
- void* mem; /* malloced aggregate space */
- mchunkptr p; /* corresponding chunk */
- size_t remainder_size; /* remaining bytes while splitting */
- void** marray; /* either "chunks" or malloced ptr array */
- mchunkptr array_chunk; /* chunk for malloced ptr array */
- flag_t was_enabled; /* to disable mmap */
- size_t size;
- size_t i;
-
- ensure_initialization();
- /* compute array length, if needed */
- if (chunks != 0) {
- if (n_elements == 0)
- return chunks; /* nothing to do */
- marray = chunks;
- array_size = 0;
- }
- else {
- /* if empty req, must still return chunk representing empty array */
- if (n_elements == 0)
- return (void**)internal_malloc(m, 0);
- marray = 0;
- array_size = request2size(n_elements * (sizeof(void*)));
- }
-
- /* compute total element size */
- if (opts & 0x1) { /* all-same-size */
- element_size = request2size(*sizes);
- contents_size = n_elements * element_size;
- }
- else { /* add up all the sizes */
- element_size = 0;
- contents_size = 0;
- for (i = 0; i != n_elements; ++i)
- contents_size += request2size(sizes[i]);
- }
-
- size = contents_size + array_size;
-
- /*
- Allocate the aggregate chunk. First disable direct-mmapping so
- malloc won't use it, since we would not be able to later
- free/realloc space internal to a segregated mmap region.
- */
- was_enabled = use_mmap(m);
- disable_mmap(m);
- mem = internal_malloc(m, size - CHUNK_OVERHEAD);
- if (was_enabled)
- enable_mmap(m);
- if (mem == 0)
- return 0;
-
- if (PREACTION(m)) return 0;
- p = mem2chunk(mem);
- remainder_size = chunksize(p);
-
- assert(!is_mmapped(p));
-
- if (opts & 0x2) { /* optionally clear the elements */
- memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size);
- }
-
- /* If not provided, allocate the pointer array as final part of chunk */
- if (marray == 0) {
- size_t array_chunk_size;
- array_chunk = chunk_plus_offset(p, contents_size);
- array_chunk_size = remainder_size - contents_size;
- marray = (void**) (chunk2mem(array_chunk));
- set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size);
- remainder_size = contents_size;
- }
-
- /* split out elements */
- for (i = 0; ; ++i) {
- marray[i] = chunk2mem(p);
- if (i != n_elements-1) {
- if (element_size != 0)
- size = element_size;
- else
- size = request2size(sizes[i]);
- remainder_size -= size;
- set_size_and_pinuse_of_inuse_chunk(m, p, size);
- p = chunk_plus_offset(p, size);
- }
- else { /* the final element absorbs any overallocation slop */
- set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size);
- break;
- }
- }
-
-#if DEBUG
- if (marray != chunks) {
- /* final element must have exactly exhausted chunk */
- if (element_size != 0) {
- assert(remainder_size == element_size);
- }
- else {
- assert(remainder_size == request2size(sizes[i]));
- }
- check_inuse_chunk(m, mem2chunk(marray));
- }
- for (i = 0; i != n_elements; ++i)
- check_inuse_chunk(m, mem2chunk(marray[i]));
-
-#endif /* DEBUG */
-
- POSTACTION(m);
- return marray;
-}
-
-/* Try to free all pointers in the given array.
- Note: this could be made faster, by delaying consolidation,
- at the price of disabling some user integrity checks, We
- still optimize some consolidations by combining adjacent
- chunks before freeing, which will occur often if allocated
- with ialloc or the array is sorted.
-*/
-static size_t internal_bulk_free(mstate m, void* array[], size_t nelem) {
- size_t unfreed = 0;
- if (!PREACTION(m)) {
- void** a;
- void** fence = &(array[nelem]);
- for (a = array; a != fence; ++a) {
- void* mem = *a;
- if (mem != 0) {
- mchunkptr p = mem2chunk(mem);
- size_t psize = chunksize(p);
-#if FOOTERS
- if (get_mstate_for(p) != m) {
- ++unfreed;
- continue;
- }
-#endif
- check_inuse_chunk(m, p);
- *a = 0;
- if (RTCHECK(ok_address(m, p) && ok_inuse(p))) {
- void ** b = a + 1; /* try to merge with next chunk */
- mchunkptr next = next_chunk(p);
- if (b != fence && *b == chunk2mem(next)) {
- size_t newsize = chunksize(next) + psize;
- set_inuse(m, p, newsize);
- *b = chunk2mem(p);
- }
- else
- dispose_chunk(m, p, psize);
- }
- else {
- CORRUPTION_ERROR_ACTION(m);
- break;
- }
- }
- }
- if (should_trim(m, m->topsize))
- sys_trim(m, 0);
- POSTACTION(m);
- }
- return unfreed;
-}
-
-/* Traversal */
-#if MALLOC_INSPECT_ALL
-static void internal_inspect_all(mstate m,
- void(*handler)(void *start,
- void *end,
- size_t used_bytes,
- void* callback_arg),
- void* arg) {
- if (is_initialized(m)) {
- mchunkptr top = m->top;
- msegmentptr s;
- for (s = &m->seg; s != 0; s = s->next) {
- mchunkptr q = align_as_chunk(s->base);
- while (segment_holds(s, q) && q->head != FENCEPOST_HEAD) {
- mchunkptr next = next_chunk(q);
- size_t sz = chunksize(q);
- size_t used;
- void* start;
- if (is_inuse(q)) {
- used = sz - CHUNK_OVERHEAD; /* must not be mmapped */
- start = chunk2mem(q);
- }
- else {
- used = 0;
- if (is_small(sz)) { /* offset by possible bookkeeping */
- start = (void*)((char*)q + sizeof(struct malloc_chunk));
- }
- else {
- start = (void*)((char*)q + sizeof(struct malloc_tree_chunk));
- }
- }
- if (start < (void*)next) /* skip if all space is bookkeeping */
- handler(start, next, used, arg);
- if (q == top)
- break;
- q = next;
- }
- }
- }
-}
-#endif /* MALLOC_INSPECT_ALL */
-
-/* ------------------ Exported realloc, memalign, etc -------------------- */
-
-#if !ONLY_MSPACES
-
-void* dlrealloc(void* oldmem, size_t bytes) {
- void* mem = 0;
- if (oldmem == 0) {
- mem = dlmalloc(bytes);
- }
- else if (bytes >= MAX_REQUEST) {
- MALLOC_FAILURE_ACTION;
- }
-#ifdef REALLOC_ZERO_BYTES_FREES
- else if (bytes == 0) {
- dlfree(oldmem);
- }
-#endif /* REALLOC_ZERO_BYTES_FREES */
- else {
- size_t nb = request2size(bytes);
- mchunkptr oldp = mem2chunk(oldmem);
-#if ! FOOTERS
- mstate m = gm;
-#else /* FOOTERS */
- mstate m = get_mstate_for(oldp);
- if (!ok_magic(m)) {
- USAGE_ERROR_ACTION(m, oldmem);
- return 0;
- }
-#endif /* FOOTERS */
- if (!PREACTION(m)) {
- mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1);
- POSTACTION(m);
- if (newp != 0) {
- check_inuse_chunk(m, newp);
- mem = chunk2mem(newp);
- }
- else {
- mem = internal_malloc(m, bytes);
- if (mem != 0) {
- size_t oc = chunksize(oldp) - overhead_for(oldp);
- memcpy(mem, oldmem, (oc < bytes)? oc : bytes);
- internal_free(m, oldmem);
- }
- }
- }
- }
- return mem;
-}
-
-void* dlrealloc_in_place(void* oldmem, size_t bytes) {
- void* mem = 0;
- if (oldmem != 0) {
- if (bytes >= MAX_REQUEST) {
- MALLOC_FAILURE_ACTION;
- }
- else {
- size_t nb = request2size(bytes);
- mchunkptr oldp = mem2chunk(oldmem);
-#if ! FOOTERS
- mstate m = gm;
-#else /* FOOTERS */
- mstate m = get_mstate_for(oldp);
- if (!ok_magic(m)) {
- USAGE_ERROR_ACTION(m, oldmem);
- return 0;
- }
-#endif /* FOOTERS */
- if (!PREACTION(m)) {
- mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0);
- POSTACTION(m);
- if (newp == oldp) {
- check_inuse_chunk(m, newp);
- mem = oldmem;
- }
- }
- }
- }
- return mem;
-}
-
-void* dlmemalign(size_t alignment, size_t bytes) {
- if (alignment <= MALLOC_ALIGNMENT) {
- return dlmalloc(bytes);
- }
- return internal_memalign(gm, alignment, bytes);
-}
-
-int dlposix_memalign(void** pp, size_t alignment, size_t bytes) {
- void* mem = 0;
- if (alignment == MALLOC_ALIGNMENT)
- mem = dlmalloc(bytes);
- else {
- size_t d = alignment / sizeof(void*);
- size_t r = alignment % sizeof(void*);
- if (r != 0 || d == 0 || (d & (d-SIZE_T_ONE)) != 0)
- return EINVAL;
- else if (bytes <= MAX_REQUEST - alignment) {
- if (alignment < MIN_CHUNK_SIZE)
- alignment = MIN_CHUNK_SIZE;
- mem = internal_memalign(gm, alignment, bytes);
- }
- }
- if (mem == 0)
- return ENOMEM;
- else {
- *pp = mem;
- return 0;
- }
-}
-
-void* dlvalloc(size_t bytes) {
- size_t pagesz;
- ensure_initialization();
- pagesz = mparams.page_size;
- return dlmemalign(pagesz, bytes);
-}
-
-void* dlpvalloc(size_t bytes) {
- size_t pagesz;
- ensure_initialization();
- pagesz = mparams.page_size;
- return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE));
-}
-
-void** dlindependent_calloc(size_t n_elements, size_t elem_size,
- void* chunks[]) {
- size_t sz = elem_size; /* serves as 1-element array */
- return ialloc(gm, n_elements, &sz, 3, chunks);
-}
-
-void** dlindependent_comalloc(size_t n_elements, size_t sizes[],
- void* chunks[]) {
- return ialloc(gm, n_elements, sizes, 0, chunks);
-}
-
-size_t dlbulk_free(void* array[], size_t nelem) {
- return internal_bulk_free(gm, array, nelem);
-}
-
-#if MALLOC_INSPECT_ALL
-void dlmalloc_inspect_all(void(*handler)(void *start,
- void *end,
- size_t used_bytes,
- void* callback_arg),
- void* arg) {
- ensure_initialization();
- if (!PREACTION(gm)) {
- internal_inspect_all(gm, handler, arg);
- POSTACTION(gm);
- }
-}
-#endif /* MALLOC_INSPECT_ALL */
-
-int dlmalloc_trim(size_t pad) {
- int result = 0;
- ensure_initialization();
- if (!PREACTION(gm)) {
- result = sys_trim(gm, pad);
- POSTACTION(gm);
- }
- return result;
-}
-
-size_t dlmalloc_footprint(void) {
- return gm->footprint;
-}
-
-size_t dlmalloc_max_footprint(void) {
- return gm->max_footprint;
-}
-
-size_t dlmalloc_footprint_limit(void) {
- size_t maf = gm->footprint_limit;
- return maf == 0 ? MAX_SIZE_T : maf;
-}
-
-size_t dlmalloc_set_footprint_limit(size_t bytes) {
- size_t result; /* invert sense of 0 */
- if (bytes == 0)
- result = granularity_align(1); /* Use minimal size */
- if (bytes == MAX_SIZE_T)
- result = 0; /* disable */
- else
- result = granularity_align(bytes);
- return gm->footprint_limit = result;
-}
-
-#if !NO_MALLINFO
-struct mallinfo dlmallinfo(void) {
- return internal_mallinfo(gm);
-}
-#endif /* NO_MALLINFO */
-
-#if !NO_MALLOC_STATS
-void dlmalloc_stats() {
- internal_malloc_stats(gm);
-}
-#endif /* NO_MALLOC_STATS */
-
-int dlmallopt(int param_number, int value) {
- return change_mparam(param_number, value);
-}
-
-size_t dlmalloc_usable_size(void* mem) {
- if (mem != 0) {
- mchunkptr p = mem2chunk(mem);
- if (is_inuse(p))
- return chunksize(p) - overhead_for(p);
- }
- return 0;
-}
-
-#endif /* !ONLY_MSPACES */
-
-/* ----------------------------- user mspaces ---------------------------- */
-
-#if MSPACES
-
-static mstate init_user_mstate(char* tbase, size_t tsize) {
- size_t msize = pad_request(sizeof(struct malloc_state));
- mchunkptr mn;
- mchunkptr msp = align_as_chunk(tbase);
- mstate m = (mstate)(chunk2mem(msp));
- memset(m, 0, msize);
- (void)INITIAL_LOCK(&m->mutex);
- msp->head = (msize|INUSE_BITS);
- m->seg.base = m->least_addr = tbase;
- m->seg.size = m->footprint = m->max_footprint = tsize;
- m->magic = mparams.magic;
- m->release_checks = MAX_RELEASE_CHECK_RATE;
- m->mflags = mparams.default_mflags;
- m->extp = 0;
- m->exts = 0;
- disable_contiguous(m);
- init_bins(m);
- mn = next_chunk(mem2chunk(m));
- init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);
- check_top_chunk(m, m->top);
- return m;
-}
-
-mspace create_mspace(size_t capacity, int locked) {
- mstate m = 0;
- size_t msize;
- ensure_initialization();
- msize = pad_request(sizeof(struct malloc_state));
- if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
- size_t rs = ((capacity == 0)? mparams.granularity :
- (capacity + TOP_FOOT_SIZE + msize));
- size_t tsize = granularity_align(rs);
- char* tbase = (char*)(CALL_MMAP(tsize));
- if (tbase != CMFAIL) {
- m = init_user_mstate(tbase, tsize);
- m->seg.sflags = USE_MMAP_BIT;
- set_lock(m, locked);
- }
- }
- return (mspace)m;
-}
-
-mspace create_mspace_with_base(void* base, size_t capacity, int locked) {
- mstate m = 0;
- size_t msize;
- ensure_initialization();
- msize = pad_request(sizeof(struct malloc_state));
- if (capacity > msize + TOP_FOOT_SIZE &&
- capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
- m = init_user_mstate((char*)base, capacity);
- m->seg.sflags = EXTERN_BIT;
- set_lock(m, locked);
- }
- return (mspace)m;
-}
-
-int mspace_track_large_chunks(mspace msp, int enable) {
- int ret = 0;
- mstate ms = (mstate)msp;
- if (!PREACTION(ms)) {
- if (!use_mmap(ms)) {
- ret = 1;
- }
- if (!enable) {
- enable_mmap(ms);
- } else {
- disable_mmap(ms);
- }
- POSTACTION(ms);
- }
- return ret;
-}
-
-size_t destroy_mspace(mspace msp) {
- size_t freed = 0;
- mstate ms = (mstate)msp;
- if (ok_magic(ms)) {
- msegmentptr sp = &ms->seg;
- (void)DESTROY_LOCK(&ms->mutex); /* destroy before unmapped */
- while (sp != 0) {
- char* base = sp->base;
- size_t size = sp->size;
- flag_t flag = sp->sflags;
- (void)base; /* placate people compiling -Wunused-variable */
- sp = sp->next;
- if ((flag & USE_MMAP_BIT) && !(flag & EXTERN_BIT) &&
- CALL_MUNMAP(base, size) == 0)
- freed += size;
- }
- }
- else {
- USAGE_ERROR_ACTION(ms,ms);
- }
- return freed;
-}
-
-/*
- mspace versions of routines are near-clones of the global
- versions. This is not so nice but better than the alternatives.
-*/
-
-void* mspace_malloc(mspace msp, size_t bytes) {
- mstate ms = (mstate)msp;
- if (!ok_magic(ms)) {
- USAGE_ERROR_ACTION(ms,ms);
- return 0;
- }
- if (!PREACTION(ms)) {
- void* mem;
- size_t nb;
- if (bytes <= MAX_SMALL_REQUEST) {
- bindex_t idx;
- binmap_t smallbits;
- nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
- idx = small_index(nb);
- smallbits = ms->smallmap >> idx;
-
- if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
- mchunkptr b, p;
- idx += ~smallbits & 1; /* Uses next bin if idx empty */
- b = smallbin_at(ms, idx);
- p = b->fd;
- assert(chunksize(p) == small_index2size(idx));
- unlink_first_small_chunk(ms, b, p, idx);
- set_inuse_and_pinuse(ms, p, small_index2size(idx));
- mem = chunk2mem(p);
- check_malloced_chunk(ms, mem, nb);
- goto postaction;
- }
-
- else if (nb > ms->dvsize) {
- if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
- mchunkptr b, p, r;
- size_t rsize;
- bindex_t i;
- binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
- binmap_t leastbit = least_bit(leftbits);
- compute_bit2idx(leastbit, i);
- b = smallbin_at(ms, i);
- p = b->fd;
- assert(chunksize(p) == small_index2size(i));
- unlink_first_small_chunk(ms, b, p, i);
- rsize = small_index2size(i) - nb;
- /* Fit here cannot be remainderless if 4byte sizes */
- if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
- set_inuse_and_pinuse(ms, p, small_index2size(i));
- else {
- set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
- r = chunk_plus_offset(p, nb);
- set_size_and_pinuse_of_free_chunk(r, rsize);
- replace_dv(ms, r, rsize);
- }
- mem = chunk2mem(p);
- check_malloced_chunk(ms, mem, nb);
- goto postaction;
- }
-
- else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) {
- check_malloced_chunk(ms, mem, nb);
- goto postaction;
- }
- }
- }
- else if (bytes >= MAX_REQUEST)
- nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
- else {
- nb = pad_request(bytes);
- if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {
- check_malloced_chunk(ms, mem, nb);
- goto postaction;
- }
- }
-
- if (nb <= ms->dvsize) {
- size_t rsize = ms->dvsize - nb;
- mchunkptr p = ms->dv;
- if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
- mchunkptr r = ms->dv = chunk_plus_offset(p, nb);
- ms->dvsize = rsize;
- set_size_and_pinuse_of_free_chunk(r, rsize);
- set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
- }
- else { /* exhaust dv */
- size_t dvs = ms->dvsize;
- ms->dvsize = 0;
- ms->dv = 0;
- set_inuse_and_pinuse(ms, p, dvs);
- }
- mem = chunk2mem(p);
- check_malloced_chunk(ms, mem, nb);
- goto postaction;
- }
-
- else if (nb < ms->topsize) { /* Split top */
- size_t rsize = ms->topsize -= nb;
- mchunkptr p = ms->top;
- mchunkptr r = ms->top = chunk_plus_offset(p, nb);
- r->head = rsize | PINUSE_BIT;
- set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
- mem = chunk2mem(p);
- check_top_chunk(ms, ms->top);
- check_malloced_chunk(ms, mem, nb);
- goto postaction;
- }
-
- mem = sys_alloc(ms, nb);
-
- postaction:
- POSTACTION(ms);
- return mem;
- }
-
- return 0;
-}
-
-void mspace_free(mspace msp, void* mem) {
- if (mem != 0) {
- mchunkptr p = mem2chunk(mem);
-#if FOOTERS
- mstate fm = get_mstate_for(p);
- (void)msp; /* placate people compiling -Wunused */
-#else /* FOOTERS */
- mstate fm = (mstate)msp;
-#endif /* FOOTERS */
- if (!ok_magic(fm)) {
- USAGE_ERROR_ACTION(fm, p);
- return;
- }
- if (!PREACTION(fm)) {
- check_inuse_chunk(fm, p);
- if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {
- size_t psize = chunksize(p);
- mchunkptr next = chunk_plus_offset(p, psize);
- if (!pinuse(p)) {
- size_t prevsize = p->prev_foot;
- if (is_mmapped(p)) {
- psize += prevsize + MMAP_FOOT_PAD;
- if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
- fm->footprint -= psize;
- goto postaction;
- }
- else {
- mchunkptr prev = chunk_minus_offset(p, prevsize);
- psize += prevsize;
- p = prev;
- if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
- if (p != fm->dv) {
- unlink_chunk(fm, p, prevsize);
- }
- else if ((next->head & INUSE_BITS) == INUSE_BITS) {
- fm->dvsize = psize;
- set_free_with_pinuse(p, psize, next);
- goto postaction;
- }
- }
- else
- goto erroraction;
- }
- }
-
- if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
- if (!cinuse(next)) { /* consolidate forward */
- if (next == fm->top) {
- size_t tsize = fm->topsize += psize;
- fm->top = p;
- p->head = tsize | PINUSE_BIT;
- if (p == fm->dv) {
- fm->dv = 0;
- fm->dvsize = 0;
- }
- if (should_trim(fm, tsize))
- sys_trim(fm, 0);
- goto postaction;
- }
- else if (next == fm->dv) {
- size_t dsize = fm->dvsize += psize;
- fm->dv = p;
- set_size_and_pinuse_of_free_chunk(p, dsize);
- goto postaction;
- }
- else {
- size_t nsize = chunksize(next);
- psize += nsize;
- unlink_chunk(fm, next, nsize);
- set_size_and_pinuse_of_free_chunk(p, psize);
- if (p == fm->dv) {
- fm->dvsize = psize;
- goto postaction;
- }
- }
- }
- else
- set_free_with_pinuse(p, psize, next);
-
- if (is_small(psize)) {
- insert_small_chunk(fm, p, psize);
- check_free_chunk(fm, p);
- }
- else {
- tchunkptr tp = (tchunkptr)p;
- insert_large_chunk(fm, tp, psize);
- check_free_chunk(fm, p);
- if (--fm->release_checks == 0)
- release_unused_segments(fm);
- }
- goto postaction;
- }
- }
- erroraction:
- USAGE_ERROR_ACTION(fm, p);
- postaction:
- POSTACTION(fm);
- }
- }
-}
-
-void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {
- void* mem;
- size_t req = 0;
- mstate ms = (mstate)msp;
- if (!ok_magic(ms)) {
- USAGE_ERROR_ACTION(ms,ms);
- return 0;
- }
- if (n_elements != 0) {
- req = n_elements * elem_size;
- if (((n_elements | elem_size) & ~(size_t)0xffff) &&
- (req / n_elements != elem_size))
- req = MAX_SIZE_T; /* force downstream failure on overflow */
- }
- mem = internal_malloc(ms, req);
- if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
- memset(mem, 0, req);
- return mem;
-}
-
-void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {
- void* mem = 0;
- if (oldmem == 0) {
- mem = mspace_malloc(msp, bytes);
- }
- else if (bytes >= MAX_REQUEST) {
- MALLOC_FAILURE_ACTION;
- }
-#ifdef REALLOC_ZERO_BYTES_FREES
- else if (bytes == 0) {
- mspace_free(msp, oldmem);
- }
-#endif /* REALLOC_ZERO_BYTES_FREES */
- else {
- size_t nb = request2size(bytes);
- mchunkptr oldp = mem2chunk(oldmem);
-#if ! FOOTERS
- mstate m = (mstate)msp;
-#else /* FOOTERS */
- mstate m = get_mstate_for(oldp);
- if (!ok_magic(m)) {
- USAGE_ERROR_ACTION(m, oldmem);
- return 0;
- }
-#endif /* FOOTERS */
- if (!PREACTION(m)) {
- mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1);
- POSTACTION(m);
- if (newp != 0) {
- check_inuse_chunk(m, newp);
- mem = chunk2mem(newp);
- }
- else {
- mem = mspace_malloc(m, bytes);
- if (mem != 0) {
- size_t oc = chunksize(oldp) - overhead_for(oldp);
- memcpy(mem, oldmem, (oc < bytes)? oc : bytes);
- mspace_free(m, oldmem);
- }
- }
- }
- }
- return mem;
-}
-
-void* mspace_realloc_in_place(mspace msp, void* oldmem, size_t bytes) {
- void* mem = 0;
- if (oldmem != 0) {
- if (bytes >= MAX_REQUEST) {
- MALLOC_FAILURE_ACTION;
- }
- else {
- size_t nb = request2size(bytes);
- mchunkptr oldp = mem2chunk(oldmem);
-#if ! FOOTERS
- mstate m = (mstate)msp;
-#else /* FOOTERS */
- mstate m = get_mstate_for(oldp);
- (void)msp; /* placate people compiling -Wunused */
- if (!ok_magic(m)) {
- USAGE_ERROR_ACTION(m, oldmem);
- return 0;
- }
-#endif /* FOOTERS */
- if (!PREACTION(m)) {
- mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0);
- POSTACTION(m);
- if (newp == oldp) {
- check_inuse_chunk(m, newp);
- mem = oldmem;
- }
- }
- }
- }
- return mem;
-}
-
-void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {
- mstate ms = (mstate)msp;
- if (!ok_magic(ms)) {
- USAGE_ERROR_ACTION(ms,ms);
- return 0;
- }
- if (alignment <= MALLOC_ALIGNMENT)
- return mspace_malloc(msp, bytes);
- return internal_memalign(ms, alignment, bytes);
-}
-
-void** mspace_independent_calloc(mspace msp, size_t n_elements,
- size_t elem_size, void* chunks[]) {
- size_t sz = elem_size; /* serves as 1-element array */
- mstate ms = (mstate)msp;
- if (!ok_magic(ms)) {
- USAGE_ERROR_ACTION(ms,ms);
- return 0;
- }
- return ialloc(ms, n_elements, &sz, 3, chunks);
-}
-
-void** mspace_independent_comalloc(mspace msp, size_t n_elements,
- size_t sizes[], void* chunks[]) {
- mstate ms = (mstate)msp;
- if (!ok_magic(ms)) {
- USAGE_ERROR_ACTION(ms,ms);
- return 0;
- }
- return ialloc(ms, n_elements, sizes, 0, chunks);
-}
-
-size_t mspace_bulk_free(mspace msp, void* array[], size_t nelem) {
- return internal_bulk_free((mstate)msp, array, nelem);
-}
-
-#if MALLOC_INSPECT_ALL
-void mspace_inspect_all(mspace msp,
- void(*handler)(void *start,
- void *end,
- size_t used_bytes,
- void* callback_arg),
- void* arg) {
- mstate ms = (mstate)msp;
- if (ok_magic(ms)) {
- if (!PREACTION(ms)) {
- internal_inspect_all(ms, handler, arg);
- POSTACTION(ms);
- }
- }
- else {
- USAGE_ERROR_ACTION(ms,ms);
- }
-}
-#endif /* MALLOC_INSPECT_ALL */
-
-int mspace_trim(mspace msp, size_t pad) {
- int result = 0;
- mstate ms = (mstate)msp;
- if (ok_magic(ms)) {
- if (!PREACTION(ms)) {
- result = sys_trim(ms, pad);
- POSTACTION(ms);
- }
- }
- else {
- USAGE_ERROR_ACTION(ms,ms);
- }
- return result;
-}
-
-#if !NO_MALLOC_STATS
-void mspace_malloc_stats(mspace msp) {
- mstate ms = (mstate)msp;
- if (ok_magic(ms)) {
- internal_malloc_stats(ms);
- }
- else {
- USAGE_ERROR_ACTION(ms,ms);
- }
-}
-#endif /* NO_MALLOC_STATS */
-
-size_t mspace_footprint(mspace msp) {
- size_t result = 0;
- mstate ms = (mstate)msp;
- if (ok_magic(ms)) {
- result = ms->footprint;
- }
- else {
- USAGE_ERROR_ACTION(ms,ms);
- }
- return result;
-}
-
-size_t mspace_max_footprint(mspace msp) {
- size_t result = 0;
- mstate ms = (mstate)msp;
- if (ok_magic(ms)) {
- result = ms->max_footprint;
- }
- else {
- USAGE_ERROR_ACTION(ms,ms);
- }
- return result;
-}
-
-size_t mspace_footprint_limit(mspace msp) {
- size_t result = 0;
- mstate ms = (mstate)msp;
- if (ok_magic(ms)) {
- size_t maf = ms->footprint_limit;
- result = (maf == 0) ? MAX_SIZE_T : maf;
- }
- else {
- USAGE_ERROR_ACTION(ms,ms);
- }
- return result;
-}
-
-size_t mspace_set_footprint_limit(mspace msp, size_t bytes) {
- size_t result = 0;
- mstate ms = (mstate)msp;
- if (ok_magic(ms)) {
- if (bytes == 0)
- result = granularity_align(1); /* Use minimal size */
- if (bytes == MAX_SIZE_T)
- result = 0; /* disable */
- else
- result = granularity_align(bytes);
- ms->footprint_limit = result;
- }
- else {
- USAGE_ERROR_ACTION(ms,ms);
- }
- return result;
-}
-
-#if !NO_MALLINFO
-struct mallinfo mspace_mallinfo(mspace msp) {
- mstate ms = (mstate)msp;
- if (!ok_magic(ms)) {
- USAGE_ERROR_ACTION(ms,ms);
- }
- return internal_mallinfo(ms);
-}
-#endif /* NO_MALLINFO */
-
-size_t mspace_usable_size(const void* mem) {
- if (mem != 0) {
- mchunkptr p = mem2chunk(mem);
- if (is_inuse(p))
- return chunksize(p) - overhead_for(p);
- }
- return 0;
-}
-
-int mspace_mallopt(int param_number, int value) {
- return change_mparam(param_number, value);
-}
-
-#endif /* MSPACES */
-
-
-/* -------------------- Alternative MORECORE functions ------------------- */
-
-/*
- Guidelines for creating a custom version of MORECORE:
-
- * For best performance, MORECORE should allocate in multiples of pagesize.
- * MORECORE may allocate more memory than requested. (Or even less,
- but this will usually result in a malloc failure.)
- * MORECORE must not allocate memory when given argument zero, but
- instead return one past the end address of memory from previous
- nonzero call.
- * For best performance, consecutive calls to MORECORE with positive
- arguments should return increasing addresses, indicating that
- space has been contiguously extended.
- * Even though consecutive calls to MORECORE need not return contiguous
- addresses, it must be OK for malloc'ed chunks to span multiple
- regions in those cases where they do happen to be contiguous.
- * MORECORE need not handle negative arguments -- it may instead
- just return MFAIL when given negative arguments.
- Negative arguments are always multiples of pagesize. MORECORE
- must not misinterpret negative args as large positive unsigned
- args. You can suppress all such calls from even occurring by defining
- MORECORE_CANNOT_TRIM,
-
- As an example alternative MORECORE, here is a custom allocator
- kindly contributed for pre-OSX macOS. It uses virtually but not
- necessarily physically contiguous non-paged memory (locked in,
- present and won't get swapped out). You can use it by uncommenting
- this section, adding some #includes, and setting up the appropriate
- defines above:
-
- #define MORECORE osMoreCore
-
- There is also a shutdown routine that should somehow be called for
- cleanup upon program exit.
-
- #define MAX_POOL_ENTRIES 100
- #define MINIMUM_MORECORE_SIZE (64 * 1024U)
- static int next_os_pool;
- void *our_os_pools[MAX_POOL_ENTRIES];
-
- void *osMoreCore(int size)
- {
- void *ptr = 0;
- static void *sbrk_top = 0;
-
- if (size > 0)
- {
- if (size < MINIMUM_MORECORE_SIZE)
- size = MINIMUM_MORECORE_SIZE;
- if (CurrentExecutionLevel() == kTaskLevel)
- ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);
- if (ptr == 0)
- {
- return (void *) MFAIL;
- }
- // save ptrs so they can be freed during cleanup
- our_os_pools[next_os_pool] = ptr;
- next_os_pool++;
- ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);
- sbrk_top = (char *) ptr + size;
- return ptr;
- }
- else if (size < 0)
- {
- // we don't currently support shrink behavior
- return (void *) MFAIL;
- }
- else
- {
- return sbrk_top;
- }
- }
-
- // cleanup any allocated memory pools
- // called as last thing before shutting down driver
-
- void osCleanupMem(void)
- {
- void **ptr;
-
- for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)
- if (*ptr)
- {
- PoolDeallocate(*ptr);
- *ptr = 0;
- }
- }
-
-*/
-
-
-/* -----------------------------------------------------------------------
-History:
- v2.8.6 Wed Aug 29 06:57:58 2012 Doug Lea
- * fix bad comparison in dlposix_memalign
- * don't reuse adjusted asize in sys_alloc
- * add LOCK_AT_FORK -- thanks to Kirill Artamonov for the suggestion
- * reduce compiler warnings -- thanks to all who reported/suggested these
-
- v2.8.5 Sun May 22 10:26:02 2011 Doug Lea (dl at gee)
- * Always perform unlink checks unless INSECURE
- * Add posix_memalign.
- * Improve realloc to expand in more cases; expose realloc_in_place.
- Thanks to Peter Buhr for the suggestion.
- * Add footprint_limit, inspect_all, bulk_free. Thanks
- to Barry Hayes and others for the suggestions.
- * Internal refactorings to avoid calls while holding locks
- * Use non-reentrant locks by default. Thanks to Roland McGrath
- for the suggestion.
- * Small fixes to mspace_destroy, reset_on_error.
- * Various configuration extensions/changes. Thanks
- to all who contributed these.
-
- V2.8.4a Thu Apr 28 14:39:43 2011 (dl at gee.cs.oswego.edu)
- * Update Creative Commons URL
-
- V2.8.4 Wed May 27 09:56:23 2009 Doug Lea (dl at gee)
- * Use zeros instead of prev foot for is_mmapped
- * Add mspace_track_large_chunks; thanks to Jean Brouwers
- * Fix set_inuse in internal_realloc; thanks to Jean Brouwers
- * Fix insufficient sys_alloc padding when using 16byte alignment
- * Fix bad error check in mspace_footprint
- * Adaptations for ptmalloc; thanks to Wolfram Gloger.
- * Reentrant spin locks; thanks to Earl Chew and others
- * Win32 improvements; thanks to Niall Douglas and Earl Chew
- * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options
- * Extension hook in malloc_state
- * Various small adjustments to reduce warnings on some compilers
- * Various configuration extensions/changes for more platforms. Thanks
- to all who contributed these.
-
- V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee)
- * Add max_footprint functions
- * Ensure all appropriate literals are size_t
- * Fix conditional compilation problem for some #define settings
- * Avoid concatenating segments with the one provided
- in create_mspace_with_base
- * Rename some variables to avoid compiler shadowing warnings
- * Use explicit lock initialization.
- * Better handling of sbrk interference.
- * Simplify and fix segment insertion, trimming and mspace_destroy
- * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x
- * Thanks especially to Dennis Flanagan for help on these.
-
- V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee)
- * Fix memalign brace error.
-
- V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee)
- * Fix improper #endif nesting in C++
- * Add explicit casts needed for C++
-
- V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee)
- * Use trees for large bins
- * Support mspaces
- * Use segments to unify sbrk-based and mmap-based system allocation,
- removing need for emulation on most platforms without sbrk.
- * Default safety checks
- * Optional footer checks. Thanks to William Robertson for the idea.
- * Internal code refactoring
- * Incorporate suggestions and platform-specific changes.
- Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas,
- Aaron Bachmann, Emery Berger, and others.
- * Speed up non-fastbin processing enough to remove fastbins.
- * Remove useless cfree() to avoid conflicts with other apps.
- * Remove internal memcpy, memset. Compilers handle builtins better.
- * Remove some options that no one ever used and rename others.
-
- V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee)
- * Fix malloc_state bitmap array misdeclaration
-
- V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee)
- * Allow tuning of FIRST_SORTED_BIN_SIZE
- * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte.
- * Better detection and support for non-contiguousness of MORECORE.
- Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger
- * Bypass most of malloc if no frees. Thanks To Emery Berger.
- * Fix freeing of old top non-contiguous chunk im sysmalloc.
- * Raised default trim and map thresholds to 256K.
- * Fix mmap-related #defines. Thanks to Lubos Lunak.
- * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield.
- * Branch-free bin calculation
- * Default trim and mmap thresholds now 256K.
-
- V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee)
- * Introduce independent_comalloc and independent_calloc.
- Thanks to Michael Pachos for motivation and help.
- * Make optional .h file available
- * Allow > 2GB requests on 32bit systems.
- * new WIN32 sbrk, mmap, munmap, lock code from <[email protected]>.
- Thanks also to Andreas Mueller <a.mueller at paradatec.de>,
- and Anonymous.
- * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for
- helping test this.)
- * memalign: check alignment arg
- * realloc: don't try to shift chunks backwards, since this
- leads to more fragmentation in some programs and doesn't
- seem to help in any others.
- * Collect all cases in malloc requiring system memory into sysmalloc
- * Use mmap as backup to sbrk
- * Place all internal state in malloc_state
- * Introduce fastbins (although similar to 2.5.1)
- * Many minor tunings and cosmetic improvements
- * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK
- * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS
- Thanks to Tony E. Bennett <[email protected]> and others.
- * Include errno.h to support default failure action.
-
- V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee)
- * return null for negative arguments
- * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>
- * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
- (e.g. WIN32 platforms)
- * Cleanup header file inclusion for WIN32 platforms
- * Cleanup code to avoid Microsoft Visual C++ compiler complaints
- * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
- memory allocation routines
- * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
- * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
- usage of 'assert' in non-WIN32 code
- * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
- avoid infinite loop
- * Always call 'fREe()' rather than 'free()'
-
- V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee)
- * Fixed ordering problem with boundary-stamping
-
- V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
- * Added pvalloc, as recommended by H.J. Liu
- * Added 64bit pointer support mainly from Wolfram Gloger
- * Added anonymously donated WIN32 sbrk emulation
- * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
- * malloc_extend_top: fix mask error that caused wastage after
- foreign sbrks
- * Add linux mremap support code from HJ Liu
-
- V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
- * Integrated most documentation with the code.
- * Add support for mmap, with help from
- Wolfram Gloger ([email protected]).
- * Use last_remainder in more cases.
- * Pack bins using idea from [email protected]
- * Use ordered bins instead of best-fit threshhold
- * Eliminate block-local decls to simplify tracing and debugging.
- * Support another case of realloc via move into top
- * Fix error occuring when initial sbrk_base not word-aligned.
- * Rely on page size for units instead of SBRK_UNIT to
- avoid surprises about sbrk alignment conventions.
- * Add mallinfo, mallopt. Thanks to Raymond Nijssen
- ([email protected]) for the suggestion.
- * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
- * More precautions for cases where other routines call sbrk,
- courtesy of Wolfram Gloger ([email protected]).
- * Added macros etc., allowing use in linux libc from
- H.J. Lu ([email protected])
- * Inverted this history list
-
- V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
- * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
- * Removed all preallocation code since under current scheme
- the work required to undo bad preallocations exceeds
- the work saved in good cases for most test programs.
- * No longer use return list or unconsolidated bins since
- no scheme using them consistently outperforms those that don't
- given above changes.
- * Use best fit for very large chunks to prevent some worst-cases.
- * Added some support for debugging
-
- V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
- * Removed footers when chunks are in use. Thanks to
- Paul Wilson ([email protected]) for the suggestion.
-
- V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
- * Added malloc_trim, with help from Wolfram Gloger
-
- V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
-
- V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
- * realloc: try to expand in both directions
- * malloc: swap order of clean-bin strategy;
- * realloc: only conditionally expand backwards
- * Try not to scavenge used bins
- * Use bin counts as a guide to preallocation
- * Occasionally bin return list chunks in first scan
- * Add a few optimizations from [email protected]
-
- V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
- * faster bin computation & slightly different binning
- * merged all consolidations to one part of malloc proper
- (eliminating old malloc_find_space & malloc_clean_bin)
- * Scan 2 returns chunks (not just 1)
- * Propagate failure in realloc if malloc returns 0
- * Add stuff to allow compilation on non-ANSI compilers
-
- V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
- * removed potential for odd address access in prev_chunk
- * removed dependency on getpagesize.h
- * misc cosmetics and a bit more internal documentation
- * anticosmetics: mangled names in macros to evade debugger strangeness
- * tested on sparc, hp-700, dec-mips, rs6000
- with gcc & native cc (hp, dec only) allowing
- Detlefs & Zorn comparison study (in SIGPLAN Notices.)
-
- Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
- * Based loosely on libg++-1.2X malloc. (It retains some of the overall
- structure of old version, but most details differ.)
-
-*/
diff --git a/src/user/lib/vendor/dlmalloc/malloc.h b/src/user/lib/vendor/dlmalloc/malloc.h
deleted file mode 100644
index e52c9e5..0000000
--- a/src/user/lib/vendor/dlmalloc/malloc.h
+++ /dev/null
@@ -1,620 +0,0 @@
-/*
- Default header file for malloc-2.8.x, written by Doug Lea
- and released to the public domain, as explained at
- http://creativecommons.org/publicdomain/zero/1.0/
-
- This header is for ANSI C/C++ only. You can set any of
- the following #defines before including:
-
- * If USE_DL_PREFIX is defined, it is assumed that malloc.c
- was also compiled with this option, so all routines
- have names starting with "dl".
-
- * If HAVE_USR_INCLUDE_MALLOC_H is defined, it is assumed that this
- file will be #included AFTER <malloc.h>. This is needed only if
- your system defines a struct mallinfo that is incompatible with the
- standard one declared here. Otherwise, you can include this file
- INSTEAD of your system system <malloc.h>. At least on ANSI, all
- declarations should be compatible with system versions
-
- * If MSPACES is defined, declarations for mspace versions are included.
-*/
-
-#ifndef MALLOC_280_H
-#define MALLOC_280_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stddef.h> /* for size_t */
-
-#ifndef ONLY_MSPACES
-#define ONLY_MSPACES 0 /* define to a value */
-#elif ONLY_MSPACES != 0
-#define ONLY_MSPACES 1
-#endif /* ONLY_MSPACES */
-#ifndef NO_MALLINFO
-#define NO_MALLINFO 0
-#endif /* NO_MALLINFO */
-
-#ifndef MSPACES
-#if ONLY_MSPACES
-#define MSPACES 1
-#else /* ONLY_MSPACES */
-#define MSPACES 0
-#endif /* ONLY_MSPACES */
-#endif /* MSPACES */
-
-#if !ONLY_MSPACES
-
-#ifndef USE_DL_PREFIX
-#define dlcalloc calloc
-#define dlfree free
-#define dlmalloc malloc
-#define dlmemalign memalign
-#define dlposix_memalign posix_memalign
-#define dlrealloc realloc
-#define dlvalloc valloc
-#define dlpvalloc pvalloc
-#define dlmallinfo mallinfo
-#define dlmallopt mallopt
-#define dlmalloc_trim malloc_trim
-#define dlmalloc_stats malloc_stats
-#define dlmalloc_usable_size malloc_usable_size
-#define dlmalloc_footprint malloc_footprint
-#define dlmalloc_max_footprint malloc_max_footprint
-#define dlmalloc_footprint_limit malloc_footprint_limit
-#define dlmalloc_set_footprint_limit malloc_set_footprint_limit
-#define dlmalloc_inspect_all malloc_inspect_all
-#define dlindependent_calloc independent_calloc
-#define dlindependent_comalloc independent_comalloc
-#define dlbulk_free bulk_free
-#endif /* USE_DL_PREFIX */
-
-#if !NO_MALLINFO
-#ifndef HAVE_USR_INCLUDE_MALLOC_H
-#ifndef _MALLOC_H
-#ifndef MALLINFO_FIELD_TYPE
-#define MALLINFO_FIELD_TYPE size_t
-#endif /* MALLINFO_FIELD_TYPE */
-#ifndef STRUCT_MALLINFO_DECLARED
-#define STRUCT_MALLINFO_DECLARED 1
-struct mallinfo {
- MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */
- MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */
- MALLINFO_FIELD_TYPE smblks; /* always 0 */
- MALLINFO_FIELD_TYPE hblks; /* always 0 */
- MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */
- MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */
- MALLINFO_FIELD_TYPE fsmblks; /* always 0 */
- MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
- MALLINFO_FIELD_TYPE fordblks; /* total free space */
- MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
-};
-#endif /* STRUCT_MALLINFO_DECLARED */
-#endif /* _MALLOC_H */
-#endif /* HAVE_USR_INCLUDE_MALLOC_H */
-#endif /* !NO_MALLINFO */
-
-/*
- malloc(size_t n)
- Returns a pointer to a newly allocated chunk of at least n bytes, or
- null if no space is available, in which case errno is set to ENOMEM
- on ANSI C systems.
-
- If n is zero, malloc returns a minimum-sized chunk. (The minimum
- size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
- systems.) Note that size_t is an unsigned type, so calls with
- arguments that would be negative if signed are interpreted as
- requests for huge amounts of space, which will often fail. The
- maximum supported value of n differs across systems, but is in all
- cases less than the maximum representable value of a size_t.
-*/
-void* dlmalloc(size_t);
-
-/*
- free(void* p)
- Releases the chunk of memory pointed to by p, that had been previously
- allocated using malloc or a related routine such as realloc.
- It has no effect if p is null. If p was not malloced or already
- freed, free(p) will by default cuase the current program to abort.
-*/
-void dlfree(void*);
-
-/*
- calloc(size_t n_elements, size_t element_size);
- Returns a pointer to n_elements * element_size bytes, with all locations
- set to zero.
-*/
-void* dlcalloc(size_t, size_t);
-
-/*
- realloc(void* p, size_t n)
- Returns a pointer to a chunk of size n that contains the same data
- as does chunk p up to the minimum of (n, p's size) bytes, or null
- if no space is available.
-
- The returned pointer may or may not be the same as p. The algorithm
- prefers extending p in most cases when possible, otherwise it
- employs the equivalent of a malloc-copy-free sequence.
-
- If p is null, realloc is equivalent to malloc.
-
- If space is not available, realloc returns null, errno is set (if on
- ANSI) and p is NOT freed.
-
- if n is for fewer bytes than already held by p, the newly unused
- space is lopped off and freed if possible. realloc with a size
- argument of zero (re)allocates a minimum-sized chunk.
-
- The old unix realloc convention of allowing the last-free'd chunk
- to be used as an argument to realloc is not supported.
-*/
-void* dlrealloc(void*, size_t);
-
-/*
- realloc_in_place(void* p, size_t n)
- Resizes the space allocated for p to size n, only if this can be
- done without moving p (i.e., only if there is adjacent space
- available if n is greater than p's current allocated size, or n is
- less than or equal to p's size). This may be used instead of plain
- realloc if an alternative allocation strategy is needed upon failure
- to expand space; for example, reallocation of a buffer that must be
- memory-aligned or cleared. You can use realloc_in_place to trigger
- these alternatives only when needed.
-
- Returns p if successful; otherwise null.
-*/
-void* dlrealloc_in_place(void*, size_t);
-
-/*
- memalign(size_t alignment, size_t n);
- Returns a pointer to a newly allocated chunk of n bytes, aligned
- in accord with the alignment argument.
-
- The alignment argument should be a power of two. If the argument is
- not a power of two, the nearest greater power is used.
- 8-byte alignment is guaranteed by normal malloc calls, so don't
- bother calling memalign with an argument of 8 or less.
-
- Overreliance on memalign is a sure way to fragment space.
-*/
-void* dlmemalign(size_t, size_t);
-
-/*
- int posix_memalign(void** pp, size_t alignment, size_t n);
- Allocates a chunk of n bytes, aligned in accord with the alignment
- argument. Differs from memalign only in that it (1) assigns the
- allocated memory to *pp rather than returning it, (2) fails and
- returns EINVAL if the alignment is not a power of two (3) fails and
- returns ENOMEM if memory cannot be allocated.
-*/
-int dlposix_memalign(void**, size_t, size_t);
-
-/*
- valloc(size_t n);
- Equivalent to memalign(pagesize, n), where pagesize is the page
- size of the system. If the pagesize is unknown, 4096 is used.
-*/
-void* dlvalloc(size_t);
-
-/*
- mallopt(int parameter_number, int parameter_value)
- Sets tunable parameters The format is to provide a
- (parameter-number, parameter-value) pair. mallopt then sets the
- corresponding parameter to the argument value if it can (i.e., so
- long as the value is meaningful), and returns 1 if successful else
- 0. SVID/XPG/ANSI defines four standard param numbers for mallopt,
- normally defined in malloc.h. None of these are use in this malloc,
- so setting them has no effect. But this malloc also supports other
- options in mallopt:
-
- Symbol param # default allowed param values
- M_TRIM_THRESHOLD -1 2*1024*1024 any (-1U disables trimming)
- M_GRANULARITY -2 page size any power of 2 >= page size
- M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support)
-*/
-int dlmallopt(int, int);
-
-#define M_TRIM_THRESHOLD (-1)
-#define M_GRANULARITY (-2)
-#define M_MMAP_THRESHOLD (-3)
-
-
-/*
- malloc_footprint();
- Returns the number of bytes obtained from the system. The total
- number of bytes allocated by malloc, realloc etc., is less than this
- value. Unlike mallinfo, this function returns only a precomputed
- result, so can be called frequently to monitor memory consumption.
- Even if locks are otherwise defined, this function does not use them,
- so results might not be up to date.
-*/
-size_t dlmalloc_footprint(void);
-
-/*
- malloc_max_footprint();
- Returns the maximum number of bytes obtained from the system. This
- value will be greater than current footprint if deallocated space
- has been reclaimed by the system. The peak number of bytes allocated
- by malloc, realloc etc., is less than this value. Unlike mallinfo,
- this function returns only a precomputed result, so can be called
- frequently to monitor memory consumption. Even if locks are
- otherwise defined, this function does not use them, so results might
- not be up to date.
-*/
-size_t dlmalloc_max_footprint(void);
-
-/*
- malloc_footprint_limit();
- Returns the number of bytes that the heap is allowed to obtain from
- the system, returning the last value returned by
- malloc_set_footprint_limit, or the maximum size_t value if
- never set. The returned value reflects a permission. There is no
- guarantee that this number of bytes can actually be obtained from
- the system.
-*/
-size_t dlmalloc_footprint_limit(void);
-
-/*
- malloc_set_footprint_limit();
- Sets the maximum number of bytes to obtain from the system, causing
- failure returns from malloc and related functions upon attempts to
- exceed this value. The argument value may be subject to page
- rounding to an enforceable limit; this actual value is returned.
- Using an argument of the maximum possible size_t effectively
- disables checks. If the argument is less than or equal to the
- current malloc_footprint, then all future allocations that require
- additional system memory will fail. However, invocation cannot
- retroactively deallocate existing used memory.
-*/
-size_t dlmalloc_set_footprint_limit(size_t bytes);
-
-/*
- malloc_inspect_all(void(*handler)(void *start,
- void *end,
- size_t used_bytes,
- void* callback_arg),
- void* arg);
- Traverses the heap and calls the given handler for each managed
- region, skipping all bytes that are (or may be) used for bookkeeping
- purposes. Traversal does not include include chunks that have been
- directly memory mapped. Each reported region begins at the start
- address, and continues up to but not including the end address. The
- first used_bytes of the region contain allocated data. If
- used_bytes is zero, the region is unallocated. The handler is
- invoked with the given callback argument. If locks are defined, they
- are held during the entire traversal. It is a bad idea to invoke
- other malloc functions from within the handler.
-
- For example, to count the number of in-use chunks with size greater
- than 1000, you could write:
- static int count = 0;
- void count_chunks(void* start, void* end, size_t used, void* arg) {
- if (used >= 1000) ++count;
- }
- then:
- malloc_inspect_all(count_chunks, NULL);
-
- malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined.
-*/
-void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),
- void* arg);
-
-#if !NO_MALLINFO
-/*
- mallinfo()
- Returns (by copy) a struct containing various summary statistics:
-
- arena: current total non-mmapped bytes allocated from system
- ordblks: the number of free chunks
- smblks: always zero.
- hblks: current number of mmapped regions
- hblkhd: total bytes held in mmapped regions
- usmblks: the maximum total allocated space. This will be greater
- than current total if trimming has occurred.
- fsmblks: always zero
- uordblks: current total allocated space (normal or mmapped)
- fordblks: total free space
- keepcost: the maximum number of bytes that could ideally be released
- back to system via malloc_trim. ("ideally" means that
- it ignores page restrictions etc.)
-
- Because these fields are ints, but internal bookkeeping may
- be kept as longs, the reported values may wrap around zero and
- thus be inaccurate.
-*/
-
-struct mallinfo dlmallinfo(void);
-#endif /* NO_MALLINFO */
-
-/*
- independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
-
- independent_calloc is similar to calloc, but instead of returning a
- single cleared space, it returns an array of pointers to n_elements
- independent elements that can hold contents of size elem_size, each
- of which starts out cleared, and can be independently freed,
- realloc'ed etc. The elements are guaranteed to be adjacently
- allocated (this is not guaranteed to occur with multiple callocs or
- mallocs), which may also improve cache locality in some
- applications.
-
- The "chunks" argument is optional (i.e., may be null, which is
- probably the most typical usage). If it is null, the returned array
- is itself dynamically allocated and should also be freed when it is
- no longer needed. Otherwise, the chunks array must be of at least
- n_elements in length. It is filled in with the pointers to the
- chunks.
-
- In either case, independent_calloc returns this pointer array, or
- null if the allocation failed. If n_elements is zero and "chunks"
- is null, it returns a chunk representing an array with zero elements
- (which should be freed if not wanted).
-
- Each element must be freed when it is no longer needed. This can be
- done all at once using bulk_free.
-
- independent_calloc simplifies and speeds up implementations of many
- kinds of pools. It may also be useful when constructing large data
- structures that initially have a fixed number of fixed-sized nodes,
- but the number is not known at compile time, and some of the nodes
- may later need to be freed. For example:
-
- struct Node { int item; struct Node* next; };
-
- struct Node* build_list() {
- struct Node** pool;
- int n = read_number_of_nodes_needed();
- if (n <= 0) return 0;
- pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
- if (pool == 0) die();
- // organize into a linked list...
- struct Node* first = pool[0];
- for (i = 0; i < n-1; ++i)
- pool[i]->next = pool[i+1];
- free(pool); // Can now free the array (or not, if it is needed later)
- return first;
- }
-*/
-void** dlindependent_calloc(size_t, size_t, void**);
-
-/*
- independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
-
- independent_comalloc allocates, all at once, a set of n_elements
- chunks with sizes indicated in the "sizes" array. It returns
- an array of pointers to these elements, each of which can be
- independently freed, realloc'ed etc. The elements are guaranteed to
- be adjacently allocated (this is not guaranteed to occur with
- multiple callocs or mallocs), which may also improve cache locality
- in some applications.
-
- The "chunks" argument is optional (i.e., may be null). If it is null
- the returned array is itself dynamically allocated and should also
- be freed when it is no longer needed. Otherwise, the chunks array
- must be of at least n_elements in length. It is filled in with the
- pointers to the chunks.
-
- In either case, independent_comalloc returns this pointer array, or
- null if the allocation failed. If n_elements is zero and chunks is
- null, it returns a chunk representing an array with zero elements
- (which should be freed if not wanted).
-
- Each element must be freed when it is no longer needed. This can be
- done all at once using bulk_free.
-
- independent_comallac differs from independent_calloc in that each
- element may have a different size, and also that it does not
- automatically clear elements.
-
- independent_comalloc can be used to speed up allocation in cases
- where several structs or objects must always be allocated at the
- same time. For example:
-
- struct Head { ... }
- struct Foot { ... }
-
- void send_message(char* msg) {
- int msglen = strlen(msg);
- size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
- void* chunks[3];
- if (independent_comalloc(3, sizes, chunks) == 0)
- die();
- struct Head* head = (struct Head*)(chunks[0]);
- char* body = (char*)(chunks[1]);
- struct Foot* foot = (struct Foot*)(chunks[2]);
- // ...
- }
-
- In general though, independent_comalloc is worth using only for
- larger values of n_elements. For small values, you probably won't
- detect enough difference from series of malloc calls to bother.
-
- Overuse of independent_comalloc can increase overall memory usage,
- since it cannot reuse existing noncontiguous small chunks that
- might be available for some of the elements.
-*/
-void** dlindependent_comalloc(size_t, size_t*, void**);
-
-/*
- bulk_free(void* array[], size_t n_elements)
- Frees and clears (sets to null) each non-null pointer in the given
- array. This is likely to be faster than freeing them one-by-one.
- If footers are used, pointers that have been allocated in different
- mspaces are not freed or cleared, and the count of all such pointers
- is returned. For large arrays of pointers with poor locality, it
- may be worthwhile to sort this array before calling bulk_free.
-*/
-size_t dlbulk_free(void**, size_t n_elements);
-
-/*
- pvalloc(size_t n);
- Equivalent to valloc(minimum-page-that-holds(n)), that is,
- round up n to nearest pagesize.
- */
-void* dlpvalloc(size_t);
-
-/*
- malloc_trim(size_t pad);
-
- If possible, gives memory back to the system (via negative arguments
- to sbrk) if there is unused memory at the `high' end of the malloc
- pool or in unused MMAP segments. You can call this after freeing
- large blocks of memory to potentially reduce the system-level memory
- requirements of a program. However, it cannot guarantee to reduce
- memory. Under some allocation patterns, some large free blocks of
- memory will be locked between two used chunks, so they cannot be
- given back to the system.
-
- The `pad' argument to malloc_trim represents the amount of free
- trailing space to leave untrimmed. If this argument is zero, only
- the minimum amount of memory to maintain internal data structures
- will be left. Non-zero arguments can be supplied to maintain enough
- trailing space to service future expected allocations without having
- to re-obtain memory from the system.
-
- Malloc_trim returns 1 if it actually released any memory, else 0.
-*/
-int dlmalloc_trim(size_t);
-
-/*
- malloc_stats();
- Prints on stderr the amount of space obtained from the system (both
- via sbrk and mmap), the maximum amount (which may be more than
- current if malloc_trim and/or munmap got called), and the current
- number of bytes allocated via malloc (or realloc, etc) but not yet
- freed. Note that this is the number of bytes allocated, not the
- number requested. It will be larger than the number requested
- because of alignment and bookkeeping overhead. Because it includes
- alignment wastage as being in use, this figure may be greater than
- zero even when no user-level chunks are allocated.
-
- The reported current and maximum system memory can be inaccurate if
- a program makes other calls to system memory allocation functions
- (normally sbrk) outside of malloc.
-
- malloc_stats prints only the most commonly interesting statistics.
- More information can be obtained by calling mallinfo.
-
- malloc_stats is not compiled if NO_MALLOC_STATS is defined.
-*/
-void dlmalloc_stats(void);
-
-#endif /* !ONLY_MSPACES */
-
-/*
- malloc_usable_size(void* p);
-
- Returns the number of bytes you can actually use in
- an allocated chunk, which may be more than you requested (although
- often not) due to alignment and minimum size constraints.
- You can use this many bytes without worrying about
- overwriting other allocated objects. This is not a particularly great
- programming practice. malloc_usable_size can be more useful in
- debugging and assertions, for example:
-
- p = malloc(n);
- assert(malloc_usable_size(p) >= 256);
-*/
-size_t dlmalloc_usable_size(const void*);
-
-#if MSPACES
-
-/*
- mspace is an opaque type representing an independent
- region of space that supports mspace_malloc, etc.
-*/
-typedef void* mspace;
-
-/*
- create_mspace creates and returns a new independent space with the
- given initial capacity, or, if 0, the default granularity size. It
- returns null if there is no system memory available to create the
- space. If argument locked is non-zero, the space uses a separate
- lock to control access. The capacity of the space will grow
- dynamically as needed to service mspace_malloc requests. You can
- control the sizes of incremental increases of this space by
- compiling with a different DEFAULT_GRANULARITY or dynamically
- setting with mallopt(M_GRANULARITY, value).
-*/
-mspace create_mspace(size_t capacity, int locked);
-
-/*
- destroy_mspace destroys the given space, and attempts to return all
- of its memory back to the system, returning the total number of
- bytes freed. After destruction, the results of access to all memory
- used by the space become undefined.
-*/
-size_t destroy_mspace(mspace msp);
-
-/*
- create_mspace_with_base uses the memory supplied as the initial base
- of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
- space is used for bookkeeping, so the capacity must be at least this
- large. (Otherwise 0 is returned.) When this initial space is
- exhausted, additional memory will be obtained from the system.
- Destroying this space will deallocate all additionally allocated
- space (if possible) but not the initial base.
-*/
-mspace create_mspace_with_base(void* base, size_t capacity, int locked);
-
-/*
- mspace_track_large_chunks controls whether requests for large chunks
- are allocated in their own untracked mmapped regions, separate from
- others in this mspace. By default large chunks are not tracked,
- which reduces fragmentation. However, such chunks are not
- necessarily released to the system upon destroy_mspace. Enabling
- tracking by setting to true may increase fragmentation, but avoids
- leakage when relying on destroy_mspace to release all memory
- allocated using this space. The function returns the previous
- setting.
-*/
-int mspace_track_large_chunks(mspace msp, int enable);
-
-#if !NO_MALLINFO
-/*
- mspace_mallinfo behaves as mallinfo, but reports properties of
- the given space.
-*/
-struct mallinfo mspace_mallinfo(mspace msp);
-#endif /* NO_MALLINFO */
-
-/*
- An alias for mallopt.
-*/
-int mspace_mallopt(int, int);
-
-/*
- The following operate identically to their malloc counterparts
- but operate only for the given mspace argument
-*/
-void* mspace_malloc(mspace msp, size_t bytes);
-void mspace_free(mspace msp, void* mem);
-void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
-void* mspace_realloc(mspace msp, void* mem, size_t newsize);
-void* mspace_realloc_in_place(mspace msp, void* mem, size_t newsize);
-void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
-void** mspace_independent_calloc(mspace msp, size_t n_elements,
- size_t elem_size, void* chunks[]);
-void** mspace_independent_comalloc(mspace msp, size_t n_elements,
- size_t sizes[], void* chunks[]);
-size_t mspace_bulk_free(mspace msp, void**, size_t n_elements);
-size_t mspace_usable_size(const void* mem);
-void mspace_malloc_stats(mspace msp);
-int mspace_trim(mspace msp, size_t pad);
-size_t mspace_footprint(mspace msp);
-size_t mspace_max_footprint(mspace msp);
-size_t mspace_footprint_limit(mspace msp);
-size_t mspace_set_footprint_limit(mspace msp, size_t bytes);
-void mspace_inspect_all(mspace msp,
- void(*handler)(void *, void *, size_t, void*),
- void* arg);
-#endif /* MSPACES */
-
-#ifdef __cplusplus
-}; /* end of extern "C" */
-#endif
-
-#endif /* MALLOC_280_H */
diff --git a/src/user/lib/vendor/getopt/getopt.c b/src/user/lib/vendor/getopt/getopt.c
deleted file mode 100644
index 63c9b51..0000000
--- a/src/user/lib/vendor/getopt/getopt.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* Adapted from https://github.com/skeeto/getopt by Chris Wellons */
-
-/* A minimal POSIX getopt() implementation in ANSI C
- *
- * This is free and unencumbered software released into the public domain.
- *
- * This implementation supports the convention of resetting the option
- * parser by assigning optind to 0. This resets the internal state
- * appropriately.
- *
- * Ref: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html
- */
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include "getopt.h"
-
-int optind;
-int opterr = 1;
-int optopt;
-char *optarg;
-
-int
-getopt(int argc, char * const argv[], const char *optstring)
-{
- static int optpos = 1;
- const char *arg;
-
- /* Reset? */
- if (optind == 0) {
- optind = !!argc;
- optpos = 1;
- }
-
- arg = argv[optind];
- if (arg && strcmp(arg, "--") == 0) {
- optind++;
- return -1;
- } else if (!arg || arg[0] != '-' || !isalnum(arg[1])) {
- return -1;
- } else {
- const char *opt = strchr(optstring, arg[optpos]);
- optopt = arg[optpos];
- if (!opt) {
- if (opterr && *optstring != ':')
- fprintf(stderr, "%s: illegal option: %c\n", argv[0], optopt);
- return '?';
- } else if (opt[1] == ':') {
- if (arg[optpos + 1]) {
- optarg = (char *)arg + optpos + 1;
- optind++;
- optpos = 1;
- return optopt;
- } else if (argv[optind + 1]) {
- optarg = (char *)argv[optind + 1];
- optind += 2;
- optpos = 1;
- return optopt;
- } else {
- if (opterr && *optstring != ':')
- fprintf(stderr,
- "%s: option requires an argument: %c\n",
- argv[0], optopt);
- return *optstring == ':' ? ':' : '?';
- }
- } else {
- if (!arg[++optpos]) {
- optind++;
- optpos = 1;
- }
- return optopt;
- }
- }
-}
-
diff --git a/src/user/lib/vendor/getopt/getopt.h b/src/user/lib/vendor/getopt/getopt.h
deleted file mode 100644
index 4cb075c..0000000
--- a/src/user/lib/vendor/getopt/getopt.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Adapted from https://github.com/skeeto/getopt by Chris Wellons */
-
-/* A minimal POSIX getopt() implementation in ANSI C
- *
- * This is free and unencumbered software released into the public domain.
- *
- * This implementation supports the convention of resetting the option
- * parser by assigning optind to 0. This resets the internal state
- * appropriately.
- *
- * Ref: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html
- */
-#ifndef GETOPT_H
-#define GETOPT_H
-
-extern int optind, opterr, optopt;
-extern char *optarg;
-
-int getopt(int argc, char * const argv[], const char *optstring);
-
-#endif
diff --git a/src/user/linker.ld b/src/user/linker.ld
deleted file mode 100644
index 4925448..0000000
--- a/src/user/linker.ld
+++ /dev/null
@@ -1,23 +0,0 @@
-ENTRY(_start)
-
-SECTIONS
-{
- __executable_start = .;
- .text BLOCK(4K) : ALIGN(4K)
- {
- *(.text)
- }
- .rodata BLOCK(4K) : ALIGN(4K)
- {
- *(.rodata)
- }
- .data BLOCK(4K) : ALIGN(4K)
- {
- *(.data)
- }
- .bss BLOCK(4K) : ALIGN(4K)
- {
- *(COMMON)
- *(.bss)
- }
-}