Initial revision
authorceriel <none@none>
Tue, 6 Jan 1987 11:25:09 +0000 (11:25 +0000)
committerceriel <none@none>
Tue, 6 Jan 1987 11:25:09 +0000 (11:25 +0000)
14 files changed:
modules/src/malloc/Makefile [new file with mode: 0644]
modules/src/malloc/READ_ME [new file with mode: 0644]
modules/src/malloc/add_file [new file with mode: 0755]
modules/src/malloc/check.c [new file with mode: 0644]
modules/src/malloc/check.h [new file with mode: 0644]
modules/src/malloc/getsize.c [new file with mode: 0644]
modules/src/malloc/global.c [new file with mode: 0644]
modules/src/malloc/impl.h [new file with mode: 0644]
modules/src/malloc/log.c [new file with mode: 0644]
modules/src/malloc/log.h [new file with mode: 0644]
modules/src/malloc/mal.c [new file with mode: 0644]
modules/src/malloc/param.h [new file with mode: 0644]
modules/src/malloc/phys.c [new file with mode: 0644]
modules/src/malloc/phys.h [new file with mode: 0644]

diff --git a/modules/src/malloc/Makefile b/modules/src/malloc/Makefile
new file mode 100644 (file)
index 0000000..994d099
--- /dev/null
@@ -0,0 +1,38 @@
+EMHOME = ../../..
+INSTALL = $(EMHOME)/modules/install
+COMPARE = $(EMHOME)/modules/compare
+CFLAGS = -O -I$(EMHOME)/modules/h
+
+MALLOCSRC =    READ_ME size_type.h param.h impl.h check.h log.h phys.h \
+               mal.c log.c phys.c check.c
+
+all:           malloc.o
+
+install:       all
+               $(INSTALL) lib/malloc.o
+
+cmp:           all
+               $(COMPARE) lib/malloc.o
+
+malloc1.c:     $(MALLOCSRC) Makefile add_file
+               rm -f malloc1.c
+               for i in $(MALLOCSRC) ; do add_file $$i >> malloc1.c ; done
+
+malloc.c:      malloc1.c
+               cclash -l7 -c malloc1.c > clashes
+               cid -Fclashes < malloc1.c > malloc.c
+
+pr:
+               @pr Makefile add_file $(MALLOCSRC)
+
+opr:
+               make pr | opr
+
+clean:
+               rm -f *.o clashes malloc1.c size_type.h getsize malloc.c
+
+size_type.h:   getsize
+               getsize > size_type.h
+
+getsize:       getsize.o
+               $(CC) -o getsize getsize.o
diff --git a/modules/src/malloc/READ_ME b/modules/src/malloc/READ_ME
new file mode 100644 (file)
index 0000000..37be215
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+       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.
+*/
diff --git a/modules/src/malloc/add_file b/modules/src/malloc/add_file
new file mode 100755 (executable)
index 0000000..7a5eace
--- /dev/null
@@ -0,0 +1,14 @@
+echo ''
+echo '/**********************************************************/'
+echo '/*'
+echo '/*               ' This was file $1
+echo '/*'
+echo '/**********************************************************/'
+echo ''
+cat $1 |
+sed '
+       /#include[      ].*"/d
+       s/^public/private/
+       s/^publicdata/static/
+'
+echo ''
diff --git a/modules/src/malloc/check.c b/modules/src/malloc/check.c
new file mode 100644 (file)
index 0000000..cb88d47
--- /dev/null
@@ -0,0 +1,297 @@
+#include       <stdio.h>
+#include       "param.h"
+#include       "impl.h"
+#include       "check.h"
+#include       "phys.h"
+#include       "log.h"
+
+#ifdef CHECK                   /* otherwise this whole file is skipped */
+
+private acquire_malout(), check_ml_last();
+private dump_all_mallinks(), dump_free_list(), dump_mallink(), print_loop();
+private working_on();
+private unsigned int checksum();
+static FILE *malout;
+
+public mallink *free_list_entry();
+
+#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(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()       {
+       static char buf[BUFSIZ];
+       
+       if (!malout)    {
+               malout = fopen("mal.out", "w"); 
+               setbuf(malout, buf);
+       }
+}
+
+private
+dump_all_mallinks()    {
+       mallink *ml;
+       
+       for_all_mallinks (ml)   {
+               if (print_loop(ml))
+                       return;
+               dump_mallink((char *)0, ml);
+       }
+}
+
+private
+dump_free_list(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(ml) 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(s, ml) 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
+
+public
+check_mallinks(s) 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(s) 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(ml) 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;
+}
+
+public
+calc_checksum(ml) mallink *ml; {
+       set_checksum(ml, checksum(ml));
+}
+
+#define        N_COLOUR        10
+static mallink *off_colour[N_COLOUR];
+
+public
+started_working_on(ml) 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);
+}
+
+public
+stopped_working_on(ml) 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(ml) mallink *ml;    {
+       int i;
+       
+       for (i = 0; i < N_COLOUR; i++)
+               if (off_colour[i] == ml)
+                       return 1;
+       return 0;
+}
+
+public
+check_work_empty(s) 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);
+}
+
+public int
+Error(fmt, s, ml) char *fmt, *s; mallink *ml;  {
+       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
diff --git a/modules/src/malloc/check.h b/modules/src/malloc/check.h
new file mode 100644 (file)
index 0000000..c9697c7
--- /dev/null
@@ -0,0 +1,15 @@
+#ifdef CHECK
+
+public check_mallinks(), calc_checksum(), check_work_empty();
+public started_working_on(), stopped_working_on();
+
+#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
diff --git a/modules/src/malloc/getsize.c b/modules/src/malloc/getsize.c
new file mode 100644 (file)
index 0000000..d7cd3a4
--- /dev/null
@@ -0,0 +1,19 @@
+/*     find out if a pointer-sized integer, preferably unsigned,
+       must be declared as an unsigned int or a long
+*/
+
+#include <stdio.h>
+
+main()
+{
+       if (sizeof(unsigned int) == sizeof(char *)) {
+               puts("typedef unsigned int size_type;");
+               return 0;
+       }
+       if (sizeof(long) == sizeof(char *)) {
+               puts("typedef long size_type;");
+               return 0;
+       }
+       fputs(stderr, "funny pointer size\n");
+       return 1;
+}
diff --git a/modules/src/malloc/global.c b/modules/src/malloc/global.c
new file mode 100644 (file)
index 0000000..0061ed4
--- /dev/null
@@ -0,0 +1,6 @@
+#include       "param.h"
+#include       "impl.h"
+
+/*     The only global data item:
+*/
+mallink *ml_last;              /* link to the world */
diff --git a/modules/src/malloc/impl.h b/modules/src/malloc/impl.h
new file mode 100644 (file)
index 0000000..8c39f95
--- /dev/null
@@ -0,0 +1,73 @@
+/*     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 != 1 && ALIGNMENT != 2 && ALIGNMENT != 4 && ALIGNMENT != 8 &&\
+    ALIGNMENT != 16
+ALIGNMENT must be a (small) power of two !!!
+#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        block_of_mallink(ml)    ((char *)ml)
+#define        mallink_of_block(addr)  ((mallink *)addr)
+
+#define        public  extern
+#define        publicdata
+#ifndef        EXTERN
+#define        private static
+#define        privatedata     static
+#else  def     EXTERN
+#define        private extern
+#define        privatedata
+#endif EXTERN
+
+#ifdef ASSERT
+public m_assert();
+#define        assert(b)               (!(b) ? m_assert(__FILE__, __LINE__) : 0)
+#else  ndef    ASSERT
+#define        assert(b)               0
+#endif ASSERT
diff --git a/modules/src/malloc/log.c b/modules/src/malloc/log.c
new file mode 100644 (file)
index 0000000..9def283
--- /dev/null
@@ -0,0 +1,128 @@
+#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(ml)
+       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 < (1 << 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(ml)
+       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 < (1 << 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(class, n)
+       unsigned int 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(class)
+       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(i)     {
+       /*      To allow maldump.c access to log.c's private data.
+       */
+       return free_list[i];
+}
+#endif CHECK
diff --git a/modules/src/malloc/log.h b/modules/src/malloc/log.h
new file mode 100644 (file)
index 0000000..c69f2f6
--- /dev/null
@@ -0,0 +1,12 @@
+/*     Algorithms to manipulate the doubly-linked lists of free
+       chunks.
+*/
+
+public link_free_chunk(), unlink_free_chunk();
+public mallink *first_present(), *search_free_list();
+
+#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))
diff --git a/modules/src/malloc/mal.c b/modules/src/malloc/mal.c
new file mode 100644 (file)
index 0000000..629318c
--- /dev/null
@@ -0,0 +1,293 @@
+#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               (char *)(-1)    /* funny failure value */
+#endif
+extern char *SBRK();
+#ifdef STORE
+#define        MAX_STORE       32
+private do_free(), sell_out();
+privatedata mallink *store[MAX_STORE];
+#endif STORE
+
+char *
+malloc(n)
+       register unsigned int n;
+{check_mallinks("malloc entry");{
+       register mallink *ml;
+       register int min_class;
+
+       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);
+                       check_mallinks("malloc fast exit");
+                       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 unsigned int n1 = n;
+
+               assert(n1 < (1 << LOG_MAX_SIZE));
+               min_class = 0;
+
+               while (n1 >= MIN_SIZE) {
+                       n1 >>= 1;
+                       min_class++;
+               }
+       }
+
+       if (min_class >= MAX_FLIST)
+               return (char *) 0;      /* we don't deal in blocks that big */
+       ml = first_present(min_class);
+       if (ml == MAL_NULL)     {
+               /*      Try and extend */
+               register char *p;
+#define        GRABSIZE        4096            /* Power of 2 */
+               register unsigned int req =
+                       (n+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);
+               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 (char *) 0;
+                               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");
+       return block_of_mallink(ml);
+}}
+
+free(addr)
+       char *addr;
+{check_mallinks("free entry");{
+       register mallink *ml = mallink_of_block(addr);
+#ifdef STORE
+
+       if (free_of(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;
+               check_mallinks("free fast exit");
+       }
+       else    {
+               do_free(ml);
+               check_mallinks("free exit");
+       }
+}}
+
+private
+do_free(ml)
+       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(char *) != 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.
+       */
+       }
+}}
+
+char *
+realloc(addr, n)
+       char *addr;
+       register unsigned int n;
+{check_mallinks("realloc entry");{
+       register mallink *ml = mallink_of_block(addr), *ph_next;
+       register unsigned int size;
+
+       if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
+       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 */
+               char *new;
+               register char *l1, *l2 = addr;
+
+               stopped_working_on(ml);
+               if (!(new = l1 = malloc(n))) return (char *) 0; /* no way */
+               while (size--) *l1++ = *l2++;
+               free(addr);
+               check_work_empty("mv_realloc");
+               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");
+       return addr;
+}}
+
+/*     Auxiliary routines */
+
+#ifdef STORE
+private
+sell_out()     {
+       /*      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);
+                       do_free(ml);
+                       ml = *stp;
+               }
+       }
+
+}
+#endif STORE
+
+#ifdef ASSERT
+public
+m_assert(fn, ln)
+       char *fn;
+{
+       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
diff --git a/modules/src/malloc/param.h b/modules/src/malloc/param.h
new file mode 100644 (file)
index 0000000..a89e6b9
--- /dev/null
@@ -0,0 +1,51 @@
+#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.
+                               */
+
+/*#    define  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.
+                               */
+
+/*#    define  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.
+                               */
+
+/*#    define  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.
+                               */
+
+#      define 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
diff --git a/modules/src/malloc/phys.c b/modules/src/malloc/phys.c
new file mode 100644 (file)
index 0000000..da42536
--- /dev/null
@@ -0,0 +1,93 @@
+#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(p, n)
+       char *p;
+       unsigned int 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 *)(p + mallink_size());   /* bump 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(ml, size)
+       register mallink *ml;
+       unsigned int 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);
+
+       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(ml1, ml2)
+       register mallink *ml1, *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;
+}
diff --git a/modules/src/malloc/phys.h b/modules/src/malloc/phys.h
new file mode 100644 (file)
index 0000000..f11d476
--- /dev/null
@@ -0,0 +1,61 @@
+/*     Algorithms to manipulate the doubly-linked list of physical
+       chunks.
+*/
+publicdata mallink *ml_last;
+
+#define        __free_of(ml)           ((size_type)_phys_prev_of(ml) & 01)
+#define __phys_prev_of(ml)     (mallink *)((size_type)_phys_prev_of(ml) & ~01)
+#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();
+#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) | 01 : \
+                      (size_type) _phys_prev_of(ml) & ~01))
+#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(), combine_chunks();
+public mallink *create_chunk();