head	1.8;
access;
symbols
	RELEASE_4_3_0:1.7
	RELEASE_4_2_0:1.7
	RELEASE_4_1_1:1.7
	RELEASE_4_1_0:1.7
	RELEASE_3_5_0:1.7
	RELEASE_4_0_0:1.7
	RELEASE_3_4_0:1.7
	RELEASE_3_3_0:1.7
	RELEASE_3_2_0:1.7
	RELEASE_3_1_0:1.7
	RELEASE_2_2_8:1.7
	RELEASE_3_0_0:1.7
	RELEASE_2_2_7:1.7
	RELEASE_2_2_6:1.7
	RELEASE_2_2_5:1.5
	RELEASE_2_2_1:1.1.1.1
	RELEASE_2_2_2:1.1.1.1
	jdp_1_0:1.1.1.1
	JDP:1.1.1;
locks; strict;
comment	@# @;


1.8
date	2001.07.21.23.41.40;	author jdp;	state dead;
branches;
next	1.7;

1.7
date	98.01.17.21.12.13;	author jdp;	state Exp;
branches;
next	1.6;

1.6
date	98.01.16.21.46.13;	author jseger;	state Exp;
branches;
next	1.5;

1.5
date	97.09.05.05.34.11;	author jdp;	state Exp;
branches;
next	1.4;

1.4
date	97.07.26.01.45.53;	author jdp;	state Exp;
branches;
next	1.3;

1.3
date	97.07.04.17.31.36;	author jdp;	state Exp;
branches;
next	1.2;

1.2
date	97.06.29.20.43.30;	author jdp;	state Exp;
branches;
next	1.1;

1.1
date	96.10.29.23.01.53;	author jdp;	state Exp;
branches
	1.1.1.1;
next	;

1.1.1.1
date	96.10.29.23.01.53;	author jdp;	state Exp;
branches;
next	;


desc
@@


1.8
log
@Remove the old modula-3 and modula-3-lib ports.  They are superseded
by the pm3-* family of ports, which build a newer and better-maintained
version of Modula-3.  I have converted all ports which depended on
modula-3 to use pm3-* instead.

PR:		ports/27664 is rendered irrelevant
@
text
@This inserts a thread-safe version of malloc into the "m3core"
package.  It solves some very obscure problems that were caused by
back-door entries into malloc from <*EXTERNAL*> procedures, without
locking the heap.  These allowed multiple threads to enter the
malloc package at once, and led to scribbling in memory and subsequent
core dumps.

This also adds separate wrapper files for network related functions to the
m3makefile, for SOCKS support.

--- m3/m3core/src/runtime/FreeBSD2/m3makefile.orig	Tue Sep 17 16:48:03 1996
+++ m3/m3core/src/runtime/FreeBSD2/m3makefile	Thu Oct 24 16:11:02 1996
@@@@ -13,6 +13,30 @@@@
 c_source       ("RTThreadC")
 c_source       ("RTHeapDepC")
 s_source       ("_fpsetjmp")
+c_source       ("malloc")
+
+% These wrappers were extracted from RTHeapDepC.c and modified slightly,
+% in order to make it possible to support SOCKS.
+c_source       ("accept")
+c_source       ("bind")
+c_source       ("close")
+c_source       ("connect")
+c_source       ("dup")
+c_source       ("dup2")
+c_source       ("gethostbyaddr")
+c_source       ("gethostbyname")
+c_source       ("getpeername")
+c_source       ("getsockname")
+c_source       ("listen")
+c_source       ("read")
+c_source       ("recv")
+c_source       ("recvfrom")
+c_source       ("select")
+c_source       ("send")
+c_source       ("sendto")
+c_source       ("shutdown")
+c_source       ("socket")
+c_source       ("write")
 
 %% s_source (RTStackASM)
 
