and simpler one stolen from K&R. libc builds now.
-local headers = {}
-
-local function addheader(dir, list)
- for _, f in ipairs(list) do
- local b = basename(f)
- headers[dir..b] = f
- end
-end
-
-addheader("", filenamesof("./headers/*.h"))
-addheader("sys/", filenamesof("./headers/sys/*.h"))
-
-acklibrary {
- name = "headers",
- hdrs = headers
-}
+include("plat/build.lua")
tabgen {
name = "ctype_tab",
"+ctype_files",
"+ctype_tab",
"./ctype/*.c",
- "./assert/*.c",
"./errno/*.c",
"./locale/*.c",
+ "./malloc/*.c",
"./math/*.c",
"./misc/environ.c", -- don't build everything here as it's all obsolete
"./setjmp/*.c",
"./setjmp/*.e",
"./signal/*.c",
+ "./assert/*.c",
"./stdio/*.c",
"./stdlib/*.c",
"./string/*.c",
},
hdrs = {}, -- must be empty
deps = {
- "+headers",
+ "lang/cem/libcc.ansi/headers+headers",
"plat/"..plat.."+headers",
},
vars = { plat = plat }
installable {
name = "pkg_"..plat,
map = {
+ "lang/cem/libcc.ansi/headers+pkg",
["$(PLATIND)/"..plat.."/c-ansi.o"] = "+crt_"..plat,
["$(PLATIND)/"..plat.."/libc.a"] = "+lib_"..plat,
}
--- /dev/null
+include("plat/build.lua")
+
+local headers = {}
+local installmap = {}
+
+local function addheader(dir, list)
+ for _, f in ipairs(list) do
+ local b = basename(f)
+ headers[dir..b] = f
+ installmap[concatpath("$(PLATIND)/include/ansi/", dir, b)] = f
+ end
+end
+
+addheader("", filenamesof("./*.h"))
+addheader("sys/", filenamesof("./sys/*.h"))
+
+acklibrary {
+ name = "headers",
+ hdrs = headers
+}
+
+installable {
+ name = "pkg",
+ map = installmap
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include "malloc.h"
+
+block_t __mem_root = {&__mem_root, 0};
+block_t* __mem_freelist = &__mem_root;
+
+/* Pulls more memory from the system. */
+
+static block_t* brkmore(size_t nb)
+{
+ uintptr_t bytes;
+ block_t* p;
+
+ if (nb < BRKSIZE)
+ nb = BRKSIZE;
+ bytes = nb * sizeof(block_t);
+
+ /* Danger, will robinson! sbrk's parameter is *signed*... but malloc() takes a
+ * size_t. */
+
+ if (bytes > INTPTR_MAX)
+ return NULL;
+
+ p = sbrk(bytes);
+ if (p == (block_t*)-1)
+ return NULL;
+
+ /* Add it to the free list by pretending it's a used block and freeing it. */
+
+ p->size = nb;
+ free(p + 1);
+ return __mem_freelist;
+}
+
+void* malloc(size_t size)
+{
+ block_t* p;
+ block_t* prev;
+ size_t nblocks;
+
+ /* Add on space for the header; make sure we allocate a round number
+ * of blocks; avoid overflow. */
+ nblocks = BLOCKCOUNT(size);
+ if (nblocks < size)
+ return NULL;
+ nblocks /= sizeof(block_t);
+
+ prev = __mem_freelist;
+ p = prev->next;
+ for (;;)
+ {
+ if (p->size == nblocks)
+ {
+ /* We found a hole of exactly the right size. Unlink and return it.
+ * The size field is already set. */
+ prev->next = p->next;
+ __mem_freelist = prev;
+ return (void*) (p+1);
+ }
+ else if (p->size > nblocks)
+ {
+ /* We found a hole bigger than we need. We shrink the hole and return
+ * what's left. */
+ p->size -= nblocks;
+ p += p->size; /* p now points at our new block */
+ p->size = nblocks;
+ __mem_freelist = prev;
+ return (void*) (p+1);
+ }
+
+ if (p == __mem_freelist)
+ {
+ /* Uh-oh --- we've gone right round the ring and haven't found
+ * anything. Get more memory from the system and keep going. */
+ p = brkmore(nblocks);
+ if (!p)
+ return NULL;
+ }
+
+ prev = p;
+ p = p->next;
+ }
+}
+
+void free(void *ptr)
+{
+ block_t* h = BLOCKOF(ptr);
+ block_t* p;
+
+ if (!ptr)
+ return;
+
+ /* __mem_freelist points into an ordered ring of free blocks. First,
+ * we run around the ring until we find the last block before this one.
+ */
+
+ p = __mem_freelist;
+ for (;;)
+ {
+ /* Is h between p and the block after p? If so, h needs to be inserted
+ * after p, so stop here. */
+ if ((p < h) && (h < p->next))
+ break;
+
+ /* Is p the last block before the end of the address space? */
+ if (p >= p->next)
+ {
+ /* Is h after p? (That is, will it become the new last block?) */
+ if (p < h)
+ break;
+
+ /* Is h going to become the new *first* block? */
+ if (h < p->next)
+ break;
+ }
+
+ p = p->next;
+ }
+
+ /* If we can, merge the next block onto the end of h. */
+
+ if ((h + h->size) == p->next)
+ {
+ h->size += p->next->size;
+ h->next = p->next->next;
+ }
+ else
+ {
+ /* Otherwise, insert h before p->next. */
+ h->next = p->next;
+ }
+
+ /* Now try to merge h onto the end of p. */
+
+ if ((p + p->size) == h)
+ {
+ p->size += h->size;
+ p->next = h->next;
+ }
+ else
+ {
+ /* Okay, we couldn't do the merge. Fix up the linked list. */
+ p->next = h;
+ }
+
+ /* ...and update the ring pointer. */
+ __mem_freelist = p;
+}
+
--- /dev/null
+/* This is an ANSI C version of the classic K&R memory allocator, with
+ * some improvements stolen from the Fuzix libc.
+ */
+
+#ifndef MALLOC_H
+#define MALLOC_H
+
+typedef struct block_s {
+ struct block_s* next;
+ size_t size; /* in sizeof(block_t) units */
+} block_t;
+
+extern block_t __mem_root;
+extern block_t* __mem_first_free;
+
+#define BLOCKOF(p) (((block_t*)(p)) - 1)
+
+/* Smallest amount to allocate from brk */
+#define BRKSIZE (512 / sizeof(block_t))
+
+#define BLOCKCOUNT(bytes) \
+ (bytes + sizeof(block_t) + sizeof(block_t) - 1)
+
+#endif
+
--- /dev/null
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include "malloc.h"
+
+void* realloc(void *ptr, size_t size)
+{
+ block_t* h;
+ size_t nblocks;
+ void* newptr;
+
+ if (size == 0)
+ {
+ free(ptr);
+ return NULL;
+ }
+
+ if (!ptr)
+ return malloc(size);
+
+ h = BLOCKOF(ptr);
+
+ nblocks = BLOCKCOUNT(size);
+ /* Overflow check. */
+ if (nblocks < size)
+ return NULL;
+
+ /* Shrinking the block? Don't bother doing anything (it's never worth it). */
+ if (nblocks <= h->size)
+ return ptr;
+
+ /* Allocate and copy. */
+
+ newptr = malloc(size);
+ if (!newptr)
+ return NULL;
+ memcpy(newptr, ptr, h->size * sizeof(block_t));
+ free(ptr);
+ return newptr;
+}
+++ /dev/null
-READ_ME
-add_file
-check.c
-check.h
-global.c
-impl.h
-log.c
-log.h
-mal.c
-param.h
-phys.c
-phys.h
-size_type.h
+++ /dev/null
-DIR = .
-MALLOC_C = $(DIR)/malloc.c
-MALLOC_O = $(DIR)/malloc.o
-
-MALLOCSRC = READ_ME size_type.h param.h impl.h check.h log.h phys.h \
- mal.c log.c phys.c check.c
-
-$(MALLOC_C): $(MALLOCSRC) Makefile add_file
- rm -f $(MALLOC_C)
- for i in $(MALLOCSRC) ; do add_file $$i >> $(MALLOC_C) ; done
- rm -f $(MALLOC_O)
-
-pr:
- @pr Makefile add_file $(MALLOCSRC)
-
-opr:
- make pr | opr
-
-clean:
- rm -f *.o malloc.c
+++ /dev/null
-/*
- PROGRAM
- malloc(), free(), realloc()
- AUTHOR
- Dick Grune, Free University, Amsterdam
- Modified by Ceriel Jacobs, Free University, Amsterdam,
- to make it faster
- VERSION
- $Id$
- DESCRIPTION
- This is an independent rewrite of the malloc/free package; it is
- fast and efficient. Free blocks are kept in doubly linked lists,
- list N holding blocks with sizes between 2**N and 2**(N+1)-1.
- Consequently neither malloc nor free have to do any searching:
- the cost of a call of malloc() (or free()) is constant, however
- many blocks you have got.
-
- If you switch on the NON_STANDARD macro (see param.h) every block
- costs 2 pointers overhead (otherwise it's 4).
-*/
-/*
- There is an organisational problem here: during devellopment
- I want the package divided into modules, which implies external
- names for the communication. The only external names I want in
- the finished product are malloc, realloc and free. This requires
- some hanky-panky.
-*/
+++ /dev/null
-#!/bin/sh
-
-echo ""
-echo "/**********************************************************/"
-echo "/* This was file $1 */"
-echo "/**********************************************************/"
-echo ""
-
-cat $1 |
-sed '
- /#include[ ].*"/d
- s/^public/private/
- s/^publicdata/static/
-'
-echo ''
+++ /dev/null
-/* $Id$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-#include <stdio.h>
-
-#ifdef CHECK /* otherwise this whole file is skipped */
-
-/* ??? check these later */
-private acquire_malout(void), check_ml_last(const char *s);
-private dump_all_mallinks(void), dump_free_list(int i);
-private dump_mallink(const char *s, mallink *ml), print_loop(mallink *ml);
-private working_on(mallink *ml);
-private size_type checksum(mallink *ml);
-static FILE *malout;
-
-private mallink *free_list_entry(int i);
-
-#define for_free_list(i,p) \
- for (p = free_list_entry(i); p; p = log_next_of(p))
-
-#define for_all_mallinks(ml) /* backwards! */ \
- for (ml = ml_last; ml; \
- ml = first_mallink(ml) ? MAL_NULL : phys_prev_of(ml))
-
-/* Maldump */
-
-static int pr_cnt = 0;
-
-maldump(int n) {
- /* Dump pertinent info in pseudo-readable format;
- abort afterwards if n != 0.
- */
- static int dumping = 0;
- int i;
-
- if (dumping)
- return;
- dumping++;
- acquire_malout();
- fprintf(malout,
- ">>>>>>>>>>>>>>>> DUMP OF ALL MALLINKS <<<<<<<<<<<<<<<<");
- fprintf(malout, " ml_last = %p\n", ml_last);
- if (++pr_cnt == 100) pr_cnt = 0;
- dump_all_mallinks();
- fprintf(malout,
- ">>>>>>>>>>>>>>>> DUMP OF FREE_LISTS <<<<<<<<<<<<<<<<\n");
- if (++pr_cnt == 100) pr_cnt = 0;
- for (i = 0; i < MAX_FLIST; i++)
- dump_free_list(i);
- fprintf(malout,
- ">>>>>>>>>>>>>>>> END OF DUMP <<<<<<<<<<<<<<<<\n");
- fclose(malout);
- dumping--;
- if (n)
- abort();
-}
-
-private
-acquire_malout(void) {
- static char buf[BUFSIZ];
-
- if (!malout) {
- malout = freopen("mal.out", "w", stderr);
- setbuf(malout, buf);
- }
-}
-
-private
-dump_all_mallinks(void) {
- mallink *ml;
-
- for_all_mallinks (ml) {
- if (print_loop(ml))
- return;
- dump_mallink((char *)0, ml);
- }
-}
-
-private
-dump_free_list(int i) {
- mallink *ml = free_list_entry(i);
-
- if (!ml)
- return;
- fprintf(malout, "%2d: ", i);
- for_free_list(i, ml) {
- if (print_loop(ml))
- return;
- fprintf(malout, "%p ", ml);
- }
- fprintf(malout, "<\n");
-}
-
-private int
-print_loop(mallink *ml) {
- if (print_of(ml) == pr_cnt) {
- fprintf(malout, "... PRINT LOOP\n");
- return 1;
- }
- set_print(ml, pr_cnt);
- return 0;
-}
-
-private
-dump_mallink(const char *s, mallink *ml) {
- acquire_malout();
- if (s)
- fprintf(malout, "%s: ", s);
- fprintf(malout, "@: %p;", ml);
- if (ml && checksum_of(ml) != checksum(ml))
- fprintf(malout, ">>>> CORRUPTED <<<<");
- if (!ml) {
- fprintf(malout, "\n");
- return;
- }
- if (free_of(ml)) {
- fprintf(malout, " l_p: %p;", _log_prev_of(ml));
- fprintf(malout, " l_n: %p;", _log_next_of(ml));
- }
- fprintf(malout, " p_s: %p;", prev_size_of(ml));
- fprintf(malout, " t_s: %p;", _this_size_of(ml));
- fprintf(malout, " sz: %lu;", (unsigned long) size_of(ml));
- fprintf(malout, " fr: %d;", free_of(ml));
- fprintf(malout, "\n");
-}
-
-/* Check_mallinks() checks the total data structure as accessible
- through free_list[] and ml_last. All check_sums should be OK,
- except those held in the small array off_colour. This is a
- trick to allow to continue checking even when a few mallinks
- are temporarily out of order.
- Check_mallinks() tests for a lot of internal consistency.
-*/
-
-/* Some arbitrary constants */
-#define IN_ML_LAST 93
-#define IN_FREE_LIST 57 /* and in ml_last */
-#define CLEAR 21
-
-#define VRIJ 1
-#define BEZET 2
-
-private
-check_mallinks(const char *s) {
- mallink *ml;
- size_type size;
- int i;
- char stat;
-
- check_ml_last(s);
- stat = BEZET;
- for_all_mallinks(ml) {
- if (checksum_of(ml) != checksum(ml))
- Error("mallink info at %p corrupted", s, ml);
- if (working_on(ml)) {
- stat = BEZET;
- continue;
- }
- if ( !last_mallink(ml) &&
- phys_prev_of(phys_next_of(ml)) != ml
- )
- Error("upward chain bad at %p", s, ml);
- if ( !first_mallink(ml) &&
- phys_next_of(phys_prev_of(ml)) != ml
- )
- Error("downward chain bad at %p", s, ml);
- if (free_of(ml)) {
- if (stat == VRIJ)
- Error("free mallink at %p follows free mallink",
- s, ml);
- stat = VRIJ;
- }
- else
- stat = BEZET;
- set_mark(ml, IN_ML_LAST);
- }
-
- for (i = 0, size = MIN_SIZE; i < MAX_FLIST; i++, size *= 2) {
- for_free_list(i, ml) {
- if (working_on(ml))
- continue;
- if (!free_of(ml))
- Error("occupied mallink %p occurs in free_list", s, ml);
- switch (mark_of(ml)) {
- case IN_ML_LAST:
- set_mark(ml, IN_FREE_LIST);
- break;
- case IN_FREE_LIST:
- Error("mallink %p occurs in 2 free_lists",
- s, ml);
- default:
- Error("unknown mallink %p in free_list",
- s, ml);
- }
- if (size_of(ml) < size)
- Error("size of mallink %p too small", s, ml);
- if (size_of(ml) >= 2*size)
- Error("size of mallink %p too large", s, ml);
- }
- }
- for_all_mallinks (ml) {
- if (working_on(ml))
- continue;
- if (free_of(ml) && mark_of(ml) != IN_FREE_LIST)
- Error("free mallink %p is in no free_list", s, ml);
- set_mark(ml, CLEAR);
- }
-}
-
-private
-check_ml_last(const char *s) {
- if (ml_last && _this_size_of(ml_last) == 0)
- Error("size of ml_last == 0, at %p", s, ml_last);
-}
-
-private size_type
-checksum(mallink *ml) {
- size_type sum = 0;
-
- if (free_of(ml)) {
- sum += (size_type)_log_prev_of(ml);
- sum += (size_type)_log_next_of(ml);
- }
- sum += (size_type)prev_size_of(ml);
- sum += (size_type)_this_size_of(ml);
- return sum;
-}
-
-private
-calc_checksum(mallink *ml) {
- set_checksum(ml, checksum(ml));
-}
-
-#define N_COLOUR 10
-static mallink *off_colour[N_COLOUR];
-
-private
-started_working_on(mallink *ml) {
- int i;
-
- for (i = 0; i < N_COLOUR; i++)
- if (off_colour[i] == MAL_NULL) {
- off_colour[i] = ml;
- return;
- }
- Error("out of off_colour array at %p", "started_working_on", ml);
-}
-
-private
-stopped_working_on(mallink *ml) {
- int i;
-
- for (i = 0; i < N_COLOUR; i++)
- if (off_colour[i] == ml) {
- off_colour[i] = MAL_NULL;
- return;
- }
- Error("stopped working on mallink %p", "stopped_working_on", ml);
-}
-
-private int
-working_on(mallink *ml) {
- int i;
-
- for (i = 0; i < N_COLOUR; i++)
- if (off_colour[i] == ml)
- return 1;
- return 0;
-}
-
-private
-check_work_empty(const char *s) {
- int i;
- int cnt = 0;
-
- for (i = 0; i < N_COLOUR; i++)
- if (off_colour[i] != MAL_NULL)
- cnt++;
- if (cnt != 0)
- Error("off_colour not empty", s, MAL_NULL);
-}
-
-private int
-Error(const char *fmt, const char *s, mallink *ml) {
- static int already_called = 0;
-
- if (already_called++) return 0;
- setbuf(stdout, (char *) 0);
- printf("%s: ", s);
- printf(fmt, (long)ml);
- printf("\n");
- acquire_malout();
- fprintf(malout, "%s: ", s);
- fprintf(malout, fmt, (long)ml);
- fprintf(malout, "\n");
- fflush(stdout);
- maldump(1);
- return 0; /* to satisfy lint */
-}
-
-#endif /* CHECK */
+++ /dev/null
-/* $Id$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-#ifdef CHECK
-
-public check_mallinks(const char *s), calc_checksum(mallink *ml);
-public check_work_empty(const char *s);
-public started_working_on(mallink *ml), stopped_working_on(mallink *ml);
-
-#else /* ifndef CHECK */
-
-#define maldump(n) abort()
-#define check_mallinks(s) 0
-#define calc_checksum(ml) 0
-#define started_working_on(ml) 0
-#define stopped_working_on(ml) 0
-#define check_work_empty(s) 0
-
-#endif /* CHECK */
+++ /dev/null
-/* $Id$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-#include "param.h"
-#include "impl.h"
-
-/* The only global data item:
-*/
-mallink *ml_last; /* link to the world */
+++ /dev/null
-/* $Id$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-/* This file essentially describes how the mallink info block
- is implemented.
-*/
-
-#define MIN_SIZE (1<<LOG_MIN_SIZE)
-#define MAX_FLIST (LOG_MAX_SIZE - LOG_MIN_SIZE)
-#if ALIGNMENT != 4 && ALIGNMENT != 8 && ALIGNMENT != 16
-#error ALIGNMENT must be 4, 8 or 16
-#elif ALIGNMENT % _EM_LSIZE
-/* since calloc() does it's initialization in longs */
-#error ALIGNMENT must be a multiple of the long size
-#endif
-#define align(n) (((n) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))
-
-union _inf {
- union _inf *ptr;
- size_type ui;
-};
-
-typedef union _inf mallink;
-#define MAL_NULL ((mallink *)0)
-
-/* Access macros; only these macros know where to find values.
- They are also lvalues.
-*/
-#ifndef NON_STANDARD
-#define OFF_SET 0
-#else /* def NON_STANDARD */
-#define OFF_SET 2
-#endif /* NON_STANDARD */
-
-#define _log_prev_of(ml) ((ml)[-1+OFF_SET]).ptr
-#define _log_next_of(ml) ((ml)[-2+OFF_SET]).ptr
-#define _phys_prev_of(ml) ((ml)[-3+OFF_SET]).ptr
-#define _this_size_of(ml) ((ml)[-4+OFF_SET]).ui
-#ifndef CHECK
-#define N_WORDS 4
-#else /* ifdef CHECK */
-#define _checksum_of(ml) ((ml)[-5+OFF_SET]).ui
-#define _print_of(ml) ((ml)[-6+OFF_SET]).ui
-#define _mark_of(ml) ((ml)[-7+OFF_SET]).ui
-#define N_WORDS 7
-#endif /* CHECK */
-
-#define mallink_size() (size_t) \
- align((N_WORDS - OFF_SET) * sizeof (mallink))
-
-#ifdef CHECK
-#define set_mark(ml,e) (_mark_of(ml) = (e))
-#define mark_of(ml) (_mark_of(ml))
-
-#define set_checksum(ml,e) (_checksum_of(ml) = (e))
-#define checksum_of(ml) (_checksum_of(ml))
-#endif /* CHECK */
-
-#define new_mallink(ml) ( _log_prev_of(ml) = 0, \
- _log_next_of(ml) = 0, \
- _phys_prev_of(ml) = 0, \
- _this_size_of(ml) = 0 )
-
-#define block_of_mallink(ml) ((void *)ml)
-#define mallink_of_block(addr) ((mallink *)addr)
-
-#define public extern
-#define publicdata extern
-#ifndef EXTERN
-#define private static
-#define privatedata static
-#else /* def EXTERN */
-#define private extern
-#define privatedata
-#endif /* EXTERN */
-
-#ifdef ASSERT
-public m_assert(const char *fn, int ln);
-#define assert(b) (!(b) ? m_assert(__FILE__, __LINE__) : 0)
-#else /* ndef ASSERT */
-#define assert(b) 0
-#endif /* ASSERT */
+++ /dev/null
-/* $Id$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-#include "param.h"
-#include "impl.h"
-#include "check.h"
-#include "log.h"
-
-/* Logical manipulations.
- The chunks are properly chained in the physical chain.
-*/
-
-privatedata mallink *free_list[MAX_FLIST+1];
-
-public
-link_free_chunk(register mallink *ml)
-{
- /* The free chunk ml is inserted in its proper logical
- chain.
- */
- register mallink **mlp = &free_list[0];
- register size_type n = size_of(ml);
- register mallink *ml1;
-
- assert(n < (1L << LOG_MAX_SIZE));
-
- do {
- n >>= 1;
- mlp++;
- }
- while (n >= MIN_SIZE);
-
- ml1 = *--mlp;
- set_log_prev(ml, MAL_NULL);
- set_log_next(ml, ml1);
- calc_checksum(ml);
- if (ml1) {
- /* link backwards
- */
- set_log_prev(ml1, ml);
- calc_checksum(ml1);
- }
- *mlp = ml;
-}
-
-public
-unlink_free_chunk(register mallink *ml)
-{
- /* Unlinks a free chunk from (the middle of) the
- logical chain.
- */
- register mallink *next = log_next_of(ml);
- register mallink *prev = log_prev_of(ml);
-
- if (!prev) {
- /* it is the first in the chain */
- register mallink **mlp = &free_list[-1];
- register size_type n = size_of(ml);
-
- assert(n < (1L << LOG_MAX_SIZE));
- do {
- n >>= 1;
- mlp++;
- }
- while (n >= MIN_SIZE);
- *mlp = next;
- }
- else {
- set_log_next(prev, next);
- calc_checksum(prev);
- }
- if (next) {
- set_log_prev(next, prev);
- calc_checksum(next);
- }
-}
-
-public mallink *
-search_free_list(int class, size_t n)
-{
- /* Searches the free_list[class] for a chunk of at least size n;
- since it is searching a slightly undersized list,
- such a block may not be there.
- */
- register mallink *ml;
-
- for (ml = free_list[class]; ml; ml = log_next_of(ml))
- if (size_of(ml) >= n)
- return ml;
- return MAL_NULL; /* nothing found */
-}
-
-public mallink *
-first_present(int class)
-{
- /* Find the index i in free_list[] such that:
- i >= class && free_list[i] != MAL_NULL.
- Return MAL_NULL if no such i exists;
- Otherwise, return the first block of this list, after
- unlinking it.
- */
- register mallink **mlp, *ml;
-
- for (mlp = &free_list[class]; mlp < &free_list[MAX_FLIST]; mlp++) {
- if ((ml = *mlp) != MAL_NULL) {
-
- *mlp = log_next_of(ml); /* may be MAL_NULL */
- if (*mlp) {
- /* unhook backward link
- */
- set_log_prev(*mlp, MAL_NULL);
- calc_checksum(*mlp);
- }
- return ml;
- }
- }
- return MAL_NULL;
-}
-
-#ifdef CHECK
-public mallink *
-free_list_entry(int i) {
- /* To allow maldump.c access to log.c's private data.
- */
- return free_list[i];
-}
-#endif /* CHECK */
+++ /dev/null
-/* $Id$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-/* Algorithms to manipulate the doubly-linked lists of free
- chunks.
-*/
-
-public link_free_chunk(mallink *ml), unlink_free_chunk(mallink *ml);
-public mallink *first_present(int class);
-public mallink *search_free_list(int class, size_t n);
-
-#ifdef STORE
-#define in_store(ml) ((size_type)_phys_prev_of(ml) & STORE_BIT)
-#define set_store(ml, e) \
- (_phys_prev_of(ml) = (mallink *) \
- ((e) ? (size_type) _phys_prev_of(ml) | STORE_BIT : \
- (size_type) _phys_prev_of(ml) & ~STORE_BIT))
-#endif
-#define set_log_prev(ml,e) (_log_prev_of(ml) = (e))
-#define log_prev_of(ml) (mallink *) (_log_prev_of(ml))
-
-#define set_log_next(ml,e) (_log_next_of(ml) = (e))
-#define log_next_of(ml) (mallink *) (_log_next_of(ml))
-
+++ /dev/null
-/* $Id$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-#include <limits.h>
-#include <stdlib.h>
-#include "param.h"
-#include "impl.h"
-#include "check.h"
-#include "log.h"
-#include "phys.h"
-
-/* Malloc space is traversed by N doubly-linked lists of chunks, each
- containing a couple of house-keeping data addressed as a
- 'mallink' and a piece of useful space, called the block.
- The N lists are accessed through their starting pointers in
- free_list[]. Free_list[n] points to a list of chunks between
- 2**(n+LOG_MIN_SIZE) and 2**(n+LOG_MIN_SIZE+1)-1, which means
- that the smallest chunk is 2**LOG_MIN_SIZE (== MIN_SIZE).
-*/
-
-#ifdef SYSTEM
-#include <system.h>
-#define SBRK sys_break
-extern void *SBRK(int incr);
-#else
-#include <unistd.h>
-#define SBRK sbrk
-#define ILL_BREAK (void *)(-1) /* funny failure value */
-#endif
-#ifdef STORE
-#define MAX_STORE 32
-private do_free(mallink *ml), sell_out(void);
-privatedata mallink *store[MAX_STORE];
-#endif /* STORE */
-
-void *
-malloc(register size_t n)
-{check_mallinks("malloc entry");{
- register mallink *ml;
- register int min_class;
-
- if (n == 0) {
- return NULL;
- }
- if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
-#ifdef STORE
- if (n <= MAX_STORE*MIN_SIZE) {
- /* look in the store first */
- register mallink **stp = &store[(n >> LOG_MIN_SIZE) - 1];
-
- if (ml = *stp) {
- *stp = log_next_of(ml);
- set_store(ml, 0);
- check_mallinks("malloc fast exit");
- assert(! in_store(ml));
- return block_of_mallink(ml);
- }
- }
-#endif /* STORE */
-
- check_work_empty("malloc, entry");
-
- /* Acquire a chunk of at least size n if at all possible;
- Try everything.
- */
- {
- /* Inline substitution of "smallest".
- */
- register size_t n1 = n;
-
- assert(n1 < (1L << LOG_MAX_SIZE));
- min_class = 0;
-
- do {
- n1 >>= 1;
- min_class++;
- } while (n1 >= MIN_SIZE);
- }
-
- if (min_class >= MAX_FLIST)
- return NULL; /* we don't deal in blocks that big */
- ml = first_present(min_class);
- if (ml == MAL_NULL) {
- /* Try and extend */
- register void *p;
-#define GRABSIZE 4096 /* Power of 2 */
- register size_t req =
- ((MIN_SIZE<<min_class)+ mallink_size() + GRABSIZE - 1) &
- ~(GRABSIZE-1);
-
- if (!ml_last) {
- /* first align SBRK() */
-
- p = SBRK(0);
- SBRK((int) (align((size_type) p) - (size_type) p));
- }
-
- /* SBRK takes an int; sorry ... */
- if ((int) req < 0) {
- p = ILL_BREAK;
- } else {
- p = SBRK((int)req);
- }
- if (p == ILL_BREAK) {
- req = n + mallink_size();
- if ((int) req >= 0) p = SBRK((int)req);
- }
- if (p == ILL_BREAK) {
- /* Now this is bad. The system will not give us
- more memory. We can only liquidate our store
- and hope it helps.
- */
-#ifdef STORE
- sell_out();
- ml = first_present(min_class);
- if (ml == MAL_NULL) {
-#endif /* STORE */
- /* In this emergency we try to locate a suitable
- chunk in the free_list just below the safe
- one; some of these chunks may fit the job.
- */
- ml = search_free_list(min_class - 1, n);
- if (!ml) /* really out of space */
- return NULL;
- started_working_on(ml);
- unlink_free_chunk(ml);
- check_mallinks("suitable_chunk, forced");
-#ifdef STORE
- }
- else started_working_on(ml);
-#endif /* STORE */
- }
- else {
- assert((size_type)p == align((size_type)p));
- ml = create_chunk(p, req);
- }
- check_mallinks("suitable_chunk, extended");
- }
- else started_working_on(ml);
-
- /* we have a chunk */
- set_free(ml, 0);
- calc_checksum(ml);
- check_mallinks("suitable_chunk, removed");
- n += mallink_size();
- if (n + MIN_SIZE <= size_of(ml)) {
- truncate(ml, n);
- }
- stopped_working_on(ml);
- check_mallinks("malloc exit");
- check_work_empty("malloc exit");
-#ifdef STORE
- assert(! in_store(ml));
-#endif
- return block_of_mallink(ml);
-}}
-
-void
-free(void *addr)
-{check_mallinks("free entry");{
- register mallink *ml;
-
- if (addr == NULL) {
- check_mallinks("free(0) very fast exit");
- return;
- }
-
- ml = mallink_of_block(addr);
-#ifdef STORE
-
- if (free_of(ml) || in_store(ml))
- return; /* user frees free block */
- if (size_of(ml) <= MAX_STORE*MIN_SIZE) {
- /* return to store */
- mallink **stp = &store[(size_of(ml) >> LOG_MIN_SIZE) - 1];
-
- set_log_next(ml, *stp);
- *stp = ml;
- set_store(ml, 1);
- calc_checksum(ml);
- check_mallinks("free fast exit");
- }
- else {
- do_free(ml);
- check_mallinks("free exit");
- }
-}}
-
-private
-do_free(register mallink *ml)
-{{
-#endif
-
-#ifndef STORE
- if (free_of(ml)) return;
-#endif /* STORE */
- started_working_on(ml);
- set_free(ml, 1);
- calc_checksum(ml);
- if (! last_mallink(ml)) {
- register mallink *next = phys_next_of(ml);
-
- if (free_of(next)) coalesce_forw(ml, next);
- }
-
- if (! first_mallink(ml)) {
- register mallink *prev = phys_prev_of(ml);
-
- if (free_of(prev)) {
- coalesce_backw(ml, prev);
- ml = prev;
- }
- }
- link_free_chunk(ml);
- stopped_working_on(ml);
- check_work_empty("free");
-
- /* Compile-time checks on param.h */
- switch (0) {
- case MIN_SIZE < OFF_SET * sizeof(mallink): break;
- case 1: break;
- /* If this statement does not compile due to duplicate case
- entry, the minimum size block cannot hold the links for
- the free blocks. Either raise LOG_MIN_SIZE or switch
- off NON_STANDARD.
- */
- }
- switch(0) {
- case sizeof(void *) != sizeof(size_type): break;
- case 1: break;
- /* If this statement does not compile due to duplicate
- case entry, size_type is not defined correctly.
- Redefine and compile again.
- */
- }
-}}
-
-void *
-realloc(void *addr, register size_t n)
-{check_mallinks("realloc entry");{
- register mallink *ml, *ph_next;
- register size_type size;
-
- if (addr == NULL) {
- /* Behave like most Unix realloc's when handed a
- null-pointer
- */
- return malloc(n);
- }
- if (n == 0) {
- free(addr);
- return NULL;
- }
- ml = mallink_of_block(addr);
- if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
-#ifdef STORE
- if (in_store(ml)) {
- register mallink *stp = store[(size_of(ml) >> LOG_MIN_SIZE) - 1];
- mallink *stp1 = NULL;
- while (ml != stp) {
- stp1 = stp;
- stp = log_next_of(stp);
- }
- stp = log_next_of(stp);
- if (! stp1) store[(size_of(ml) >> LOG_MIN_SIZE) - 1] = stp;
- else set_log_next(stp1, stp);
- set_store(ml, 0);
- calc_checksum(ml);
- }
-#endif
- if (free_of(ml)) {
- unlink_free_chunk(ml);
- set_free(ml, 0); /* user reallocs free block */
- }
- started_working_on(ml);
- size = size_of(ml);
- if ( /* we can simplify the problem by adding the next chunk: */
- n > size &&
- !last_mallink(ml) &&
- (ph_next = phys_next_of(ml), free_of(ph_next)) &&
- n <= size + mallink_size() + size_of(ph_next)
- ) {
- /* add in the physically next chunk */
- unlink_free_chunk(ph_next);
- combine_chunks(ml, ph_next);
- size = size_of(ml);
- check_mallinks("realloc, combining");
- }
- if (n > size) { /* this didn't help */
- void *new;
- register char *l1, *l2 = addr;
-
- stopped_working_on(ml);
- if (!(new = l1 = malloc(n))) return NULL; /* no way */
- while (size--) *l1++ = *l2++;
- free(addr);
- check_work_empty("mv_realloc");
-#ifdef STORE
- assert(! in_store(mallink_of_block(new)));
-#endif
- return new;
- }
- /* it helped, but maybe too well */
- n += mallink_size();
- if (n + MIN_SIZE <= size_of(ml)) {
- truncate(ml, n);
- }
- stopped_working_on(ml);
- check_mallinks("realloc exit");
- check_work_empty("realloc");
-#ifdef STORE
- assert(! in_store(ml));
-#endif
- return addr;
-}}
-
-void *
-calloc(size_t nmemb, size_t size)
-{check_mallinks("calloc entry");{
- long *l1, *l2;
- size_t n;
-
- if (size == 0) return NULL;
- if (nmemb == 0) return NULL;
-
- /* Check for overflow on the multiplication. The peephole-optimizer
- * will eliminate all but one of the possibilities.
- */
- if (sizeof(size_t) == sizeof(int)) {
- if (UINT_MAX / size < nmemb) return NULL;
- } else if (sizeof(size_t) == sizeof(long)) {
- if (ULONG_MAX / size < nmemb) return NULL;
- } else return NULL; /* can't happen, can it ? */
-
- n = size * nmemb;
- if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
- if (n >= (1L << LOG_MAX_SIZE)) return NULL;
- l1 = (long *) malloc(n);
- l2 = l1 + (n / sizeof(long)); /* n is at least long aligned */
- while ( l2 != l1 ) *--l2 = 0;
- check_mallinks("calloc exit");
- check_work_empty("calloc exit");
- return (void *)l1;
-}}
-/* Auxiliary routines */
-
-#ifdef STORE
-private
-sell_out(void) {
- /* Frees all block in store.
- */
- register mallink **stp;
-
- for (stp = &store[0]; stp < &store[MAX_STORE]; stp++) {
- register mallink *ml = *stp;
-
- while (ml) {
- *stp = log_next_of(ml);
- set_store(ml, 0);
- do_free(ml);
- ml = *stp;
- }
- }
-
-}
-#endif /* STORE */
-
-#ifdef ASSERT
-public
-m_assert(const char *fn, int ln)
-{
- char ch;
-
- while (*fn)
- write(2, fn++, 1);
- write(2, ": malloc assert failed in line ", 31);
- ch = (ln / 100) + '0'; write(2, &ch, 1); ln %= 100;
- ch = (ln / 10) + '0'; write(2, &ch, 1); ln %= 10;
- ch = (ln / 1) + '0'; write(2, &ch, 1);
- write(2, "\n", 1);
- maldump(1);
-}
-#endif /* ASSERT */
+++ /dev/null
-/* $Id$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-#include "size_type.h"
-
-# define NON_STANDARD /* If defined, the contents of a block
- will NOT be left undisturbed after it
- is freed, as opposed to what it says
- in the manual (malloc(2)).
- Setting this option reduces the memory
- overhead considerably. I personally
- consider the specified behaviour an
- artefact of the original
- implementation.
- */
-
-# undef ASSERT /* If defined, some inexpensive tests
- will be made to ensure the
- correctness of some sensitive data.
- It often turns an uncontrolled crash
- into a controlled one.
- */
-
-# undef CHECK /* If defined, extensive and expensive
- tests will be done, inculding a
- checksum on the mallinks (chunk
- information blocks). The resulting
- information will be printed on a file
- called mal.out .
- Additionally a function
- maldump(n) int n;
- will be defined, which will dump
- pertinent info in pseudo-readable
- form; it aborts afterwards if n != 0.
- */
-
-# undef EXTERN /* If defined, all static names will
- become extern, which is a help in
- using adb(1) or prof(1)
- */
-
-# define STORE /* If defined, separate free lists will
- be kept of chunks with small sizes,
- to speed things up a little.
- */
-
-# undef SYSTEM /* If defined, the system module is used.
- Otherwise, "sbrk" is called directly.
- */
-
-#define ALIGNMENT 8
- /* alignment common to all types */
-#define LOG_MIN_SIZE 3
-#define LOG_MAX_SIZE 24
+++ /dev/null
-/* $Id$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-#include <stdlib.h>
-#include "param.h"
-#include "impl.h"
-#include "check.h"
-#include "phys.h"
-
-/* Physical manipulations.
- The blocks concerned are not in any logical chain.
-*/
-
-public mallink *
-create_chunk(void *p, size_t n)
-{
- /* The newly acquired piece of memory at p, of length n,
- is turned into a free chunk, properly chained in the
- physical chain.
- The address of the chunk is returned.
- */
- register mallink *ml;
- /* All of malloc memory is followed by a virtual chunk, the
- mallink of which starts mallink_size() bytes past the last
- byte in memory.
- Its use is prevented by testing for ml == ml_last first.
- */
- register mallink *last = ml_last;
-
- assert(!last || p == (char *)phys_next_of(last) - mallink_size());
- ml = (mallink *)((char *)p + mallink_size()); /* bump ml */
- new_mallink(ml);
- started_working_on(ml);
- set_free(ml, 1);
- set_phys_prev(ml, last);
- ml_last = ml;
-
- set_phys_next(ml, (mallink *)((char *)ml + n));
- calc_checksum(ml);
- assert(size_of(ml) + mallink_size() == n);
- if (last && free_of(last)) {
- coalesce_backw(ml, last);
- ml = last;
- }
- check_mallinks("create_chunk, phys. linked");
- return ml;
-}
-
-public
-truncate(register mallink *ml, size_t size)
-{
- /* The chunk ml is truncated.
- The chunk at ml is split in two.
- The remaining part is then freed.
- */
- register mallink *new = (mallink *)((char *)ml + size);
- register mallink *ph_next = phys_next_of(ml);
-
- new_mallink(new);
- set_free(new, 1);
- set_phys_prev(new, ml);
- set_phys_next(new, ph_next);
- calc_checksum(new);
- if (! last_mallink(ml)) {
- set_phys_prev(ph_next, new);
- calc_checksum(ph_next);
- if (free_of(ph_next)) coalesce_forw(new, ph_next);
- }
- else ml_last = new;
- set_phys_next(ml, new);
- calc_checksum(ml);
-
- started_working_on(new);
- link_free_chunk(new);
- stopped_working_on(new);
- check_mallinks("truncate");
-}
-
-public
-combine_chunks(register mallink *ml1, register mallink *ml2)
-{
- /* The chunks ml1 and ml2 are combined.
- */
- register mallink *ml3 = phys_next_of(ml2);
-
- set_phys_next(ml1, ml3);
- calc_checksum(ml1);
- if (!last_mallink(ml2)) {
- set_phys_prev(ml3, ml1);
- calc_checksum(ml3);
- }
- if (ml_last == ml2)
- ml_last = ml1;
-}
+++ /dev/null
-/* $Id$ */
-/*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
-/* Algorithms to manipulate the doubly-linked list of physical
- chunks.
-*/
-publicdata mallink *ml_last;
-
-#define FREE_BIT 01
-#ifdef STORE
-#define STORE_BIT 02
-#define BITS (FREE_BIT|STORE_BIT)
-#else
-#define BITS (FREE_BIT)
-#endif
-
-#define __bits(ml) ((int)((size_type)_phys_prev_of(ml) & BITS))
-#define __free_of(ml) ((int)((size_type)_phys_prev_of(ml) & FREE_BIT))
-#define __phys_prev_of(ml) ((mallink *)((size_type)_phys_prev_of(ml) & ~BITS))
-#define prev_size_of(ml) ((char *)(ml) - \
- (char *)__phys_prev_of(ml) - \
- mallink_size() \
- )
-#define set_phys_prev(ml,e) \
- (_phys_prev_of(ml) = (mallink *) ((char *)e + __bits(ml)))
-
-#ifdef CHECK
-public Error(const char *fmt, const char *s, mallink *ml);
-#define phys_prev_of(ml) (mallink *) \
- (first_mallink(ml) ? \
- (char *)Error("phys_prev_of first_mallink %p", "somewhere", ml) : \
- (char *)__phys_prev_of(ml) \
- )
-#else /* ndef CHECK */
-#define phys_prev_of(ml) __phys_prev_of(ml)
-#endif /* CHECK */
-
-#define first_mallink(ml) (int) (__phys_prev_of(ml) == 0)
-#define last_mallink(ml) (int) ((ml) == ml_last)
-
-/* There is an ambiguity in the semantics of phys_next_of: sometimes
- one wants it to return MAL_NULL if there is no next chunk, at
- other times one wants the address of the virtual chunk at the
- end of memory. The present version returns the address of the
- (virtual) chunk and relies on the user to test last_mallink(ml)
- first.
-*/
-#define size_of(ml) (_this_size_of(ml) - mallink_size())
-#define set_phys_next(ml,e) \
- (_this_size_of(ml) = (size_type)((char *)(e) - (char *)(ml)))
-#define phys_next_of(ml) (mallink *) ((char *)(ml) + _this_size_of(ml))
-
-#define set_free(ml,e) \
- (_phys_prev_of(ml) = (mallink *) \
- ((e) ? (size_type) _phys_prev_of(ml) | FREE_BIT : \
- (size_type) _phys_prev_of(ml) & ~FREE_BIT))
-#define free_of(ml) (__free_of(ml))
-
-#define coalesce_forw(ml,nxt) ( unlink_free_chunk(nxt), \
- combine_chunks((ml), (nxt)))
-
-#define coalesce_backw(ml,prv) ( unlink_free_chunk(prv), \
- stopped_working_on(ml), \
- combine_chunks((prv), (ml)), \
- started_working_on(prv))
-
-#ifdef CHECK
-#define set_print(ml,e) (_print_of(ml) = (e))
-#define print_of(ml) (_print_of(ml))
-#endif /* CHECK */
-
-public truncate(mallink *ml, size_t size);
-public combine_chunks(register mallink *ml1, register mallink *ml2);
-public mallink *create_chunk(void *p, size_t n);
+++ /dev/null
-#if _EM_WSIZE == _EM_PSIZE
-typedef unsigned int size_type;
-#elif _EM_LSIZE == _EM_PSIZE
-typedef unsigned long size_type;
-#else
-#error funny pointer size
-#endif
-#include <stdlib.h>