/******************************************************************************* * 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; iparent), 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; }