--- m3/m3core/src/runtime/FreeBSD2/malloc.c.orig	Mon Jul 28 14:36:20 1997
+++ m3/m3core/src/runtime/FreeBSD2/malloc.c	Thu Sep  4 22:15:00 1997
@@@@ -0,0 +1,1153 @@@@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * From FreeBSD: malloc.c,v 1.32 1997/08/31 05:59:39 phk Exp
+ * Modified for Modula-3 thread safety by jdp@@polstra.com (John Polstra).
+ *
+ */
+
+#define _THREAD_SAFE	1	/* Turn on thread safety for Modula-3 */
+
+/*
+ * Defining EXTRA_SANITY will enable extra checks which are related
+ * to internal conditions and consistency in malloc.c. This has a
+ * noticeable runtime performance hit, and generally will not do you
+ * any good unless you fiddle with the internals of malloc or want
+ * to catch random pointer corruption as early as possible.
+ */
+#ifndef MALLOC_EXTRA_SANITY
+#undef MALLOC_EXTRA_SANITY
+#endif
+
+/*
+ * What to use for Junk.  This is the byte value we use to fill with
+ * when the 'J' option is enabled.
+ */
+#define SOME_JUNK	0xd0		/* as in "Duh" :-) */
+
+/*
+ * The basic parameters you can tweak.
+ *
+ * malloc_pageshift	pagesize = 1 << malloc_pageshift
+ *			It's probably best if this is the native
+ *			page size, but it doesn't have to be.
+ *
+ * malloc_minsize	minimum size of an allocation in bytes.
+ *			If this is too small it's too much work
+ *			to manage them.  This is also the smallest
+ *			unit of alignment used for the storage
+ *			returned by malloc/realloc.
+ *
+ */
+
+#if defined(__FreeBSD__)
+#   if defined(__i386__)
+#       define malloc_pageshift		12U
+#       define malloc_minsize		16U
+#   endif
+#endif /* __FreeBSD__ */
+
+#if defined(__sparc__) && defined(sun)
+#   define malloc_pageshift		12U
+#   define malloc_minsize		16U
+#   define MAP_ANON			(0)
+    static int fdzero;
+#   define MMAP_FD	fdzero
+#   define INIT_MMAP() \
+	{ if ((fdzero=open("/dev/zero", O_RDWR, 0000)) == -1) \
+	    wrterror("open of /dev/zero"); }
+#   define MADV_FREE			MADV_DONTNEED
+#endif /* __sparc__ */
+
+#if defined(__linux__)
+#   if defined(__i386__)
+#       define malloc_pageshift		12U
+#       define malloc_minsize		16U
+#   endif
+#endif /* __linux__ */
+
+#if defined(__alpha)
+#   define malloc_pageshift		13U
+#   define malloc_minsize		16U
+#endif /* __alpha */
+
+/* Insert your combination here... */
+#if defined(__FOOCPU__) && defined(__BAROS__)
+#   define malloc_pageshift		12U
+#   define malloc_minsize		16U
+#endif /* __FOOCPU__ && __BAROS__ */
+
+
+/*
+ * No user serviceable parts behind this point.
+ */
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * This structure describes a page worth of chunks.
+ */
+
+struct pginfo {
+    struct pginfo	*next;	/* next on the free list */
+    void		*page;	/* Pointer to the page */
+    u_short		size;	/* size of this page's chunks */
+    u_short		shift;	/* How far to shift for this size chunks */
+    u_short		free;	/* How many free chunks */
+    u_short		total;	/* How many chunk */
+    u_int		bits[1]; /* Which chunks are free */
+};
+
+/*
+ * This structure describes a number of free pages.
+ */
+
+struct pgfree {
+    struct pgfree	*next;	/* next run of free pages */
+    struct pgfree	*prev;	/* prev run of free pages */
+    void		*page;	/* pointer to free pages */
+    void		*end;	/* pointer to end of free pages */
+    size_t		size;	/* number of bytes free */
+};
+
+/*
+ * How many bits per u_int in the bitmap.
+ * Change only if not 8 bits/byte
+ */
+#define	MALLOC_BITS	(8*sizeof(u_int))
+
+/*
+ * Magic values to put in the page_directory
+ */
+#define MALLOC_NOT_MINE	((struct pginfo*) 0)
+#define MALLOC_FREE 	((struct pginfo*) 1)
+#define MALLOC_FIRST	((struct pginfo*) 2)
+#define MALLOC_FOLLOW	((struct pginfo*) 3)
+#define MALLOC_MAGIC	((struct pginfo*) 4)
+
+#ifndef malloc_pageshift
+#define malloc_pageshift		12U
+#endif
+
+#ifndef malloc_minsize
+#define malloc_minsize			16U
+#endif
+
+#if !defined(malloc_pagesize)
+#define malloc_pagesize			(1UL<<malloc_pageshift)
+#endif
+
+#if ((1<<malloc_pageshift) != malloc_pagesize)
+#error	"(1<<malloc_pageshift) != malloc_pagesize"
+#endif
+
+#ifndef malloc_maxsize
+#define malloc_maxsize			((malloc_pagesize)>>1)
+#endif
+
+/* A mask for the offset inside a page.  */
+#define malloc_pagemask	((malloc_pagesize)-1)
+
+#define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask)))
+#define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo)
+
+#ifdef _THREAD_SAFE
+extern int RT0u__inCritical;  /* Flag set when in a critical region */
+#define THREAD_LOCK()		(++RT0u__inCritical)
+#define THREAD_UNLOCK()		(--RT0u__inCritical)
+#endif
+
+#ifndef THREAD_LOCK
+#define THREAD_LOCK()
+#endif
+
+#ifndef THREAD_UNLOCK
+#define THREAD_UNLOCK()
+#endif
+
+#ifndef MMAP_FD
+#define MMAP_FD (-1)
+#endif
+
+#ifndef INIT_MMAP
+#define INIT_MMAP()
+#endif
+
+/* This is needed at least by HP-UX 10.20 */
+#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
+#define MAP_ANON MAP_ANONYMOUS
+#endif
+
+/* Set when initialization has been done */
+static unsigned malloc_started;	
+
+/* Recusion flag for public interface. */
+static int malloc_active;
+
+/* Number of free pages we cache */
+static unsigned malloc_cache = 16;
+
+/* The offset from pagenumber to index into the page directory */
+static u_long malloc_origo;
+
+/* The last index in the page directory we care about */
+static u_long last_index;
+
+/* Pointer to page directory. Allocated "as if with" malloc */
+static struct	pginfo **page_dir;
+
+/* How many slots in the page directory */
+static unsigned	malloc_ninfo;
+
+/* Free pages line up here */
+static struct pgfree free_list;
+
+/* Abort(), user doesn't handle problems.  */
+static int malloc_abort;
+
+/* Are we trying to die ?  */
+static int suicide;
+
+/* always realloc ?  */
+static int malloc_realloc;
+
+/* pass the kernel a hint on free pages ?  */
+static int malloc_hint = 1;
+
+/* xmalloc behaviour ?  */
+static int malloc_xmalloc;
+
+/* sysv behaviour for malloc(0) ?  */
+static int malloc_sysv;
+
+/* zero fill ?  */
+static int malloc_zero;
+
+/* junk fill ?  */
+static int malloc_junk;
+
+#ifdef HAS_UTRACE
+
+/* utrace ?  */
+static int malloc_utrace;
+
+struct ut { void *p; size_t s; void *r; };
+
+void utrace __P((struct ut *, int));
+
+#define UTRACE(a, b, c) \
+	if (malloc_utrace) \
+		{struct ut u; u.p=a; u.s = b; u.r=c; utrace(&u, sizeof u);}
+#else /* !HAS_UTRACE */
+#define UTRACE(a,b,c)
+#endif /* HAS_UTRACE */
+
+/* my last break. */
+static void *malloc_brk;
+
+/* one location cache for free-list holders */
+static struct pgfree *px;
+
+/* compile-time options */
+char *malloc_options;
+
+/* Name of the current public function */
+static char *malloc_func;
+
+/* Macro for mmap */
+#define MMAP(size) \
+	mmap((caddr_t)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \
+	    MMAP_FD, 0);
+
+/*
+ * Necessary function declarations
+ */
+static int extend_pgdir(u_long index);
+static void *imalloc(size_t size);
+static void ifree(void *ptr);
+static void *irealloc(void *ptr, size_t size);
+
+static void
+wrterror(char *p)
+{
+    char *q = " error: ";
+    write(STDERR_FILENO, malloc_func, strlen(malloc_func));
+    write(STDERR_FILENO, q, strlen(q));
+    write(STDERR_FILENO, p, strlen(p));
+    suicide = 1;
+    abort();
+}
+
+static void
+wrtwarning(char *p)
+{
+    char *q = " warning: ";
+    if (malloc_abort)
+	wrterror(p);
+    write(STDERR_FILENO, malloc_func, strlen(malloc_func));
+    write(STDERR_FILENO, q, strlen(q));
+    write(STDERR_FILENO, p, strlen(p));
+}
+
+
+/*
+ * Allocate a number of pages from the OS
+ */
+static caddr_t
+map_pages(int pages)
+{
+    caddr_t result, tail;
+
+    result = (caddr_t)pageround((u_long)sbrk(0));
+    tail = result + (pages << malloc_pageshift);
+
+    if (brk(tail)) {
+#ifdef EXTRA_SANITY
+	wrterror("(ES): map_pages fails\n");
+#endif /* EXTRA_SANITY */
+	return 0;
+    }
+
+    last_index = ptr2index(tail) - 1;
+    malloc_brk = tail;
+
+    if ((last_index+1) >= malloc_ninfo && !extend_pgdir(last_index))
+	return 0;;
+
+    return result;
+}
+
+/*
+ * Extend page directory
+ */
+static int
+extend_pgdir(u_long index)
+{
+    struct  pginfo **new, **old;
+    int i, oldlen;
+
+    /* Make it this many pages */
+    i = index * sizeof *page_dir;
+    i /= malloc_pagesize;
+    i += 2;
+
+    /* remember the old mapping size */
+    oldlen = malloc_ninfo * sizeof *page_dir;
+
+    /*
+     * NOTE: we allocate new pages and copy the directory rather than tempt
+     * fate by trying to "grow" the region.. There is nothing to prevent
+     * us from accidently re-mapping space that's been allocated by our caller
+     * via dlopen() or other mmap().
+     *
+     * The copy problem is not too bad, as there is 4K of page index per
+     * 4MB of malloc arena.
+     *
+     * We can totally avoid the copy if we open a file descriptor to associate
+     * the anon mappings with.  Then, when we remap the pages at the new
+     * address, the old pages will be "magically" remapped..  But this means
+     * keeping open a "secret" file descriptor.....
+     */
+
+    /* Get new pages */
+    new = (struct pginfo**) MMAP(i * malloc_pagesize);
+    if (new == (struct pginfo **)-1)
+	return 0;
+
+    /* Copy the old stuff */
+    memcpy(new, page_dir,
+	    malloc_ninfo * sizeof *page_dir);
+
+    /* register the new size */
+    malloc_ninfo = i * malloc_pagesize / sizeof *page_dir;
+
+    /* swap the pointers */
+    old = page_dir;
+    page_dir = new;
+
+    /* Now free the old stuff */
+    munmap((caddr_t)old, oldlen);
+    return 1;
+}
+
+/*
+ * Initialize the world
+ */
+static void
+malloc_init ()
+{
+    char *p, b[64];
+    int i, j;
+
+    INIT_MMAP();
+
+#ifdef EXTRA_SANITY
+    malloc_junk = 1;
+#endif /* EXTRA_SANITY */
+
+    for (i = 0; i < 3; i++) {
+	if (i == 0) {
+	    j = readlink("/etc/malloc.conf", b, sizeof b - 1);
+	    if (j <= 0)
+		continue;
+	    b[j] = '\0';
+	    p = b;
+	} else if (i == 1) {
+	    p = getenv("MALLOC_OPTIONS");
+	} else {
+	    p = malloc_options;
+	}
+	for (; p && *p; p++) {
+	    switch (*p) {
+		case '>': malloc_cache   <<= 1; break;
+		case '<': malloc_cache   >>= 1; break;
+		case 'a': malloc_abort   = 0; break;
+		case 'A': malloc_abort   = 1; break;
+		case 'h': malloc_hint    = 0; break;
+		case 'H': malloc_hint    = 1; break;
+		case 'r': malloc_realloc = 0; break;
+		case 'R': malloc_realloc = 1; break;
+		case 'j': malloc_junk    = 0; break;
+		case 'J': malloc_junk    = 1; break;
+#ifdef HAS_UTRACE
+		case 'u': malloc_utrace  = 0; break;
+		case 'U': malloc_utrace  = 1; break;
+#endif
+		case 'v': malloc_sysv    = 0; break;
+		case 'V': malloc_sysv    = 1; break;
+		case 'x': malloc_xmalloc = 0; break;
+		case 'X': malloc_xmalloc = 1; break;
+		case 'z': malloc_zero    = 0; break;
+		case 'Z': malloc_zero    = 1; break;
+		default:
+		    j = malloc_abort;
+		    malloc_abort = 0;
+		    wrtwarning("unknown char in MALLOC_OPTIONS\n");
+		    malloc_abort = j;
+		    break;
+	    }
+	}
+    }
+
+    UTRACE(0, 0, 0);
+
+    /*
+     * We want junk in the entire allocation, and zero only in the part
+     * the user asked for.
+     */
+    if (malloc_zero)
+	malloc_junk=1;
+
+    /*
+     * If we run with junk (or implicitly from above: zero), we want to
+     * force realloc() to get new storage, so we can DTRT with it.
+     */
+    if (malloc_junk)
+	malloc_realloc=1;
+
+    /* Allocate one page for the page directory */
+    page_dir = (struct pginfo **) MMAP(malloc_pagesize);
+
+    if (page_dir == (struct pginfo **) -1)
+	wrterror("mmap(2) failed, check limits.\n");
+
+    /*
+     * We need a maximum of malloc_pageshift buckets, steal these from the
+     * front of the page_directory;
+     */
+    malloc_origo = ((u_long)pageround((u_long)sbrk(0))) >> malloc_pageshift;
+    malloc_origo -= malloc_pageshift;
+
+    malloc_ninfo = malloc_pagesize / sizeof *page_dir;
+
+    /* Recalculate the cache size in bytes, and make sure it's nonzero */
+
+    if (!malloc_cache)
+	malloc_cache++;
+
+    malloc_cache <<= malloc_pageshift;
+
+    /*
+     * This is a nice hack from Kaleb Keithly (kaleb@@x.org).
+     * We can sbrk(2) further back when we keep this on a low address.
+     */
+    px = (struct pgfree *) imalloc (sizeof *px);
+
+    /* Been here, done that */
+    malloc_started++;
+}
+
+/*
+ * Allocate a number of complete pages
+ */
+static void *
+malloc_pages(size_t size)
+{
+    void *p, *delay_free = 0;
+    int i;
+    struct pgfree *pf;
+    u_long index;
+
+    size = pageround(size);
+
+    p = 0;
+
+    /* Look for free pages before asking for more */
+    for(pf = free_list.next; pf; pf = pf->next) {
+
+#ifdef EXTRA_SANITY
+	if (pf->size & malloc_pagemask)
+	    wrterror("(ES): junk length entry on free_list\n");
+	if (!pf->size)
+	    wrterror("(ES): zero length entry on free_list\n");
+	if (pf->page == pf->end)
+	    wrterror("(ES): zero entry on free_list\n");
+	if (pf->page > pf->end) 
+	    wrterror("(ES): sick entry on free_list\n");
+	if ((void*)pf->page >= (void*)sbrk(0))
+	    wrterror("(ES): entry on free_list past brk\n");
+	if (page_dir[ptr2index(pf->page)] != MALLOC_FREE) 
+	    wrterror("(ES): non-free first page on free-list\n");
+	if (page_dir[ptr2index(pf->end)-1] != MALLOC_FREE)
+	    wrterror("(ES): non-free last page on free-list\n");
+#endif /* EXTRA_SANITY */
+
+	if (pf->size < size)
+	    continue;
+
+	if (pf->size == size) {
+	    p = pf->page;
+	    if (pf->next)
+		    pf->next->prev = pf->prev;
+	    pf->prev->next = pf->next;
+	    delay_free = pf;
+	    break;
+	} 
+
+	p = pf->page;
+	pf->page = (char *)pf->page + size;
+	pf->size -= size;
+	break;
+    }
+
+#ifdef EXTRA_SANITY
+    if (p && page_dir[ptr2index(p)] != MALLOC_FREE)
+	wrterror("(ES): allocated non-free page on free-list\n");
+#endif /* EXTRA_SANITY */
+
+    size >>= malloc_pageshift;
+
+    /* Map new pages */
+    if (!p)
+	p = map_pages(size);
+
+    if (p) {
+
+	index = ptr2index(p);
+	page_dir[index] = MALLOC_FIRST;
+	for (i=1;i<size;i++)
+	    page_dir[index+i] = MALLOC_FOLLOW;
+
+	if (malloc_junk)
+	    memset(p, SOME_JUNK, size << malloc_pageshift);
+    }
+
+    if (delay_free) {
+	if (!px)
+	    px = delay_free;
+	else
+	    ifree(delay_free);
+    }
+
+    return p;
+}
+
+/*
+ * Allocate a page of fragments
+ */
+
+static __inline__ int
+malloc_make_chunks(int bits)
+{
+    struct  pginfo *bp;
+    void *pp;
+    int i, k, l;
+
+    /* Allocate a new bucket */
+    pp = malloc_pages(malloc_pagesize);
+    if (!pp)
+	return 0;
+
+    /* Find length of admin structure */
+    l = offsetof(struct pginfo, bits[0]);
+    l += sizeof bp->bits[0] *
+	(((malloc_pagesize >> bits)+MALLOC_BITS-1) / MALLOC_BITS);
+
+    /* Don't waste more than two chunks on this */
+    if ((1<<(bits)) <= l+l) {
+	bp = (struct  pginfo *)pp;
+    } else {
+	bp = (struct  pginfo *)imalloc(l);
+	if (!bp) {
+	    ifree(pp);
+	    return 0;
+	}
+    }
+
+    bp->size = (1<<bits);
+    bp->shift = bits;
+    bp->total = bp->free = malloc_pagesize >> bits;
+    bp->page = pp;
+
+    /* set all valid bits in the bitmap */
+    k = bp->total;
+    i = 0;
+
+    /* Do a bunch at a time */
+    for(;k-i >= MALLOC_BITS; i += MALLOC_BITS)
+	bp->bits[i / MALLOC_BITS] = ~0;
+
+    for(; i < k; i++)
+        bp->bits[i/MALLOC_BITS] |= 1<<(i%MALLOC_BITS);
+
+    if (bp == bp->page) {
+	/* Mark the ones we stole for ourselves */
+	for(i=0;l > 0;i++) {
+	    bp->bits[i/MALLOC_BITS] &= ~(1<<(i%MALLOC_BITS));
+	    bp->free--;
+	    bp->total--;
+	    l -= (1 << bits);
+	}
+    }
+
+    /* MALLOC_LOCK */
+
+    page_dir[ptr2index(pp)] = bp;
+
+    bp->next = page_dir[bits];
+    page_dir[bits] = bp;
+
+    /* MALLOC_UNLOCK */
+
+    return 1;
+}
+
+/*
+ * Allocate a fragment
+ */
+static void *
+malloc_bytes(size_t size)
+{
+    int i,j;
+    u_int u;
+    struct  pginfo *bp;
+    int k;
+    u_int *lp;
+
+    /* Don't bother with anything less than this */
+    if (size < malloc_minsize)
+	size = malloc_minsize;
+
+    /* Find the right bucket */
+    j = 1;
+    i = size-1;
+    while (i >>= 1)
+	j++;
+
+    /* If it's empty, make a page more of that size chunks */
+    if (!page_dir[j] && !malloc_make_chunks(j))
+	return 0;
+
+    bp = page_dir[j];
+
+    /* Find first word of bitmap which isn't empty */
+    for (lp = bp->bits; !*lp; lp++)
+	;
+
+    /* Find that bit, and tweak it */
+    u = 1;
+    k = 0;
+    while (!(*lp & u)) {
+	u += u;
+	k++;
+    }
+    *lp ^= u;
+
+    /* If there are no more free, remove from free-list */
+    if (!--bp->free) {
+	page_dir[j] = bp->next;
+	bp->next = 0;
+    }
+
+    /* Adjust to the real offset of that chunk */
+    k += (lp-bp->bits)*MALLOC_BITS;
+    k <<= bp->shift;
+
+    if (malloc_junk)
+	memset((u_char*)bp->page + k, SOME_JUNK, bp->size);
+
+    return (u_char *)bp->page + k;
+}
+
+/*
+ * Allocate a piece of memory
+ */
+static void *
+imalloc(size_t size)
+{
+    void *result;
+
+    if (suicide)
+	abort();
+
+    if ((size + malloc_pagesize) < size)	/* Check for overflow */
+	result = 0;
+    else if (size <= malloc_maxsize)
+	result =  malloc_bytes(size);
+    else
+	result =  malloc_pages(size);
+
+    if (malloc_abort && !result)
+	wrterror("allocation failed.\n");
+
+    if (malloc_zero && result)
+	memset(result, 0, size);
+
+    return result;
+}
+
+/*
+ * Change the size of an allocation.
+ */
+static void *
+irealloc(void *ptr, size_t size)
+{
+    void *p;
+    u_long osize, index;
+    struct pginfo **mp;
+    int i;
+
+    if (suicide)
+	abort();
+
+    index = ptr2index(ptr);
+
+    if (index < malloc_pageshift) {
+	wrtwarning("junk pointer, too low to make sense.\n");
+	return 0;
+    }
+
+    if (index > last_index) {
+	wrtwarning("junk pointer, too high to make sense.\n");
+	return 0;
+    }
+
+    mp = &page_dir[index];
+
+    if (*mp == MALLOC_FIRST) {			/* Page allocation */
+
+	/* Check the pointer */
+	if ((u_long)ptr & malloc_pagemask) {
+	    wrtwarning("modified (page-) pointer.\n");
+	    return 0;
+	}
+
+	/* Find the size in bytes */
+	for (osize = malloc_pagesize; *++mp == MALLOC_FOLLOW;)
+	    osize += malloc_pagesize;
+
+        if (!malloc_realloc && 			/* unless we have to, */
+	  size <= osize && 			/* .. or are too small, */
+	  size > (osize - malloc_pagesize)) {	/* .. or can free a page, */
+	    return ptr;				/* don't do anything. */
+	}
+
+    } else if (*mp >= MALLOC_MAGIC) {		/* Chunk allocation */
+
+	/* Check the pointer for sane values */
+	if (((u_long)ptr & ((*mp)->size-1))) {
+	    wrtwarning("modified (chunk-) pointer.\n");
+	    return 0;
+	}
+
+	/* Find the chunk index in the page */
+	i = ((u_long)ptr & malloc_pagemask) >> (*mp)->shift;
+
+	/* Verify that it isn't a free chunk already */
+        if ((*mp)->bits[i/MALLOC_BITS] & (1<<(i%MALLOC_BITS))) {
+	    wrtwarning("chunk is already free.\n");
+	    return 0;
+	}
+
+	osize = (*mp)->size;
+
+	if (!malloc_realloc &&		/* Unless we have to, */
+	  size < osize && 		/* ..or are too small, */
+	  (size > osize/2 ||	 	/* ..or could use a smaller size, */
+	  osize == malloc_minsize)) {	/* ..(if there is one) */
+	    return ptr;			/* ..Don't do anything */
+	}
+
+    } else {
+	wrtwarning("pointer to wrong page.\n");
+	return 0;
+    }
+
+    p = imalloc(size);
+
+    if (p) {
+	/* copy the lesser of the two sizes, and free the old one */
+	if (!size || !osize)
+	    ;
+	else if (osize < size)
+	    memcpy(p, ptr, osize);
+	else
+	    memcpy(p, ptr, size);
+	ifree(ptr);
+    } 
+    return p;
+}
+
+/*
+ * Free a sequence of pages
+ */
+
+static __inline__ void
+free_pages(void *ptr, int index, struct pginfo *info)
+{
+    int i;
+    struct pgfree *pf, *pt=0;
+    u_long l;
+    void *tail;
+
+    if (info == MALLOC_FREE) {
+	wrtwarning("page is already free.\n");
+	return;
+    }
+
+    if (info != MALLOC_FIRST) {
+	wrtwarning("pointer to wrong page.\n");
+	return;
+    }
+
+    if ((u_long)ptr & malloc_pagemask) {
+	wrtwarning("modified (page-) pointer.\n");
+	return;
+    }
+
+    /* Count how many pages and mark them free at the same time */
+    page_dir[index] = MALLOC_FREE;
+    for (i = 1; page_dir[index+i] == MALLOC_FOLLOW; i++)
+	page_dir[index + i] = MALLOC_FREE;
+
+    l = i << malloc_pageshift;
+
+    if (malloc_junk)
+	memset(ptr, SOME_JUNK, l);
+
+#ifdef MADV_FREE
+    if (malloc_hint)
+	madvise(ptr, l, MADV_FREE);
+#endif
+
+    tail = (char *)ptr+l;
+
+    /* add to free-list */
+    if (!px)
+	px = imalloc(sizeof *pt);	/* This cannot fail... */
+    px->page = ptr;
+    px->end =  tail;
+    px->size = l;
+    if (!free_list.next) {
+
+	/* Nothing on free list, put this at head */
+	px->next = free_list.next;
+	px->prev = &free_list;
+	free_list.next = px;
+	pf = px;
+	px = 0;
+
+    } else {
+
+	/* Find the right spot, leave pf pointing to the modified entry. */
+	tail = (char *)ptr+l;
+
+	for(pf = free_list.next; pf->end < ptr && pf->next; pf = pf->next)
+	    ; /* Race ahead here */
+
+	if (pf->page > tail) {
+	    /* Insert before entry */
+	    px->next = pf;
+	    px->prev = pf->prev;
+	    pf->prev = px;
+	    px->prev->next = px;
+	    pf = px;
+	    px = 0;
+	} else if (pf->end == ptr ) {
+	    /* Append to the previous entry */
+	    pf->end = (char *)pf->end + l;
+	    pf->size += l;
+	    if (pf->next && pf->end == pf->next->page ) {
+		/* And collapse the next too. */
+		pt = pf->next;
+		pf->end = pt->end;
+		pf->size += pt->size;
+		pf->next = pt->next;
+		if (pf->next)
+		    pf->next->prev = pf;
+	    }
+	} else if (pf->page == tail) {
+	    /* Prepend to entry */
+	    pf->size += l;
+	    pf->page = ptr;
+	} else if (!pf->next) {
+	    /* Append at tail of chain */
+	    px->next = 0;
+	    px->prev = pf;
+	    pf->next = px;
+	    pf = px;
+	    px = 0;
+	} else {
+	    wrterror("freelist is destroyed.\n");
+	}
+    }
+    
+    /* Return something to OS ? */
+    if (!pf->next &&				/* If we're the last one, */
+      pf->size > malloc_cache &&		/* ..and the cache is full, */
+      pf->end == malloc_brk &&			/* ..and none behind us, */
+      malloc_brk == sbrk(0)) {			/* ..and it's OK to do... */
+
+	/*
+	 * Keep the cache intact.  Notice that the '>' above guarantees that
+	 * the pf will always have at least one page afterwards.
+	 */
+	pf->end = (char *)pf->page + malloc_cache;
+	pf->size = malloc_cache;
+
+	brk(pf->end);
+	malloc_brk = pf->end;
+
+	index = ptr2index(pf->end);
+	last_index = index - 1;
+
+	for(i=index;i <= last_index;)
+	    page_dir[i++] = MALLOC_NOT_MINE;
+
+	/* XXX: We could realloc/shrink the pagedir here I guess. */
+    }
+    if (pt)
+	ifree(pt);
+}
+
+/*
+ * Free a chunk, and possibly the page it's on, if the page becomes empty.
+ */
+
+static __inline__ void
+free_bytes(void *ptr, int index, struct pginfo *info)
+{
+    int i;
+    struct pginfo **mp;
+    void *vp;
+
+    /* Find the chunk number on the page */
+    i = ((u_long)ptr & malloc_pagemask) >> info->shift;
+
+    if (((u_long)ptr & (info->size-1))) {
+	wrtwarning("modified (chunk-) pointer.\n");
+	return;
+    }
+
+    if (info->bits[i/MALLOC_BITS] & (1<<(i%MALLOC_BITS))) {
+	wrtwarning("chunk is already free.\n");
+	return;
+    }
+
+    if (malloc_junk)
+	memset(ptr, SOME_JUNK, info->size);
+
+    info->bits[i/MALLOC_BITS] |= 1<<(i%MALLOC_BITS);
+    info->free++;
+
+    mp = page_dir + info->shift;
+
+    if (info->free == 1) {
+
+	/* Page became non-full */
+
+	mp = page_dir + info->shift;
+	/* Insert in address order */
+	while (*mp && (*mp)->next && (*mp)->next->page < info->page)
+	    mp = &(*mp)->next;
+	info->next = *mp;
+	*mp = info;
+	return;
+    }
+
+    if (info->free != info->total)
+	return;
+
+    /* Find & remove this page in the queue */
+    while (*mp != info) {
+	mp = &((*mp)->next);
+#ifdef EXTRA_SANITY
+	if (!*mp)
+		wrterror("(ES): Not on queue\n");
+#endif /* EXTRA_SANITY */
+    }
+    *mp = info->next;
+
+    /* Free the page & the info structure if need be */
+    page_dir[ptr2index(info->page)] = MALLOC_FIRST;
+    vp = info->page;		/* Order is important ! */
+    if(vp != (void*)info) 
+	ifree(info);
+    ifree(vp);
+}
+
+static void
+ifree(void *ptr)
+{
+    struct pginfo *info;
+    int index;
+
+    /* This is legal */
+    if (!ptr)
+	return;
+
+    if (!malloc_started) {
+	wrtwarning("malloc() has never been called.\n");
+	return;
+    }
+
+    /* If we're already sinking, don't make matters any worse. */
+    if (suicide)
+	return;
+
+    index = ptr2index(ptr);
+
+    if (index < malloc_pageshift) {
+	wrtwarning("junk pointer, too low to make sense.\n");
+	return;
+    }
+
+    if (index > last_index) {
+	wrtwarning("junk pointer, too high to make sense.\n");
+	return;
+    }
+
+    info = page_dir[index];
+
+    if (info < MALLOC_MAGIC)
+        free_pages(ptr, index, info);
+    else
+	free_bytes(ptr, index, info);
+    return;
+}
+
+/*
+ * These are the public exported interface routines.
+ */
+
+
+void *
+malloc(size_t size)
+{
+    register void *r;
+
+    malloc_func = " in malloc():";
+    THREAD_LOCK();
+    if (malloc_active++) {
+	wrtwarning("recursive call.\n");
+        malloc_active--;
+	return (0);
+    }
+    if (!malloc_started)
+	malloc_init();
+    if (malloc_sysv && !size)
+	r = 0;
+    else
+	r = imalloc(size);
+    UTRACE(0, size, r);
+    malloc_active--;
+    THREAD_UNLOCK();
+    if (malloc_xmalloc && !r)
+	wrterror("out of memory.\n");
+    return (r);
+}
+
+void
+free(void *ptr)
+{
+    malloc_func = " in free():";
+    THREAD_LOCK();
+    if (malloc_active++) {
+	wrtwarning("recursive call.\n");
+        malloc_active--;
+	return;
+    }
+    ifree(ptr);
+    UTRACE(ptr, 0, 0);
+    malloc_active--;
+    THREAD_UNLOCK();
+    return;
+}
+
+void *
+realloc(void *ptr, size_t size)
+{
+    register void *r;
+
+    malloc_func = " in realloc():";
+    THREAD_LOCK();
+    if (malloc_active++) {
+	wrtwarning("recursive call.\n");
+        malloc_active--;
+	return (0);
+    }
+    if (ptr && !malloc_started) {
+	wrtwarning("malloc() has never been called.\n");
+	ptr = 0;
+    }		
+    if (!malloc_started)
+	malloc_init();
+    if (malloc_sysv && !size) {
+	ifree(ptr);
+	r = 0;
+    } else if (!ptr) {
+	r = imalloc(size);
+    } else {
+        r = irealloc(ptr, size);
+    }
+    UTRACE(ptr, size, r);
+    malloc_active--;
+    THREAD_UNLOCK();
+    if (malloc_xmalloc && !r)
+	wrterror("out of memory.\n");
+    return (r);
+}
+
+void *
+calloc(size_t num, size_t size)
+{
+    register void *r;
+
+    size *= num;
+    r = malloc(size);
+    if (r)
+	memset(r, 0, size);
+    return (r);
+}
@


