Initializing help system before first use

Improved memory management for external types

For the task module we have described a very simple way of handling memory allocations in a module directly with the corresponding C functions: whenever an object of the new type needs to be created the required space is allocated and when the object is deleted this space is freed in C.

In this section we give an example of memory management by the module: the space for new complex numbers is allocated in large chunks. The module keeps track of the available space, including space that has already been used by this module and may be recycled. This proceding requires much less memory allocation operations and only a single set of deallocations. Furthermore, at the deletion of an object the possibily expensive search for the object in the entire list held by the module context is replaced by a copy of the pointer to the list of free space.

Module context

Contrary to the context of the task module that only keeps a single list, we now define a context that holds two lists:

typedef struct
    {
     s_nmlist *nmlist;
     u_freelist *freelist;
    } s_cxctx;

The first of these lists, nmlist, is all the space allocated for complex numbers, stored in chunks of size NCXL:

typedef struct Nmlist
    {
     s_complex list[NCXL];
     int nextfree;
     struct Nmlist *next;
    } s_nmlist;

The second list indicates the free entries in the list of numbers:

typedef union Freelist
    {
     s_complex cx;
     union Freelist *next;
    } u_freelist;

Service function reset

The reset service function initializes the module context at its first call and frees all space that has been allocated by the module at the next call to it:

static void *cx_reset(XPRMcontext ctx, void *libctx, int version)
{
 s_cxctx *cxctx;
 s_nmlist *nmlist;

 if(libctx==NULL)               /* libctx==NULL => initialization */
 {
  cxctx=malloc(sizeof(s_cxctx));
  memset(cxctx, 0, sizeof(s_cxctx));
  return cxctx;
 }
 else                           /* Otherwise release the resources we use */
 {
  cxctx=libctx;
  while(cxctx->nmlist!=NULL)
  {
   nmlist=cxctx->nmlist;
   cxctx->nmlist=nmlist->next;
   free(nmlist);
  }
  free(cxctx);
  return NULL;
 }
}

Type creation and deletion functions

In our example we define the task creation function printed below. As mentioned in the previous section, the space for complex numbers is not allocated one-by-one but in larger chunks and the module also keeps track of space that may be re-used. We therefore face the following choice every time a new complex number is created:

  • if possible re-use space that has been allocated earlier,
  • otherwise, if no free space remains, allocate a new block of complex numbers,
  • otherwise use the next free space.

In the case that the complex number passed into the creation function already exists we simply augment its reference counter.

static void *cx_create(XPRMcontext ctx, void *libctx, void *todup,
                       int typnum)
{
 s_cxctx *cxctx;
 s_complex *complex;
 s_nmlist *nmlist;

 if(todup!=NULL)
 {
  ((s_complex *)todup)->refcnt++;
  return todup;
 }
 else
 {
  cxctx=libctx;
  if(cxctx->freelist!=NULL)         /* Re-use allocated space that was freed */
  {
   complex=&(cxctx->freelist->cx);
   cxctx->freelist=cxctx->freelist->next;
  }
  else                              /* Allocate a new block of complex numbers */
   if((cxctx->nmlist==NULL)||(cxctx->nmlist->nextfree>=NCXL))
   {
    nmlist=malloc(sizeof(s_nmlist));
    nmlist->next=cxctx->nmlist;
    cxctx->nmlist=nmlist;
    nmlist->nextfree=1;
    complex=nmlist->list;
   }
   else                             /* Use allocated and yet free space */
    complex=&(cxctx->nmlist->list[cxctx->nmlist->nextfree++]);

  complex->re=complex->im=0;        /* Initialize the new complex number */
  complex->refcnt=1;
  return complex;
 }
}

The deletion function does not completely deallocate the space used by a complex number. It simply moves it into the list of space that may be recycled:

static void cx_delete(XPRMcontext ctx, void *libctx, void *todel, int typnum)
{
 s_cxctx *cxctx;
 u_freelist *freelist;

 if((todel!=NULL)&&((--((s_complex *)todel)->refcnt)<1))
 {
  cxctx=libctx;
  freelist=todel;                    /* Delete = space to be recycled */
  freelist->next=cxctx->freelist;
  cxctx->freelist=freelist;
 }
}