Path: utzoo!attcan!uunet!lll-winken!lll-tis!ames!mailrus!purdue!decwrl!hplabs!hp-pcd!hpcvlx!fred From: fred@hpcvlx.HP.COM (Fred Taft) Newsgroups: comp.windows.x Subject: Re: HP's Xtk Fixes (as Context Diffs) Message-ID: <1610047@hpcvlx.HP.COM> Date: 19 Aug 88 19:52:11 GMT References: <1610043@hpcvlx.HP.COM> Organization: Hewlett-Packard Co., Corvallis, OR, USA Lines: 691 VERSION: Xtk release 2 SYNOPSIS: Using XtParseTranslationTable() causes a program to grow without an upper bound. DESCRIPTION: XtParseTranslationTable() returns a pointer to a translation state table, which in turn contains potentially many other pointers to blocks of memory (state records, action records, etc). Unfortunately, the toolkit does not provide a mechanism for freeing up this memory once an application is done with it. It appears that the reason the memory is not freed up is because the toolkit caches these parsed translation table, thus potentially saving time (and space) if the same translation is ever parsed again. However, our widget set parses many (possibly 100 or more, depending upon what widgets you use), and each of the translation tables are unique. If an application, such as a window manager, is creating and destroying alot of widgets, it's size continues to grow because all of these state tables are cached, but never used again after the associated widget is destroyed. The patches which follow affect the following files: 1) TMstate.c - Added XtDestroyStateTable(), which frees up a translation state table and all underlying malloc memory. Modified MergeStates() to create new copies of the parameter strings and array of string pointers, rather than just copying the existing pointers. Removed the caching of the parsed event state tables in XtOverrideTranslations and XtAugmentTranslations. Added a call to XtDestroyStateTable() in both XtOverrideTranslations and XtAugmentTranslations, to free up the widgets old translation state table. 2) TMparse.c - Removed the caching of the parsed event state table in XtParseTranslationTable(). 3) Core.c - Added a call to XtDestroyStateTable() in CoreDestroy(), to free up the widgets state table. REPEAT-BY: Have a program which parses several unique translation tables, and watch the size of the program grow. FIX: *** Core.c Fri Aug 19 11:26:00 1988 --- Core.new.c Fri Aug 19 11:25:42 1988 *************** *** 277,282 } XtFree((char *) widget->core.tm.proc_table); _XtUnregisterWindow(widget->core.window, widget); if (widget->core.constraints != NULL) XtFree((char *) widget->core.constraints); for (i = 0; i < widget->core.num_popups; i++) { --- 277,290 ----- } XtFree((char *) widget->core.tm.proc_table); _XtUnregisterWindow(widget->core.window, widget); + + + /* Destroy the translation state table */ + + XtDestroyStateTable (widget->core.widget_class, + widget->core.tm.translations); + + if (widget->core.constraints != NULL) XtFree((char *) widget->core.constraints); for (i = 0; i < widget->core.num_popups; i++) { *** TMparse.c Fri Aug 19 11:34:09 1988 --- TMparse.new.c Fri Aug 19 11:33:50 1988 *************** *** 1418,1423 XtTranslations XtParseTranslationTable(source) String source; { XrmValue from,to; from.addr = source; from.size = strlen(source)+1; --- 1418,1424 ----- XtTranslations XtParseTranslationTable(source) String source; { + int noArgs = 0; XrmValue from,to; from.addr = source; from.size = strlen(source)+1; *************** *** 1421,1426 XrmValue from,to; from.addr = source; from.size = strlen(source)+1; XtDirectConvert((XtConverter) _CompileTranslations, (XrmValuePtr) NULL, 0, &from, &to); return (*(XtTranslations*)(to.addr)); --- 1422,1431 ----- XrmValue from,to; from.addr = source; from.size = strlen(source)+1; + to.addr = NULL; + to.size = 0; + _CompileTranslations (NULL, &noArgs, &from, &to); + /* XtDirectConvert((XtConverter) _CompileTranslations, (XrmValuePtr) NULL, 0, &from, &to); */ *************** *** 1423,1428 from.size = strlen(source)+1; XtDirectConvert((XtConverter) _CompileTranslations, (XrmValuePtr) NULL, 0, &from, &to); return (*(XtTranslations*)(to.addr)); } --- 1428,1434 ----- /* XtDirectConvert((XtConverter) _CompileTranslations, (XrmValuePtr) NULL, 0, &from, &to); + */ return (*(XtTranslations*)(to.addr)); } *** TMstate.c Fri Aug 19 11:40:59 1988 --- TMstate.new.c Fri Aug 19 11:40:31 1988 *************** *** 39,44 #include "TMprivate.h" #include#define StringToAction(string) ((XtAction) StringToQuark(string)) --- 38,47 ----- #include "TMprivate.h" #include + typedef struct _DestroyListEntry { + XtTranslations stateTable; + struct _DestroyListEntry * next; + } DestroyListEntry; /* List of state tables waiting to be destroyed */ static DestroyListEntry * st_destroy_list = NULL; *************** *** 40,45 #include #define StringToAction(string) ((XtAction) StringToQuark(string)) static void FreeActions(action) --- 43,55 ----- struct _DestroyListEntry * next; } DestroyListEntry; + /* List of state tables waiting to be destroyed */ + static DestroyListEntry * st_destroy_list = NULL; + static int entryCount = 0; + static Boolean safe = FALSE; + static _DestroyStateTable(); + + #define StringToAction(string) ((XtAction) StringToQuark(string)) static void FreeActions(action) *************** *** 332,338 EventRec curEvent; StatePtr current_state = ((TMRec*)closure)->current_state; int index; ! register ActionPtr actions; XtActionProc* proc_table = ((TMRec*)closure)->proc_table; TMRec* tm = (TMRec*)closure; /* gross disgusting special case ||| */ --- 342,348 ----- EventRec curEvent; StatePtr current_state = ((TMRec*)closure)->current_state; int index; ! register ActionPtr actions, nextAction; XtActionProc* proc_table = ((TMRec*)closure)->proc_table; TMRec* tm = (TMRec*)closure; /* gross disgusting special case ||| */ *************** *** 340,345 && event->xcrossing.detail == NotifyInferior) return; XEventToTMEvent (event, &curEvent); #ifdef notdef --- 350,357 ----- && event->xcrossing.detail == NotifyInferior) return; + entryCount++; + XEventToTMEvent (event, &curEvent); #ifdef notdef *************** *** 360,365 index = MatchEvent (stateTable, &curEvent); if (index == -1) /* some event came in that we don't have any states for */ /* ignore it. */ return; --- 372,378 ----- index = MatchEvent (stateTable, &curEvent); if (index == -1) + { /* some event came in that we don't have any states for */ /* ignore it. */ entryCount--; *************** *** 362,367 if (index == -1) /* some event came in that we don't have any states for */ /* ignore it. */ return; /* are we currently in some state other than ground? */ --- 375,381 ----- { /* some event came in that we don't have any states for */ /* ignore it. */ + entryCount--; return; } *************** *** 363,368 /* some event came in that we don't have any states for */ /* ignore it. */ return; /* are we currently in some state other than ground? */ if (current_state != NULL) { --- 377,383 ----- /* ignore it. */ entryCount--; return; + } /* are we currently in some state other than ground? */ if (current_state != NULL) { *************** *** 404,409 if (Ignore(&curEvent)) { /* ignore it. */ current_state = oldState; return; } /* do ground state */ } --- 419,425 ----- if (Ignore(&curEvent)) { /* ignore it. */ current_state = oldState; + entryCount--; return; } /* do ground state */ } *************** *** 411,417 if (current_state == NULL) { /* check ground level */ current_state = stateTable->eventObjTbl[index].state; ! if (current_state == NULL) return; } tm->lastEventTime = GetTime (tm, event); --- 427,437 ----- if (current_state == NULL) { /* check ground level */ current_state = stateTable->eventObjTbl[index].state; ! if (current_state == NULL) ! { ! entryCount--; ! return; ! } } tm->lastEventTime = GetTime (tm, event); *************** *** 419,427 /* perform any actions */ actions = current_state->actions; while (actions != NULL) { ! /* perform any actions */ ! if (proc_table[actions->index] != NULL) ! (*(proc_table[actions->index]))( w, event, actions->params, &actions->num_params); actions = actions->next; } --- 439,455 ----- /* perform any actions */ actions = current_state->actions; while (actions != NULL) { ! nextAction = actions->next; ! ! /* Flag used during destroy of state tables */ ! if (nextAction == NULL) ! safe = TRUE; ! else ! safe = FALSE; ! ! /* perform any actions */ ! if (proc_table[actions->index] != NULL) ! (*(proc_table[actions->index]))( w, event, actions->params, &actions->num_params); actions = nextAction; *************** *** 423,429 if (proc_table[actions->index] != NULL) (*(proc_table[actions->index]))( w, event, actions->params, &actions->num_params); ! actions = actions->next; } /* move into successor state */ --- 451,458 ----- if (proc_table[actions->index] != NULL) (*(proc_table[actions->index]))( w, event, actions->params, &actions->num_params); ! ! actions = nextAction; } /* *************** *** 426,433 actions = actions->next; } ! /* move into successor state */ ! ((TMRec*)tm)->current_state = current_state->nextLevel; } static Boolean EqualEvents(event1, event2) --- 455,486 ----- actions = nextAction; } ! /* ! * If the state table for this widget has changed, then we ! * need to drop back to the ground level, and start over. ! */ ! if (stateTable != tm->translations) ! ((TMRec*)tm)->current_state = NULL; ! else ! /* move into successor state */ ! ((TMRec*)tm)->current_state = current_state->nextLevel; ! ! entryCount--; ! if ((entryCount == 0) && st_destroy_list) ! { ! /* It is now safe to destroy any state tables on the destroy list */ ! DestroyListEntry * current, * next; ! ! current = st_destroy_list; ! while (current) ! { ! next = current->next; ! _DestroyStateTable(current->stateTable); ! XtFree(current); ! current = next; ! } ! st_destroy_list = NULL; ! } } static Boolean EqualEvents(event1, event2) *************** *** 863,868 register StatePtr state; StateMap oldStateMap = stateMap; ActionRec *a,**aa,*b; while (new != NULL) { register int index = indexMap[new->index]; --- 916,922 ----- register StatePtr state; StateMap oldStateMap = stateMap; ActionRec *a,**aa,*b; + register int i; while (new != NULL) { register int index = indexMap[new->index]; *************** *** 902,908 a = XtNew(ActionRec); a->token = NULL; a->index = quarkIndexMap[b->index]; ! a->params = b->params; a->num_params=b->num_params; a->next = NULL; *aa = a; --- 956,964 ----- a = XtNew(ActionRec); a->token = NULL; a->index = quarkIndexMap[b->index]; ! ! ! /* a->params = b->params; */ a->num_params=b->num_params; if (a->num_params > 0) a->params = (char **) XtMalloc (sizeof (char *) * b->num_params); *************** *** 904,909 a->index = quarkIndexMap[b->index]; a->params = b->params; a->num_params=b->num_params; a->next = NULL; *aa = a; aa = &a->next; --- 960,975 ----- /* a->params = b->params; */ a->num_params=b->num_params; + if (a->num_params > 0) + a->params = (char **) XtMalloc (sizeof (char *) * b->num_params); + else + a->params = NULL; + for (i = 0; i < b->num_params; i++) + { + a->params[i] = (char *) XtMalloc (strlen (b->params[i]) + 1); + strcpy (a->params[i], b->params[i]); + } + a->next = NULL; *aa = a; aa = &a->next; *************** *** 1080,1085 Cardinal numQuarks = 0; XrmValue from,to; TMConvertRec foo; from.addr = (caddr_t)&foo; from.size = sizeof(TMConvertRec); --- 1146,1152 ----- Cardinal numQuarks = 0; XrmValue from,to; TMConvertRec foo; + int noArgs = 0; from.addr = (caddr_t)&foo; from.size = sizeof(TMConvertRec); *************** *** 1090,1095 if (widget->core.tm.translations != NULL) numQuarks = widget->core.tm.translations->numQuarks; XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL, 0, &from, &to); --- 1157,1164 ----- if (widget->core.tm.translations != NULL) numQuarks = widget->core.tm.translations->numQuarks; + _MergeTranslations (NULL, &noArgs, &from, &to); + /* XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL, 0, &from, &to); */ *************** *** 1092,1097 XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL, 0, &from, &to); widget->core.tm.translations =(*(XtTranslations*)to.addr); --- 1161,1167 ----- /* XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL, 0, &from, &to); + */ /* Destroy the translation state table */ *************** *** 1093,1098 XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL, 0, &from, &to); widget->core.tm.translations =(*(XtTranslations*)to.addr); if (XtIsRealized(widget)) --- 1163,1175 ----- 0, &from, &to); */ + + /* Destroy the translation state table */ + + XtDestroyStateTable (widget->core.widget_class, + widget->core.tm.translations); + + widget->core.tm.translations =(*(XtTranslations*)to.addr); if (XtIsRealized(widget)) *************** *** 1134,1139 Cardinal numQuarks = 0; XrmValue from,to; TMConvertRec foo; from.addr = (caddr_t)&foo; from.size = sizeof(TMConvertRec); --- 1211,1217 ----- Cardinal numQuarks = 0; XrmValue from,to; TMConvertRec foo; + int noArgs = 0; from.addr = (caddr_t)&foo; from.size = sizeof(TMConvertRec); *************** *** 1144,1149 if (widget->core.tm.translations != NULL) numQuarks = widget->core.tm.translations->numQuarks; XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL, 0, &from, &to); --- 1222,1229 ----- if (widget->core.tm.translations != NULL) numQuarks = widget->core.tm.translations->numQuarks; + _MergeTranslations (NULL, &noArgs, &from, &to); + /* XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL, 0, &from, &to); */ *************** *** 1146,1151 XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL, 0, &from, &to); widget->core.tm.translations = (*(XtTranslations*)to.addr); --- 1226,1232 ----- /* XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL, 0, &from, &to); + */ /* Destroy the translation state table */ *************** *** 1147,1152 XtDirectConvert((XtConverter) _MergeTranslations, (XrmValuePtr) NULL, 0, &from, &to); widget->core.tm.translations = (*(XtTranslations*)to.addr); if (XtIsRealized(widget)) --- 1228,1240 ----- 0, &from, &to); */ + + /* Destroy the translation state table */ + + XtDestroyStateTable (widget->core.widget_class, + widget->core.tm.translations); + + widget->core.tm.translations = (*(XtTranslations*)to.addr); if (XtIsRealized(widget)) *************** *** 1415,1417 void _XtPopupInitialize() { XtAddActions(tmActions, XtNumber(tmActions)); } --- 1503,1568 ----- void _XtPopupInitialize() { XtAddActions(tmActions, XtNumber(tmActions)); } + + + /* HP added translation state table deallocation procedure. */ + /* This is used by both toolkit functions and widgets to */ + /* eliminate a huge memory whole. */ + + XtDestroyStateTable (class, stateTable) + + WidgetClass class; + XtTranslations stateTable; + + { + register StatePtr state, nextState; + register ActionPtr action, nextAction; + + /* Don't do anything if the state table is the widget class's state table */ + if (stateTable && (stateTable != (XtTranslations)class->core_class.tm_table)) + { + if ((entryCount == 0) || safe) + { + _DestroyStateTable(stateTable); + } + else + { + DestroyListEntry * new; + + new = XtNew(DestroyListEntry); + new->next = st_destroy_list; + new->stateTable = stateTable; + st_destroy_list = new; + } + } + } + + + static _DestroyStateTable (stateTable) + + XtTranslations stateTable; + + { + register StatePtr state, nextState; + register ActionPtr action, nextAction; + + /* Free up each state record and all associated action records */ + for (state = stateTable->head; state != NULL; ) + { + for (action = state->actions; action != NULL; ) + { + nextAction = action->next; + FreeActions(action); + action = nextAction; + } + + nextState = state->forw; + XtFree(state); + state = nextState; + } + + /* Free up quark Table, event object array and the state table */ + XtFree(stateTable->quarkTable); + XtFree(stateTable->eventObjTbl); + XtFree(stateTable); + }