1.7
log
@Fix all the paths in context diff headers and remove the Index
lines, since the WORTHLESS, BROKEN new version of patch ignores
them.
@
text
@@


1.6
log
@Alter patches to apply correctly under 3.0.
PR:		5461
@
text
@a10 1
Index: m3/m3core/src/runtime/FreeBSD2/m3makefile
d44 2
a45 3
Index: m3/m3core/src/runtime/FreeBSD2/malloc.c
--- malloc.c.orig	Mon Jul 28 14:36:20 1997
+++ malloc.c	Thu Sep  4 22:15:00 1997
@


1.5
log
@Portability improvements for the thread-safe malloc.
@
text
@d12 2
a13 2
--- m3makefile.orig	Tue Sep 17 16:48:03 1996
+++ m3makefile	Thu Oct 24 16:11:02 1996
@


1.4
log
@Sync the internal threadsafe malloc with phkmalloc revision 1.28.
@
text
@d46 3
a48 3
--- malloc.c.orig	Fri Jul 11 07:48:55 1997
+++ malloc.c	Fri Jul 25 18:03:33 1997
@@@@ -0,0 +1,1139 @@@@
d57 1
a57 1
+ * From FreeBSD: malloc.c,v 1.28 1997/07/02 19:33:23 phk Exp
d96 1
a96 1
+#if defined(__FreeBSD__) || defined(__linux__)
d101 1
a101 1
+#endif /* __FreeBSD__ || __linux__ */
d104 1
a104 1
+#   define malloc_pageshirt		12U
d115 12
d141 1
d197 1
a197 1
+#define malloc_pagesize			(1U<<malloc_pageshift)
d236 5
d275 1
a275 1
+static int malloc_hint;
a329 2
+extern char *__progname;
+
a333 1
+    write(STDERR_FILENO, __progname, strlen(__progname));
a346 1
+    write(STDERR_FILENO, __progname, strlen(__progname));
d642 2
a643 2
+    l = sizeof *bp - sizeof(u_long);
+    l += sizeof(u_long) *
@


