Replaced the funky and hard-to-compile ACK malloc with a much smaller

and simpler one stolen from K&R. libc builds now.
This commit is contained in:
David Given 2016-08-11 00:30:32 +02:00
parent 3ce4e53aa9
commit a200a2fb53
20 changed files with 248 additions and 1288 deletions

View file

@ -1,19 +1,4 @@
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",
@ -49,14 +34,15 @@ for _, plat in ipairs(vars.plats) do
"+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",
@ -65,7 +51,7 @@ for _, plat in ipairs(vars.plats) do
},
hdrs = {}, -- must be empty
deps = {
"+headers",
"lang/cem/libcc.ansi/headers+headers",
"plat/"..plat.."+headers",
},
vars = { plat = plat }
@ -83,6 +69,7 @@ for _, plat in ipairs(vars.plats) do
installable {
name = "pkg_"..plat,
map = {
"lang/cem/libcc.ansi/headers+pkg",
["$(PLATIND)/"..plat.."/c-ansi.o"] = "+crt_"..plat,
["$(PLATIND)/"..plat.."/libc.a"] = "+lib_"..plat,
}

View file

@ -0,0 +1,26 @@
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
}

View file

@ -0,0 +1,151 @@
#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;
}

View file

@ -0,0 +1,25 @@
/* 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

View file

@ -0,0 +1,41 @@
#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;
}

View file

@ -1,13 +0,0 @@
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

View file

@ -1,20 +0,0 @@
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

View file

@ -1,27 +0,0 @@
/*
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.
*/

View file

@ -1,15 +0,0 @@
#!/bin/sh
echo ""
echo "/**********************************************************/"
echo "/* This was file $1 */"
echo "/**********************************************************/"
echo ""
cat $1 |
sed '
/#include[ ].*"/d
s/^public/private/
s/^publicdata/static/
'
echo ''

View file

@ -1,303 +0,0 @@
/* $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 */

View file

@ -1,21 +0,0 @@
/* $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 */

View file

@ -1,11 +0,0 @@
/* $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 */

View file

@ -1,84 +0,0 @@
/* $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 */

View file

@ -1,129 +0,0 @@
/* $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 */

View file

@ -1,26 +0,0 @@
/* $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))

View file

@ -1,385 +0,0 @@
/* $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 */

View file

@ -1,56 +0,0 @@
/* $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

View file

@ -1,96 +0,0 @@
/* $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;
}

View file

@ -1,76 +0,0 @@
/* $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);

View file

@ -1,8 +0,0 @@
#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>