which included commits to RCS files with non-trunk default branches. git-svn-id: svn://10.65.10.50/trunk@5758 c028cbd2-c16b-5b4b-a496-9718f37d4682
496 lines
11 KiB
C
Executable File
496 lines
11 KiB
C
Executable File
/*******************************************************************************
|
|
* Copyright 1991-1995 by ORCA Software, Inc. *
|
|
* *
|
|
* All rights reserved. May not be reproduced or distributed, in printed or *
|
|
* electronic form, without permission of ORCA Software, Inc. May not be *
|
|
* distributed as object code, separately or linked with other object modules, *
|
|
* without permission. *
|
|
*******************************************************************************/
|
|
|
|
/* ERROR CODES 20201-20201 */
|
|
|
|
#define XI_INTERNAL
|
|
|
|
#include "xi.h"
|
|
#include "xiheap.h"
|
|
#include "xiutils.h"
|
|
|
|
#ifndef R2
|
|
#define fatal xvt_dm_post_fatal_exit
|
|
#endif
|
|
|
|
#define PADCHAR ((char)0x8e)
|
|
#define MAGIC 0xe8
|
|
|
|
/*
|
|
constants to define for more debugging
|
|
|
|
PAD - pad allocations with N bytes of magic and check magic number when
|
|
xi_tree_check_sanity is called
|
|
FENCE - call xi_tree_check_sanity on every Nth xi_tree_* call
|
|
PREPAD - put an extra N bytes between the node struct and the data.
|
|
This padding is never checked.
|
|
|
|
sample usage:
|
|
|
|
#define PAD 20
|
|
#define FENCE 10
|
|
#define PREPAD 10
|
|
*/
|
|
/*
|
|
#define PAD 100
|
|
#define FENCE 1
|
|
*/
|
|
|
|
typedef struct _tree_node
|
|
{
|
|
struct _tree_node *parent;
|
|
struct _tree_node *sibling;
|
|
struct _tree_node *child;
|
|
#if XIWS == MTFWS
|
|
struct _tree_node *dummy;
|
|
#endif
|
|
#ifdef TREEDEBUG
|
|
int line;
|
|
char *file;
|
|
int magic; /* for sanity checks */
|
|
int size;
|
|
#ifdef PREPAD
|
|
char prepad[PREPAD];
|
|
#endif
|
|
#endif
|
|
} TREE_NODE;
|
|
|
|
#ifdef TREEDEBUG
|
|
#undef xi_tree_malloc
|
|
#undef xi_tree_realloc
|
|
#define xi_tree_malloc_body xi_tree_malloc_d
|
|
#define xi_tree_realloc_body xi_tree_realloc_d
|
|
#define xi_tree_malloc_stub xi_tree_malloc
|
|
#define xi_tree_realloc_stub xi_tree_realloc
|
|
#else
|
|
#define xi_tree_malloc_body xi_tree_malloc
|
|
#define xi_tree_realloc_body xi_tree_realloc
|
|
#define xi_tree_malloc_stub xi_tree_malloc_d
|
|
#define xi_tree_realloc_stub xi_tree_realloc_d
|
|
#endif
|
|
|
|
#define VOIDPTR_TO_TREEPTR(p) ((TREE_NODE *)((char *)(p) - sizeof(TREE_NODE)))
|
|
#define TREEPTR_TO_VOIDPTR(t) ((void *)((t) + 1))
|
|
|
|
#define DBGTAB 3
|
|
|
|
static TREE_NODE topnode =
|
|
{
|
|
NULL, &topnode, NULL
|
|
#if XIWS == MTFWS
|
|
, NULL
|
|
#endif
|
|
#ifdef TREEDEBUG
|
|
, 0, "TOPNODE", MAGIC, 0
|
|
#endif
|
|
};
|
|
static TREE_NODE *top = &topnode;
|
|
#ifdef TREEDEBUG
|
|
#ifdef FENCE
|
|
static int fence_count;
|
|
#endif
|
|
static int node_count = 1; /* start with just top node */
|
|
#endif
|
|
|
|
static void
|
|
dflt_error_fcn(void)
|
|
{
|
|
xvt_dm_post_fatal_exit( "xi_tree_memory: Out of memory" );
|
|
}
|
|
|
|
static void (* error_fcn)(void) = dflt_error_fcn;
|
|
|
|
#ifdef TREEDEBUG
|
|
void xi_tree_check_fence(void);
|
|
void
|
|
xi_tree_check_fence(void)
|
|
{
|
|
#ifdef FENCE
|
|
static int fence_count;
|
|
|
|
fence_count++;
|
|
if (fence_count % FENCE == 0)
|
|
xi_tree_check_sanity("FENCE CHECK");
|
|
#endif
|
|
}
|
|
|
|
static void near
|
|
adjust_size(size_t *size)
|
|
{
|
|
NOREF(size);
|
|
#ifdef PAD
|
|
*size += PAD;
|
|
#endif
|
|
}
|
|
|
|
static void near
|
|
validate_node(void *p)
|
|
{
|
|
if (p != NULL && VOIDPTR_TO_TREEPTR(p)->magic != MAGIC)
|
|
fatal( "Bad tree node detected: file %s, line %d",
|
|
VOIDPTR_TO_TREEPTR(p)->file, VOIDPTR_TO_TREEPTR(p)->line );
|
|
}
|
|
#endif
|
|
|
|
static void near
|
|
remove_from_siblings_and_parent(TREE_NODE *remove_t)
|
|
{
|
|
TREE_NODE *tp;
|
|
|
|
/* remove from sibling list */
|
|
tp = remove_t;
|
|
while (tp->sibling != remove_t)
|
|
tp = tp->sibling;
|
|
tp->sibling = remove_t->sibling;
|
|
|
|
/* adjust parent pointers */
|
|
if (remove_t->parent->child == remove_t)
|
|
{
|
|
remove_t->parent->child = ((remove_t->sibling == remove_t) ?
|
|
NULL : remove_t->sibling);
|
|
}
|
|
}
|
|
|
|
static void near
|
|
xi_tree_free_internal(TREE_NODE *remove_t, BOOLEAN toplevel)
|
|
{
|
|
TREE_NODE *tp;
|
|
TREE_NODE *nexttp;
|
|
|
|
if (toplevel)
|
|
{
|
|
remove_from_siblings_and_parent(remove_t);
|
|
remove_t->sibling = NULL;
|
|
}
|
|
|
|
/* free all child nodes */
|
|
tp = remove_t->child;
|
|
if (tp != NULL)
|
|
do
|
|
{
|
|
/* store next pointer before nuking node */
|
|
nexttp = tp->sibling;
|
|
xi_tree_free_internal(tp, FALSE);
|
|
tp = nexttp;
|
|
} while (tp != remove_t->child);
|
|
|
|
/* free underlying heap manager memory */
|
|
#ifdef TREEDEBUG
|
|
heap_free(remove_t->file);
|
|
node_count--;
|
|
#endif
|
|
heap_free(remove_t);
|
|
}
|
|
|
|
void
|
|
xi_tree_reparent(void *p, void *parent)
|
|
{
|
|
TREE_NODE *tn;
|
|
|
|
#ifdef TREEDEBUG
|
|
xi_tree_check_fence();
|
|
validate_node(p);
|
|
#endif
|
|
remove_from_siblings_and_parent(VOIDPTR_TO_TREEPTR(p));
|
|
tn = VOIDPTR_TO_TREEPTR(p);
|
|
if (parent == NULL)
|
|
parent = TREEPTR_TO_VOIDPTR(top);
|
|
tn->parent = VOIDPTR_TO_TREEPTR(parent);
|
|
if (tn->parent->child == NULL)
|
|
{
|
|
tn->parent->child = tn;
|
|
tn->sibling = tn;
|
|
}
|
|
else
|
|
{
|
|
/* insert tn in the sibling list */
|
|
tn->sibling = tn->parent->child->sibling;
|
|
tn->parent->child->sibling = tn;
|
|
}
|
|
}
|
|
|
|
void
|
|
xi_tree_free(void *p)
|
|
{
|
|
#ifdef TREEDEBUG
|
|
xi_tree_check_fence();
|
|
validate_node(p);
|
|
#endif
|
|
xi_tree_free_internal(VOIDPTR_TO_TREEPTR(p), TRUE);
|
|
}
|
|
|
|
void *
|
|
xi_tree_get_parent(void *p)
|
|
{
|
|
TREE_NODE *parent;
|
|
|
|
#ifdef TREEDEBUG
|
|
validate_node(p);
|
|
#endif
|
|
parent = VOIDPTR_TO_TREEPTR(p)->parent;
|
|
return((parent == top) ? NULL : TREEPTR_TO_VOIDPTR(parent));
|
|
}
|
|
|
|
void *
|
|
xi_tree_malloc_body(size_t size, void *parent
|
|
#ifdef TREEDEBUG
|
|
, int line, char *file
|
|
#endif
|
|
)
|
|
{
|
|
TREE_NODE *tn;
|
|
#ifdef TREEDEBUG
|
|
size_t orig_size = size;
|
|
|
|
xi_tree_check_fence();
|
|
validate_node(parent);
|
|
adjust_size(&size);
|
|
#endif
|
|
tn = (TREE_NODE *)heap_malloc(size + sizeof(TREE_NODE));
|
|
if (! tn)
|
|
{
|
|
(* error_fcn)();
|
|
return NULL;
|
|
}
|
|
#ifdef TREEDEBUG
|
|
gmemset((char *)tn + sizeof(TREE_NODE) + orig_size,
|
|
PADCHAR, (long)(size - orig_size));
|
|
tn->file = (char *)heap_malloc(gstrlen(file) + 1);
|
|
if (! tn->file)
|
|
{
|
|
(* error_fcn)();
|
|
return NULL;
|
|
}
|
|
gstrcpy(tn->file, file);
|
|
tn->line = line;
|
|
tn->magic = MAGIC;
|
|
tn->size = size;
|
|
node_count++;
|
|
#endif
|
|
tn->child = NULL;
|
|
tn->sibling = tn;
|
|
if (parent == NULL)
|
|
parent = TREEPTR_TO_VOIDPTR(top);
|
|
tn->parent = VOIDPTR_TO_TREEPTR(parent);
|
|
if (tn->parent->child == NULL)
|
|
tn->parent->child = tn;
|
|
else
|
|
{
|
|
/* insert tn in the sibling list */
|
|
tn->sibling = tn->parent->child->sibling;
|
|
tn->parent->child->sibling = tn;
|
|
}
|
|
return(TREEPTR_TO_VOIDPTR(tn));
|
|
}
|
|
|
|
void *
|
|
xi_tree_realloc_body(void *p, size_t size
|
|
#ifdef TREEDEBUG
|
|
, int line, char *file
|
|
#endif
|
|
)
|
|
{
|
|
TREE_NODE *old_t;
|
|
TREE_NODE *new_t;
|
|
TREE_NODE *tp;
|
|
#ifdef TREEDEBUG
|
|
size_t orig_size = size;
|
|
|
|
xi_tree_check_fence();
|
|
adjust_size(&size);
|
|
#endif
|
|
old_t = VOIDPTR_TO_TREEPTR(p);
|
|
#ifdef TREEDEBUG
|
|
validate_node(p);
|
|
#endif
|
|
new_t = (TREE_NODE *)heap_realloc(old_t, (size + sizeof(TREE_NODE)));
|
|
#ifdef TREEDEBUG
|
|
if (! new_t)
|
|
{
|
|
(* error_fcn)();
|
|
return NULL;
|
|
}
|
|
gmemset((char *)new_t + sizeof(TREE_NODE) + orig_size,
|
|
PADCHAR, (long)(size - orig_size));
|
|
new_t->line = line;
|
|
new_t->size = size;
|
|
heap_free(new_t->file);
|
|
new_t->file = (char *)heap_malloc(gstrlen(file) + 1);
|
|
if (! new_t->file)
|
|
{
|
|
(* error_fcn)();
|
|
return NULL;
|
|
}
|
|
gstrcpy(new_t->file, file);
|
|
#endif
|
|
|
|
if (new_t != old_t)
|
|
{
|
|
/* change parent pointer */
|
|
if (new_t->parent->child == old_t)
|
|
new_t->parent->child = new_t;
|
|
|
|
/* change sibling pointers */
|
|
for (tp = new_t; tp->sibling != old_t; tp = tp->sibling)
|
|
;
|
|
tp->sibling = new_t;
|
|
|
|
/* change children pointers */
|
|
tp = new_t->child;
|
|
if (tp != NULL)
|
|
do
|
|
{
|
|
tp->parent = new_t;
|
|
tp = tp->sibling;
|
|
} while (tp != new_t->child);
|
|
}
|
|
return(TREEPTR_TO_VOIDPTR(new_t))
|
|
;
|
|
}
|
|
|
|
static void near
|
|
xi_tree_dbg_internal(TREE_NODE *tn, int level)
|
|
{
|
|
char buf[150];
|
|
char *s;
|
|
TREE_NODE *tn2;
|
|
int i, l;
|
|
|
|
if (tn == NULL)
|
|
return;
|
|
/* print tab indent indicating level */
|
|
s = buf;
|
|
for (l = level; l; l--)
|
|
{
|
|
for (i=0; i<DBGTAB; i++)
|
|
*s++ = ' ';
|
|
}
|
|
#ifdef TREEDEBUG
|
|
sprintf( s, "node %08lx: par=%08lx, sib=%08lx, ch=%08lx, file=%s, line=%d",
|
|
PTR_LONG(tn), PTR_LONG(tn->parent), PTR_LONG(tn->sibling),
|
|
PTR_LONG(tn->child), tn->file, tn->line );
|
|
#else
|
|
sprintf( s, "node %08lx: par=%08lx, sib=%08lx, ch=%08lx",
|
|
PTR_LONG(tn), PTR_LONG(tn->parent), PTR_LONG(tn->sibling),
|
|
PTR_LONG(tn->child) );
|
|
#endif
|
|
xi_dbg(buf);
|
|
tn2 = tn->child;
|
|
if (tn2 != NULL)
|
|
do
|
|
{
|
|
xi_tree_dbg_internal(tn2, level + 1);
|
|
tn2 = tn2->sibling;
|
|
} while (tn2 != tn->child);
|
|
}
|
|
|
|
void
|
|
xi_tree_dbg(char *title)
|
|
{
|
|
char buf[100];
|
|
|
|
sprintf(buf, "TREE MEMORY DEBUG TRACE (%s)", title);
|
|
xi_dbg(buf);
|
|
xi_dbg("=======================");
|
|
xi_tree_dbg_internal(top, 0);
|
|
heap_dbg(title);
|
|
xi_tree_check_sanity(title);
|
|
}
|
|
|
|
static void near
|
|
xi_tree_check_sanity_internal(TREE_NODE *tn, char *title,
|
|
int *count)
|
|
{
|
|
TREE_NODE *tn2;
|
|
|
|
#ifdef TREEDEBUG
|
|
#ifdef PAD
|
|
int i;
|
|
|
|
/* check pad bytes for node */
|
|
if (tn != &topnode)
|
|
for (i = tn->size - PAD; i < tn->size; i++)
|
|
if (*((char *)tn + sizeof(TREE_NODE) + i) != PADCHAR)
|
|
fatal( "xi_tree_node padding corrupted: node=%08lx, file=%s, line=%d",
|
|
PTR_LONG(tn), tn->file, tn->line );
|
|
#endif
|
|
#endif
|
|
/* check that all children point to this node */
|
|
tn2 = tn->child;
|
|
(*count)++;
|
|
if (tn2 != NULL)
|
|
do
|
|
{
|
|
if (tn2->parent != tn)
|
|
fatal( "memory check %s: tree node %08lx has bad parent",
|
|
title, PTR_LONG(tn2) );
|
|
xi_tree_check_sanity_internal(tn2, title, count);
|
|
tn2 = tn2->sibling;
|
|
} while (tn2 != tn->child);
|
|
}
|
|
|
|
void
|
|
xi_tree_check_sanity(char *title)
|
|
{
|
|
int count = 0;
|
|
|
|
xi_tree_check_sanity_internal(top, title, &count);
|
|
#ifdef TREEDEBUG
|
|
if (count != node_count)
|
|
fatal("tree sanity check failed: tree count=%d, allocation count=%d",
|
|
count, node_count);
|
|
#endif
|
|
}
|
|
|
|
#ifdef TREEDEBUG
|
|
void *xi_tree_malloc_stub(size_t size, void *parent);
|
|
void *
|
|
xi_tree_malloc_stub(size_t size, void *parent)
|
|
{
|
|
return(xi_tree_malloc_body(size, parent, 0, "(unknown)"));
|
|
}
|
|
|
|
void *xi_tree_realloc_stub(void *p, size_t size);
|
|
void *
|
|
xi_tree_realloc_stub(void *p, size_t size)
|
|
{
|
|
return(xi_tree_realloc_body(p, size, 0, "(unknown)"));
|
|
}
|
|
#else
|
|
void *xi_tree_malloc_stub(size_t size, void *parent,
|
|
int line, char *file);
|
|
void *
|
|
xi_tree_malloc_stub(size_t size, void *parent,
|
|
int line, char *file)
|
|
{
|
|
NOREF(line);
|
|
NOREF(file);
|
|
return(xi_tree_malloc_body(size, parent));
|
|
}
|
|
|
|
void *xi_tree_realloc_stub(void *p, size_t size,
|
|
int line, char *file);
|
|
void *
|
|
xi_tree_realloc_stub(void *p, size_t size,
|
|
int line, char *file)
|
|
{
|
|
NOREF(line);
|
|
NOREF(file);
|
|
return(xi_tree_realloc_body(p, size));
|
|
}
|
|
#endif
|
|
|
|
void
|
|
xi_tree_reg_error_fcn(void (* fcn)(void))
|
|
{
|
|
error_fcn = fcn;
|
|
}
|
|
|
|
|