1.3
log
@I botched my previous update of the thread safe malloc, making it
not thread safe at all.  This commit repairs the damage.

This changes the minor version numbers of the Modula-3 shared
libraries.  The packages that depend on modula-3-lib will need to
be rebuilt:

    net/cvsup
    print/virtualpaper
@
text
@d46 3
a48 3
--- malloc.c.orig	Fri Jul  4 08:51:34 1997
+++ malloc.c	Fri Jul  4 08:53:21 1997
@@@@ -0,0 +1,1142 @@@@
d57 1
a57 1
+ * From FreeBSD: malloc.c,v 1.26 1997/06/22 17:54:27 phk Exp
d96 1
a96 1
+#if defined(__FreeBSD__)
d101 1
a101 6
+#   if defined(_THREAD_SAFE)
+	extern int RT0u__inCritical;  /* Flag set when in a critical region */
+#       define THREAD_LOCK()		(++RT0u__inCritical)
+#       define THREAD_UNLOCK()		(--RT0u__inCritical)
+#   endif
+#endif /* __FreeBSD__ */
d103 1
a103 1
+#if defined(__sparc__) || defined(sun)
d119 1
a119 1
+#endif /* __FOORCPU__ && __BAROS__ */
d201 6
d271 2
a275 1
+#ifdef HAS_UTRACE
d285 1
a285 1
+#endif
d458 1
d461 1
d487 7
a508 3
+    /* Been here, done that */
+    malloc_started++;
+
d522 2
a745 3
+    if (!malloc_started)
+	malloc_init();
+
a778 5
+    if (!malloc_started) {
+	wrtwarning("malloc() has never been called.\n");
+	return 0;
+    }
+
a1104 2
+    if (malloc_sysv && !size)
+	return (0);
d1112 6
a1117 1
+    r = imalloc(size);
d1155 6
d1183 1
a1183 15
+    if (malloc_sysv && !size)
+	return (0);
+    malloc_func = " in calloc():";
+    THREAD_LOCK();
+    if (malloc_active++) {
+	wrtwarning("recursive call.\n");
+        malloc_active--;
+	return (0);
+    }
+    r = imalloc(size);
+    UTRACE(0, size, r);
+    malloc_active--;
+    THREAD_UNLOCK();
+    if (malloc_xmalloc && !r)
+	wrterror("out of memory.\n");
@


