--- /dev/null
+Makefile
+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
+EMHOME = ../../../../..
+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
+ $Header$
+ 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
+echo ''
+echo '/**********************************************************/'
+echo '/*'
+echo '/* ' This was file $1
+echo '/*'
+echo '/**********************************************************/'
+echo ''
+cat $1 |
+sed '
+ /#include[ ].*"/d
+ s/^public/private/
+ s/^publicdata/static/
+'
+echo ''
--- /dev/null
+/* $Header$ */
+/*
+ * (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), print_loop(mallink *ml);
+private working_on(mallink *ml);
+private unsigned int 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 = %ld\n", (long)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 = fopen("mal.out", "w");
+ 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, "%ld ", 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, "@: %ld;", (long)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: %ld;", (long)_log_prev_of(ml));
+ fprintf(malout, " l_n: %ld;", (long)_log_next_of(ml));
+ }
+ fprintf(malout, " p_s: %ld;", (long)prev_size_of(ml));
+ fprintf(malout, " t_s: %ld;", (long)_this_size_of(ml));
+ fprintf(malout, " sz: %ld;", (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;
+ unsigned int 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 %ld 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 %ld", s, ml);
+ if ( !first_mallink(ml) &&
+ phys_next_of(phys_prev_of(ml)) != ml
+ )
+ Error("downward chain bad at %ld", s, ml);
+ if (free_of(ml)) {
+ if (stat == VRIJ)
+ Error("free mallink at %ld 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 %ld 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 %ld occurs in 2 free_lists",
+ s, ml);
+ default:
+ Error("unknown mallink %ld in free_list",
+ s, ml);
+ }
+ if (size_of(ml) < size)
+ Error("size of mallink %ld too small", s, ml);
+ if (size_of(ml) >= 2*size)
+ Error("size of mallink %ld 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 %ld 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 %ld", s, ml_last);
+}
+
+private unsigned int
+checksum(mallink *ml) {
+ unsigned int sum = 0;
+
+ if (free_of(ml)) {
+ sum += (unsigned int)_log_prev_of(ml);
+ sum += (unsigned int)_log_next_of(ml);
+ }
+ sum += (unsigned int)prev_size_of(ml);
+ sum += (unsigned int)_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 %ld", "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 %ld", "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) {
+ 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
+/* $Header$ */
+/*
+ * (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
+/* $Header$ */
+/*
+ * (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
+/* $Header$ */
+/*
+ * (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;
+ unsigned int 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() (unsigned int) \
+ 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
+/* $Header$ */
+/*
+ * (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];
+
+public
+link_free_chunk(register mallink *ml)
+{
+ /* The free chunk ml is inserted in its proper logical
+ chain.
+ */
+ register mallink **mlp = &free_list[-1];
+ register unsigned int 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 unsigned int 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
+/* $Header$ */
+/*
+ * (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
+/* $Header$ */
+/*
+ * (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
+#else
+#define SBRK sbrk
+#define ILL_BREAK (void *)(-1) /* funny failure value */
+#endif
+extern void *SBRK(int incr);
+#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));
+ }
+
+ p = SBRK((int)req);
+ assert((size_type)p == align((size_type)p));
+ if (p == ILL_BREAK) {
+ req = n + mallink_size();
+ 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 {
+ 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);
+ 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_t 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);
+ }
+#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
+/* $Header$ */
+/*
+ * (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
+/* $Header$ */
+/*
+ * (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
+/* $Header$ */
+/*
+ * (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) ((size_type)_phys_prev_of(ml) & BITS)
+#define __free_of(ml) ((size_type)_phys_prev_of(ml) & FREE_BIT)
+#define __phys_prev_of(ml) (mallink *)((size_type)_phys_prev_of(ml) & ~FREE_BIT)
+#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 + __free_of(ml)))
+
+#ifdef CHECK
+public Error(const char *fmt, const char *s, mallinkl *ml);
+#define phys_prev_of(ml) (mallink *) \
+ (first_mallink(ml) ? \
+ (char *)Error("phys_prev_of first_mallink %ld", "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) = (unsigned int)((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>