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