1.2
log
@Update the Modula-3 runtime's thread safe malloc to PHK's latest.
This eliminates the malloc warnings brought about by the recent
merging of calloc into malloc.c in -current's libc.

This changes the minor version numbers of the Modula-3 shared
libraries.  The packages that depend on modula-3-lib will need to
be rebuilt:

	net/cvsup
	print/virtualpaper
@
text
@d46 3
a48 3
--- malloc.c.orig	Thu May  8 17:39:18 1997
+++ malloc.c	Sat Jun 28 10:59:29 1997
@@@@ -0,0 +1,1140 @@@@
d61 2
@


1.1
log
@Initial revision
@
text
@d46 3
a48 3
--- malloc.c.orig	Mon Oct 28 20:16:48 1996
+++ malloc.c	Tue Oct 29 08:57:53 1996
@@@@ -0,0 +1,1286 @@@@
d57 2
a58 2
+ * From FreeBSD: malloc.c,v 1.15 1996/09/25 16:29:15 sos Exp
+ * Modified for Modula-3 thread-safety by jdp@@polstra.com (John Polstra).
a62 10
+ * Defining M3_THREAD_SAFE will enable the hooks into the Modula-3 runtime
+ * to permit thread-safe operation with that language system.  Do that if
+ * you want to use this malloc as part of the "m3core" package.
+ *
+ * If you define M3_THREAD_SAFE, then do not define _THREAD_SAFE,
+ * which enables the pthreads tie-ins.  They are mutually-exclusive.
+ */
+#define M3_THREAD_SAFE
+
+/*
d69 2
a70 11
+#undef EXTRA_SANITY
+
+/*
+ * Defining MALLOC_STATS will enable you to call malloc_dump() and set
+ * the [dD] options in the MALLOC_OPTIONS environment variable.
+ * It has no run-time performance hit.
+ */
+#define MALLOC_STATS
+
+#if defined(EXTRA_SANITY) && !defined(MALLOC_STATS)
+# define MALLOC_STATS	/* required for EXTRA_SANITY */
d80 12
a91 2
+ * If these weren't defined here, they would be calculated on the fly,
+ * with a noticeable performance hit.
d93 27
a119 2
+#if defined(__i386__) && defined(__FreeBSD__)
+#   define malloc_pagesize		4096U
d122 2
a123 2
+#   define malloc_maxsize		((malloc_pagesize)>>1)
+#endif /* __i386__ && __FreeBSD__ */
d128 4
a131 1
+
a135 12
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#if 0 /* Disable the utrace stuff { */
+#ifdef __FreeBSD__	/* Kludge to find out whether we have utrace() */
+#include <sys/syscall.h>
+#ifdef SYS_utrace
+#define HAVE_UTRACE
+#endif /* SYS_utrace */
+#endif /* __FreeBSD__ */
+#endif /* } 0 */
d148 1
a148 1
+    u_long		bits[1]; /* Which chunks are free */
d160 1
a160 1
+    u_long		size;	/* number of bytes free */
d164 1
a164 1
+ * How many bits per u_long in the bitmap.
d167 1
a167 1
+#define	MALLOC_BITS	(8*sizeof(u_long))
d178 3
a180 14
+/*
+ * The i386 architecture has some very convenient instructions.
+ * We might as well use them.  There are C-language backups, but
+ * they are considerably slower.
+ */
+#if defined(__i386__) && defined(__GNUC__)
+#define ffs _ffs
+static __inline__ int
+_ffs(unsigned input)
+{
+	int result;
+	__asm__("bsfl %1, %0" : "=r" (result) : "r" (input));
+	return result+1;
+}
d182 3
a184 8
+#define fls _fls
+static __inline__ int
+_fls(unsigned input)
+{
+	int result;
+	__asm__("bsrl %1, %0" : "=r" (result) : "r" (input));
+	return result+1;
+}
d186 3
a188 7
+#define set_bit _set_bit
+static __inline__ void
+_set_bit(struct pginfo *pi, int bit)
+{
+	__asm__("btsl %0, (%1)" :
+	: "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS)));
+}
d190 3
a192 7
+#define clr_bit _clr_bit
+static __inline__ void
+_clr_bit(struct pginfo *pi, int bit)
+{
+	__asm__("btcl %0, (%1)" :
+	: "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS)));
+}
d194 3
a196 15
+#endif /* __i386__ && __GNUC__ */
+
+/*
+ * Set to one when malloc_init has been called
+ */
+static	unsigned	initialized;
+
+/*
+ * The size of a page.
+ * Must be a integral multiplum of the granularity of mmap(2).
+ * Your toes will curl if it isn't a power of two
+ */
+#ifndef malloc_pagesize
+static	unsigned        malloc_pagesize;
+#endif /* malloc_pagesize */
d204 15
a218 4
+/* malloc_pagesize == 1 << malloc_pageshift */
+#ifndef malloc_pageshift
+static	unsigned	malloc_pageshift;
+#endif /* malloc_pageshift */
d220 2
a221 7
+/*
+ * The smallest allocation we bother about.
+ * Must be power of two
+ */
+#ifndef malloc_minsize
+static	unsigned  malloc_minsize;
+#endif /* malloc_minsize */
d223 2
a224 8
+/*
+ * The largest chunk we care about.
+ * Must be smaller than pagesize
+ * Must be power of two
+ */
+#ifndef malloc_maxsize
+static	unsigned  malloc_maxsize;
+#endif /* malloc_maxsize */
d226 2
a227 2
+/* The minimum size (in pages) of the free page cache.  */
+static	unsigned  malloc_cache = 16;
d230 1
a230 1
+static	u_long  malloc_origo;
d233 1
a233 1
+static	u_long  last_index;
d236 1
a236 1
+static	struct	pginfo **page_dir;
d239 1
a239 1
+static	unsigned	malloc_ninfo;
d242 1
a242 1
+static struct pgfree	free_list;
a249 5
+#ifdef MALLOC_STATS
+/* dump statistics */
+static int malloc_stats;
+#endif /* MALLOC_STATS */
+
d256 6
a267 1
+#ifdef HAVE_UTRACE
d271 1
d274 2
d279 1
a279 1
+#else /* !HAVE_UTRACE */
d281 1
a281 1
+#endif /* HAVE_UTRACE */
d292 8
d308 1
a308 59
+#ifdef MALLOC_STATS
+void
+malloc_dump(FILE *fd)
+{
+    struct pginfo **pd;
+    struct pgfree *pf;
+    int j;
+
+    pd = page_dir;
+
+    /* print out all the pages */
+    for(j=0;j<=last_index;j++) {
+	fprintf(fd, "%08lx %5d ", (j+malloc_origo) << malloc_pageshift, j);
+	if (pd[j] == MALLOC_NOT_MINE) {
+	    for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++)
+		;
+	    j--;
+	    fprintf(fd, ".. %5d not mine\n",	j);
+	} else if (pd[j] == MALLOC_FREE) {
+	    for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++)
+		;
+	    j--;
+	    fprintf(fd, ".. %5d free\n", j);
+	} else if (pd[j] == MALLOC_FIRST) {
+	    for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++)
+		;
+	    j--;
+	    fprintf(fd, ".. %5d in use\n", j);
+	} else if (pd[j] < MALLOC_MAGIC) {
+	    fprintf(fd, "(%p)\n", pd[j]);
+	} else {
+	    fprintf(fd, "%p %d (of %d) x %d @@ %p --> %p\n",
+		pd[j], pd[j]->free, pd[j]->total,
+		pd[j]->size, pd[j]->page, pd[j]->next);
+	}
+    }
+
+    for(pf=free_list.next; pf; pf=pf->next) {
+	fprintf(fd, "Free: @@%p [%p...%p[ %ld ->%p <-%p\n",
+		pf, pf->page, pf->end, pf->size, pf->prev, pf->next);
+	if (pf == pf->next) {
+		fprintf(fd, "Free_list loops.\n");
+		break;
+	}
+    }
+
+    /* print out various info */
+    fprintf(fd, "Minsize\t%d\n", malloc_minsize);
+    fprintf(fd, "Maxsize\t%d\n", malloc_maxsize);
+    fprintf(fd, "Pagesize\t%d\n", malloc_pagesize);
+    fprintf(fd, "Pageshift\t%d\n", malloc_pageshift);
+    fprintf(fd, "FirstPage\t%ld\n", malloc_origo);
+    fprintf(fd, "LastPage\t%ld %lx\n", last_index+malloc_pageshift,
+	(last_index + malloc_pageshift) << malloc_pageshift);
+    fprintf(fd, "Break\t%ld\n", (u_long)sbrk(0) >> malloc_pageshift);
+}
+#endif /* MALLOC_STATS */
+
+static char *malloc_func;
d313 5
a317 1
+    char *q = "Malloc error: ";
a318 7
+    write(2, q, strlen(q));
+    write(2, malloc_func, strlen(malloc_func));
+    write(2, p, strlen(p));
+#ifdef MALLOC_STATS
+    if (malloc_stats)
+	malloc_dump(stderr);
+#endif /* MALLOC_STATS */
d325 1
a325 1
+    char *q = "Malloc warning: ";
d328 4
a331 16
+    write(2, q, strlen(q));
+    write(2, malloc_func, strlen(malloc_func));
+    write(2, p, strlen(p));
+}
+
+#ifdef EXTRA_SANITY
+static void
+malloc_exit()
+{
+    FILE *fd = fopen("malloc.out", "a");
+    char *q = "malloc() warning: Couldn't dump stats.\n";
+    if (fd) {
+        malloc_dump(fd);
+	fclose(fd);
+    } else
+	write(2, q, strlen(q));
a332 1
+#endif /* EXTRA_SANITY */
a362 47
+ * Set a bit in the bitmap
+ */
+#ifndef set_bit
+static __inline__ void
+set_bit(struct pginfo *pi, int bit)
+{
+    pi->bits[bit/MALLOC_BITS] |= 1<<(bit%MALLOC_BITS);
+}
+#endif /* set_bit */
+
+/*
+ * Clear a bit in the bitmap
+ */
+#ifndef clr_bit
+static __inline__ void
+clr_bit(struct pginfo *pi, int bit)
+{
+    pi->bits[bit/MALLOC_BITS] &= ~(1<<(bit%MALLOC_BITS));
+}
+#endif /* clr_bit */
+
+#ifndef tst_bit
+/*
+ * Test a bit in the bitmap
+ */
+static __inline__ int
+tst_bit(struct pginfo *pi, int bit)
+{
+    return pi->bits[bit/MALLOC_BITS] & (1<<(bit%MALLOC_BITS));
+}
+#endif /* tst_bit */
+
+/*
+ * Find last bit
+ */
+#ifndef fls
+static __inline__ int
+fls(int size)
+{
+    int i = 1;
+    while (size >>= 1)
+	i++;
+    return i;
+}
+#endif /* fls */
+
+/*
d395 1
a395 2
+    new = (struct pginfo**) mmap(0, i * malloc_pagesize, PROT_READ|PROT_WRITE,
+				 MAP_ANON|MAP_PRIVATE, -1, 0);
d424 1
d439 1
a439 1
+	} else if (i == 2) {
a447 5
+#ifdef MALLOC_STATS
+		case 'd': malloc_stats   = 0; break;
+		case 'D': malloc_stats   = 1; break;
+#endif /* MALLOC_STATS */
+#ifdef MADV_FREE
a449 1
+#endif /* MADV_FREE */
a453 1
+#ifdef HAVE_UTRACE
d456 4
a459 1
+#endif /* HAVE_UTRACE */
d481 2
a482 4
+#ifdef EXTRA_SANITY
+    if (malloc_stats)
+	atexit(malloc_exit);
+#endif /* EXTRA_SANITY */
a483 46
+#ifndef malloc_pagesize
+    /* determine our pagesize */
+    malloc_pagesize = getpagesize();
+#endif /* malloc_pagesize */
+
+#ifndef malloc_maxsize
+    malloc_maxsize = malloc_pagesize >> 1;
+#endif /* malloc_maxsize */
+
+#ifndef malloc_pageshift
+    {
+    int i;
+    /* determine how much we shift by to get there */
+    for (i = malloc_pagesize; i > 1; i >>= 1)
+	malloc_pageshift++;
+    }
+#endif /* malloc_pageshift */
+
+#ifndef malloc_minsize
+    {
+    int i;
+    /*
+     * find the smallest size allocation we will bother about.
+     * this is determined as the smallest allocation that can hold
+     * it's own pginfo;
+     */
+    i = 2;
+    for(;;) {
+	int j;
+
+	/* Figure out the size of the bits */
+	j = malloc_pagesize/i;
+	j /= 8;
+	if (j < sizeof(u_long))
+		j = sizeof (u_long);
+	if (sizeof(struct pginfo) + j - sizeof (u_long) <= i)
+		break;
+	i += i;
+    }
+    malloc_minsize = i;
+    }
+#endif /* malloc_minsize */
+
+    /* Allocate one page for the page directory */
+    page_dir = (struct pginfo **) mmap(0, malloc_pagesize, PROT_READ|PROT_WRITE,
+				       MAP_ANON|MAP_PRIVATE, -1, 0);
d497 8
a504 1
+    initialized++;
a511 4
+    if (!malloc_cache)
+	malloc_cache++;
+
+    malloc_cache <<= malloc_pageshift;
d517 1
a517 1
+void *
d528 1
d625 2
a626 1
+	if (!bp)
d628 1
d636 1
a636 6
+    page_dir[ptr2index(pp)] = bp;
+
+    bp->next = page_dir[bits];
+    page_dir[bits] = bp;
+
+    /* set all valid bits in the bits */
d645 1
a645 1
+	set_bit(bp, i);
d650 1
a650 1
+	    clr_bit(bp, i);
d657 9
d675 2
a676 1
+    int j;
d679 1
a679 1
+    u_long *lp;
d686 4
a689 1
+    j = fls((size)-1);
d702 7
a708 2
+    k = ffs(*lp) - 1;
+    *lp ^= 1<<k;
d721 1
a721 1
+	memset(bp->page + k, SOME_JUNK, bp->size);
d723 1
a723 1
+    return bp->page + k;
d734 1
a734 1
+    if (!initialized)
d740 3
a742 1
+    if (size <= malloc_maxsize)
d750 1
a750 1
+    if (malloc_zero)
d768 1
a768 1
+	return 0;
d770 1
a770 1
+    if (!initialized) {
d819 1
a819 1
+	if (tst_bit(*mp, i)) {
d842 3
a844 1
+	if (osize < size)
d887 3
d893 1
a893 1
+#endif /* MADV_FREE */
d1004 1
a1004 1
+    if (tst_bit(info, i)) {
d1009 4
a1012 1
+    set_bit(info, i);
d1061 1
a1061 1
+    if (!initialized) {
a1094 16
+#ifdef _THREAD_SAFE
+#include <pthread.h>
+#include "pthread_private.h"
+static int malloc_lock;
+#define THREAD_LOCK() _thread_kern_sig_block(&malloc_lock);
+#define THREAD_UNLOCK() _thread_kern_sig_unblock(&malloc_lock);
+#elif defined(M3_THREAD_SAFE)
+extern int RT0u__inCritical;	/* Flag set when in a critical region */
+#define THREAD_LOCK() (++RT0u__inCritical)
+#define THREAD_UNLOCK() (--RT0u__inCritical)
+#else
+#define THREAD_LOCK() 
+#define THREAD_UNLOCK()
+#endif
+
+static int malloc_active;
d1101 3
a1103 1
+    malloc_func = "malloc():";
d1114 2
d1122 1
a1122 1
+    malloc_func = "free():";
d1141 1
a1141 1
+    malloc_func = "realloc():";
d1148 1
a1148 3
+    if (!ptr) {
+	r = imalloc(size);
+    } else if (ptr && !size) {
d1151 2
d1159 28
@


1.1.1.1
log
@Split the Modula-3 port into two pieces, creating a new port
"modula-3-lib".  It installs only the shared libraries needed for
executing Modula-3 programs.  This saves a lot of disk space for
people who need to run Modula-3 programs but don't need to build
them.  The original "modula-3" port now depends on this one, and
uses it to install the compiler and the rest of the development
system.

Also, everything is now built with optimization.  I have been
testing this for at least a month, and haven't seen any problems
from it.  It makes the libraries and executables substantially
smaller.

This new port also includes some hooks that will make SOCKS support
possible in the near future.
@
text
@@
