campo-sirio/xi/xitree.c
alex 18c8e52948 This commit was generated by cvs2svn to compensate for changes in r5757,
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
1997-12-17 10:43:31 +00:00

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;
}