The <alloc.h> Header File

Routines for dynamic memory allocation

Functions

alloca
Allocates memory on the local storage space.
calloc_throw
Performs calloc, and throws an error if not successful.
calloc
Allocates a memory block for a given number and size of items.
free
Frees an allocated block.
FreeHandles
Determines the number of free handles.
HeapAlloc
Allocates memory and returns a handle of allocated block.
HeapAllocESTACK
Like HeapAlloc, but reduces the size of the expression stack if necessary.
HeapAllocHigh
Allocates memory at the high end of the heap and returns the handle of the allocated block.
HeapAllocHighThrow
Performs HeapAllocHigh, and throws an error if not successful.
HeapAllocPtr
Allocates memory at the high end of the heap and returns a pointer to the allocated block.
HeapAllocPtrThrow
Performs HeapAllocPtr, and throws an error if not successful.
HeapAllocThrow
Performs HeapAlloc, and throws an error if not successful.
HeapAvail
Determines the size of the heap.
HeapCompress
Compresses the heap.
HeapDeref
Dereferences a handle.
HeapEnd
Determines the end of the heap.
HeapFree
Frees a heap block given its handle.
HeapFreeIndir
Frees a heap block given a pointer to it.
HeapFreePtr
Frees a block allocated using HeapAllocPtr.
HeapGetHandle
Gets the next available handle.
HeapGetLock
Determines whether a block is locked.
HeapLock
Locks a block.
HeapMax
Determines the size of the largest allocatable block.
HeapMoveHigh
Reallocates a block.
HeapPtrToHandle
Determines the handle associated with a block.
HeapRealloc
Reallocates a block to a new size.
HeapReallocThrow
Performs HeapRealloc, and throws an error if not successful.
HeapShuffle
Shuffles all unlocked blocks on the heap.
HeapSize
Determines the size of an allocated block.
HeapUnlock
Unlocks a block.
HeapWalk
Verifies and dumps the contents of the heap.
HLock
Locks and dereferences a handle.
malloc_throw
Performs malloc, and throws an error if not successful.
malloc
Allocates a memory block.
realloc_throw
Performs realloc, and throws an error if not successful.
realloc
Reallocates allocated memory.

Constants

H_NULL
A null-handle value.
NULL
A null-pointer value.

Predefined Types

Bool
An enumeration to describe true or false values.
HANDLE
Represents a handle associated with an allocated memory block.
HeapWalkCmds
An enumeration describing the valid parameters for HeapWalk.
size_t
A type to define sizes of strings and memory blocks.

See also: mem.h


alloca

void *alloca (unsigned long Size);

Allocates memory on the local storage space.

alloca is a function which is not included in the ANSI C standard, but it exists in many C dialects (including TIGCC). It allocates a block of Size bytes on the CPU stack (local storage space), in opposite to malloc which allocates memory on the memory heap. The space allocated with alloca exists until the containing function returns (i.e. it will be automatically deallocated at the end of the function). Be aware of the fact that the size of the hardware stack on TI calculators is limited to 16 kilobytes, so do not use alloca for allocating large blocks.

alloca is usually used for simulating automatic variable-sized one-dimensional arrays, which will be automatically deallocated when the function ends (like all automatic variables), so it is sometimes more preferable than malloc. For example, to simulate

int a[n];

where 'n' is not known in advance, you can use

int *a = alloca (n);

Note, however, that GNU C extensions allows variable-length arrays, which are more elegant than usage of alloca, and which may also be with more than one dimension (which is not possible with alloca).

Note: alloca is a built-in (open-coded) function in GNU C, which is translated to a single instruction which simply adjusts the stack. Some compiler command options (like '-ansi') prevent alloca from being an open-coded function. In this implementation of TIGCC, you can not use alloca with such options (however, it is very unlikely that you will ever have such problems).


calloc_throw

void *calloc_throw (unsigned short NoOfItems, unsigned short SizeOfItems);

Performs calloc, and throws an error if not successful.

calloc_throw calls calloc and throws a memory error if there is not enough memory. Otherwise, it returns a pointer to the allocated block.


calloc

void *calloc (unsigned short NoOfItems, unsigned short SizeOfItems);

Allocates a memory block for a given number and size of items.

calloc allocates a block of NoOfItems x SizeOfItems bytes from the memory heap. On success, calloc returns a pointer to the newly allocated block of memory. If not enough space exists for the new block, it returns NULL. The allocated block will be cleared to zero content.

Note: In releases of TIGCCLIB prior to 2.0, calloc was implemented here as a macro, Now, it is a function. It first calls malloc with NoOfItems x SizeOfItems as the argument, then calls memset if the first call was successful.

See also: malloc, realloc, free, calloc_throw


free

void free (void *Ptr);

Frees an allocated block.

free deallocates a memory block allocated by a previous call to malloc or calloc.

Note: free is in fact an ANSI C alias for a TIOS routine originally called HeapFreePtr.

Do not attempt to use free on a pointer which has changed after it was allocated with malloc, calloc, or realloc. For example, the following code will certainly crash the calculator:

char *ptr = malloc (2);
if (ptr)
  {
    *(ptr++) = 'A';  // pointer changed here
    *ptr = 0;
    ...
    free (ptr);
  }

Instead, preserve the original pointer and pass it to free.

See also: malloc, realloc, calloc


FreeHandles

short FreeHandles (void);

Determines the number of free handles.

FreeHandles returns the number of free handles.


HeapAlloc

HANDLE HeapAlloc (unsigned long Size);

Allocates memory and returns a handle of allocated block.

HeapAlloc allocates a block of heap memory of Size bytes (all odd sizes are rounded up to be even) and returns its handle. Allocated blocks are kept in a singly-linked list of blocks. Returns H_NULL if there is not enough memory. The maximum size of a single block is 65520 bytes, and the minimum size is 6 bytes. Use HeapDeref to dereference the handle and get a pointer to the actual memory. Note that an unlocked pointer to the heap is valid only as long as heap compression (i.e. garbage collection) is not done. This routine may cause garbage collection.


HeapAllocESTACK

HANDLE HeapAllocESTACK (unsigned long Size);

Like HeapAlloc, but reduces the size of the expression stack if necessary.

HeapAllocESTACK works like HeapAlloc, but reduces the size of the expression stack if necessary (i.e. if there is not enough memory). Returns H_NULL if there is not enough memory even after reducing the size of the expression stack.

Note: The information about this routine in releases of TIGCCLIB prior to 2.0 was wrong!


HeapAllocHigh

HANDLE HeapAllocHigh (unsigned long Size);

Allocates memory at the high end of the heap and returns the handle of the allocated block.

HeapAllocHigh allocates a block of Size bytes of heap memory at the high end of the heap, locks it, and returns its handle. Returns H_NULL if there is not enough memory. The primary use of this routine is to allocate task local storage. It also compresses the heap first to (hopefully) move all used (unlocked) blocks of memory down. This routine will cause garbage collection.

Note: Blocks of memory that are locked for long periods of time should be moved high in memory so that they do not interfere as much with rest of the system. This routine ALWAYS compresses the heap before it tries to allocate the requested memory and so is much slower than the standard HeapAlloc routine. Locking memory may cause the system to run out of useable memory sooner than if memory is kept unlocked.

See also: HeapAlloc


HeapAllocHighThrow

HANDLE HeapAllocHighThrow (unsigned long Size);

Performs HeapAllocHigh, and throws an error if not successful.

HeapAllocHighThrow calls HeapAllocHigh and throws a memory error if there is not enough memory. Otherwise, it returns the handle of the allocated block.


HeapAllocPtr

void *HeapAllocPtr (unsigned long Size);

Allocates memory at the high end of the heap and returns a pointer to the allocated block.

HeapAllocPtr performs HeapAllocHigh, but instead of the handle, it returns a pointer to the allocated block (NULL in a case of error). It also gives a necessary information to the heap manager which is needed later for deallocating the memory using HeapFreePtr command. This routine is principally equivalent to ANSI C malloc function, so it is aliased here also as malloc.

Note: If somebody is interested in it, the handle of the allocated block is stored two bytes below the address returned by HeapAllocPtr.


HeapAllocPtrThrow

void *HeapAllocPtrThrow (unsigned long Size);

Performs HeapAllocPtr, and throws an error if not successful.

HeapAllocPtrThrow calls HeapAllocPtr and throws a memory error if there is not enough memory. Otherwise, it returns the handle of the allocated block.


HeapAllocThrow

HANDLE HeapAllocThrow (unsigned long Size);

Performs HeapAlloc, and throws an error if not successful.

HeapAllocThrow calls HeapAlloc and throws a memory error if there is not enough memory. Otherwise, it returns the handle of the allocated block.


HeapAvail

unsigned long HeapAvail (void);

Determines the size of the heap.

HeapAvail returns the total amount of free bytes in the heap (the sum of all of the individual blocks of memory).


HeapCompress

void HeapCompress (void);

Compresses the heap.

HeapCompress coalesces all used heap blocks, deleting any free blocks from the heap if possible. If there are any locked blocks, the heap may remain fragmented. This routine is called automatically by the system whenever it is needed and usually should not be called by applications.

See also: HeapShuffle


HeapDeref

void *HeapDeref (HANDLE Handle);

Dereferences a handle.

HeapDeref dereferences Handle and returns a pointer to the actual block of the memory defined by that Handle. Nearly all heap allocation routines return a "handle" which is an identifier for a block of memory allocated in the heap. In order to use that memory, the handle must be dereferenced. Once a handle is dereferenced, that pointer is valid as long as nothing else is done to cause the heap to be compressed. If the heap is compressed the handle can be re-dereferenced to make it valid again. If a handle is locked, then the pointer that references that block of memory is valid even after the heap is compressed (since locking a handle means the heap manager will never move the memory associated with that handle).

Note: HeapDeref returns garbage if Handle is H_NULL.


HeapEnd

void *HeapEnd (void);

Determines the end of the heap.

HeapEnd returns a pointer to the end of the heap.


HeapFree

void HeapFree (HANDLE Handle);

Frees a heap block given its handle.

HeapFree frees a heap block associated with handle Handle.


HeapFreeIndir

void HeapFreeIndir (HANDLE *HandlePtr);

Frees a heap block given a pointer to it.

HeapFreeIndir is like HeapFree except you pass the address of a variable which keeps the block handle instead of the handle itself. If the handle that HandlePtr points to is not H_NULL, then it frees that handle and sets the handle variable that is pointed to by HandlePtr to H_NULL.

Maybe this sounds a bit confusing to you. In fact, doing

HeapFreeIndir (&handle);    // The ampersand ('&') is important

works exactly the same as

if (handle) HeapFree (handle);
handle = H_NULL;

Note: In releases of TIGCCLIB prior to 2.2, the information about this routine was quite misleading or even wrong.


HeapFreePtr

void HeapFreePtr (void *Ptr);

Frees a block allocated using HeapAllocPtr.

HeapFreePtr frees a heap block pointed to by Ptr. The block must be a block which was allocated using the HeapAllocPtr command.

Do not attempt to use HeapFreePtr on a pointer which has changed after it was allocated with HeapAllocPtr. For example, the following code will certainly crash the calculator:

char *ptr = HeapAllocPtr (2);
if (ptr)
  {
    *(ptr++) = 'A';  // pointer changed here
    *ptr = 0;
    ...
    HeapFreePtr (ptr);
  }

Instead, preserve the original pointer and pass it to HeapFreePtr.


HeapGetHandle

HANDLE HeapGetHandle (void);

Gets the next available handle.

HeapGetHandle returns the number of the first unallocated (free) handle, or H_NULL if there are no free handles. Used mainly for internal purposes.


HeapGetLock

short HeapGetLock (HANDLE Handle);

Determines whether a block is locked.

Returns non-zero if the block given by Handle is locked, 0 if it is not (i.e. if that memory is free to move on the next heap compression).


HeapLock

HANDLE HeapLock (HANDLE Handle);

Locks a block.

HeapLock locks the block referenced by Handle so that it is not moved during garbage collection. Returns Handle if OK, else returns H_NULL.

Note: Locking memory may cause the system to run out of usable memory sooner than if memory is kept unlocked.


HeapMax

unsigned long HeapMax (void);

Determines the size of the largest allocatable block.

HeapMax returns the size of the largest block allocatable on the heap (it will be in the range of 0 through 65520). Note that this may not be equal to HeapAvail due to locked blocks, overhead, and maximum block size. This routine will (always) cause heap compression (garbage collection).


HeapMoveHigh

HANDLE HeapMoveHigh (HANDLE Handle);

Reallocates a block.

HeapMoveHigh tries to reallocate a block referenced by Handle as high in memory as possible. The block must not be locked. If successful, returns the handle passed; otherwise returns H_NULL (in this case, the block is still in the same place as before, so no memory is lost). This routine will cause heap compression (garbage collection).


HeapPtrToHandle

HANDLE HeapPtrToHandle (void *Ptr);

Determines the handle associated with a block.

HeapPtrToHandle returns the handle which is associated with a block that is pointed to by Ptr (or H_NULL if there is not a handle that references the given block). This routine works by searching the entire table of handles for the given pointer, and so should be used accordingly. It assumes that the heap has not been compressed since the dereferenced pointer was originally obtained or the block it points to is locked.


HeapRealloc

HANDLE HeapRealloc (HANDLE Handle, unsigned long NewSize);

Reallocates a block to a new size.

If Handle is H_NULL, HeapRealloc calls HeapAlloc. Otherwise, it tries to reallocate the given heap block to a new size. Returns H_NULL if there is not enough memory (it will try to call HeapCompress) or if new size is invalid; otherwise returns Handle (but Handle will still be valid even if there was not enough memory). If the heap block is locked, then the block will not be moved in order to reallocate it. However, unlocked blocks above the heap block will be moved. The contents of the object will be unchanged up to the lesser of the new and old size. If the new size is larger, the value of the newly allocated portion of the block is indeterminate. This routine may cause garbage collection.

Note: Reallocating a locked block may fail very easily, especially if you have allocated and locked some blocks just shortly before. The reason is simple: If you allocate memory blocks in sequence, they are usually located close to each other. If you try to grow a locked block which lies directly in front of another locked block, the operation will fail because the second locked block cannot be moved. In general it is a good idea to unlock memory blocks before using HeapRealloc, and to lock them again afterwards if necessary. This way the probability to succeed is much higher.


HeapReallocThrow

HANDLE HeapReallocThrow (HANDLE Handle, unsigned long NewSize);

Performs HeapRealloc, and throws an error if not successful.

HeapReallocThrow calls HeapRealloc and throws a memory error if there is not enough memory. Otherwise, it returns the handle of the allocated block.


HeapShuffle

AMS 2.00 or higher

void HeapShuffle (void);

Shuffles all unlocked blocks on the heap.

HeapShuffle shuffles all unlocked blocks on the heap. As a consequence, all dereferenced handles to unlocked blocks of memory in the heap may become invalid. This function is not the same as HeapCompress. It is used mainly for debugging the program.

Here is a test example (called "Heap Shuffle"):

// Call HeapShuffle and compare addresses

#define USE_TI89              // Compile for TI-89
#define USE_TI92PLUS          // Compile for TI-92 Plus
#define USE_V200              // Compile for V200

#define OPTIMIZE_ROM_CALLS    // Use ROM Call Optimization
#define MIN_AMS 200           // Compile for AMS 2.00 or higher
#define SAVE_SCREEN           // Save/Restore LCD Contents

#include <tigcclib.h>         // Include All Header Files

// Main Function
void _main(void)
{
  unsigned char *p1, *p2, *p3, *p4, *p5, *p6;
  HANDLE h1, h2, h3;
  short f = FontGetSys ();
  unsigned char b[50];
  
  h1 = HeapAlloc (0x1000);
  h2 = HeapAlloc (0x1000);
  h3 = HeapAlloc (0x1000);
  
  if (h1 && h2 && h3)
    {
      ClrScr ();
      
      p1 = HeapDeref (h1);
      p3 = HeapDeref (h2);
      p5 = HLock (h3);
      HeapShuffle ();
      p2 = HeapDeref (h1);
      p4 = HeapDeref (h2);
      p6 = HeapDeref (h3);
      
      FontSetSys (F_4x6);
      DrawStr (0, 0, "Before/after shuffle:", A_NORMAL);
      
      sprintf (b, "Block 1 (unlocked): %lp %lp", p1, p2);
      DrawStr (0, 10, b, A_NORMAL);
      
      sprintf (b, "Block 2 (unlocked): %lp %lp", p3, p4);
      DrawStr (0, 20, b, A_NORMAL);
      
      sprintf (b, "Block 3 (locked): %lp %lp", p5, p6);
      DrawStr (0, 30, b, A_NORMAL);
      
      FontSetSys (f); // Restore previous font
      GKeyIn (NULL, 0);
    }
  
  HeapFree (h3);
  HeapFree (h2);
  HeapFree (h1);
}

See also: HeapCompress, HeapWalk


HeapSize

unsigned long HeapSize (HANDLE Handle);

Determines the size of an allocated block.

HeapSize returns the number of bytes allocated for the heap block referenced by Handle. Due to word alignment and minimum block size, this may not be the amount it was allocated with. Also note that because of locked blocks, it is possible (rare) that a heap block will actually be bumped up a few words by the HeapCompress routine. So never assume that the value returned by HeapSize is the true number of bytes used by the data stored in the heap block.


HeapUnlock

HANDLE HeapUnlock (HANDLE Handle);

Unlocks a block.

HeapUnlock unlocks the block referenced by the Handle so that it can be moved during garbage collection. Returns Handle if OK, else returns H_NULL.


HeapWalk

AMS 2.00 or higher

short HeapWalk (short function);

Verifies and dumps the contents of the heap.

HeapWall looks through the heap to verify it is valid. Then it prints the status of the heap, prints the size of each heap block and its handle, or prints the symbol table, according to the value of function. HeapWalk uses LIO_SendData to send the output through the link port.

The valid values for function, defined in the enum HeapWalkCmds, are:

H_WALK_VERIFY The function just verifies the heap, and outputs nothing to the link port.
H_WALK_STATUS The function outputs the total free space, maximum size of a free block, number of used and free blocks, and the number of locked blocks.
H_WALK_DUMP The function outputs the heap status and the size of the heap block for each handle.
H_WALK_SYM AMS 2.04 or higher: The function outputs the entire VAT.

HeapWalk called with function as H_WALK_VERIFY, H_WALK_STATUS or H_WALK_DUMP, returns TRUE if the heap is valid, FALSE otherwise.
HeapWalk(H_WALK_SYM) executes this block of code after verifying the heap. The example "List variables and folders" works on any AMS version, unlike HeapWalk(H_WALK_SYM):

// Sends the list of all variables and folders through the link port.
// This program does what HeapWalk(H_WALK_SYM); does on AMS 2.04 and
// later, but also works on any AMS version.

#define USE_TI89              // Compile for TI-89
#define USE_TI92PLUS          // Compile for TI-92 Plus
#define USE_V200              // Compile for V200

#define SAVE_SCREEN           // Save/Restore LCD Contents
#define OPTIMIZE_ROM_CALLS    // Use ROM Call Optimization
#define NO_CALC_DETECT
#define ENABLE_ERROR_RETURN
#define MIN_AMS 100           // Compile for AMS 1.00 or higher

#include <tigcclib.h>         // Include All Header Files

void _main(void)
{
SYM_ENTRY *symptr;
unsigned char buffer[256];
#ifdef SAVE_SYMPG // Saving the SymPG isn't necessary in _main, nobody else does it.
SymPG_S save;
TRY
  memcpy(&save, pSymPG, sizeof(SymPG_S));
#endif
  if ((symptr = SymFindFirst(NULL,2)) != NULL)
  {
    strcpy(buffer, "\r\nName/Flags/hVal (dec)\r\n");
    LIO_SendData(buffer, strlen((char*)buffer));
    do
    {
      short flags = symptr->flags.flags_n;
      if ((flags&SF_FOLDER))
        sprintf((char *)buffer, "FOLDER: %-8s   %04X  %hd\r\n", symptr->name,
        flags, symptr->handle);
      else
        sprintf((char *)buffer, "%8s\\%-8s %04X  %hd\r\n", SymFindFolderName(),
        symptr->name, flags, symptr->handle);
      LIO_SendData(buffer, strlen((char *)buffer));
      symptr = SymFindNext();
    } while (symptr != NULL);
  }
#ifdef SAVE_SYMPG // See above.
FINALLY
  memcpy(pSymPG, &save, sizeof(SymPG_S));
ENDFINAL
#endif
}

See also: HeapShuffle, vat.h, SymFindFolderName, pSymPG, SymPG_S


HLock

void *HLock (HANDLE Handle);

Locks and dereferences a handle.

HLock locks a block referenced by Handle so that it will not move on the next heap compression, and returns a pointer to the actual memory block. Returns NULL in a case of error.

Note: Locking memory may cause the system to run out of usable memory sooner than if memory is kept unlocked.


malloc_throw

void *malloc_throw (unsigned long Size);

Performs malloc, and throws an error if not successful.

malloc_throw calls malloc and throws a memory error if there is not enough memory. Otherwise, it returns a pointer to the allocated block.


malloc

void *malloc (unsigned long Size);

Allocates a memory block.

malloc allocates a block of Size bytes from the memory heap. It allows a program to allocate memory explicitly as it's needed, and in the exact amounts needed. The heap is used for dynamic allocation of variable-sized blocks of memory. Many data structures, such as trees and lists, naturally employ heap memory allocation. On success, malloc returns a pointer to the newly allocated block of memory. If not enough space exists for the new block, it returns NULL. The contents of the block are left unchanged. If the argument Size is zero malloc also returns NULL. malloc is in fact an ANSI C alias for a TIOS routine originally called HeapAllocPtr (see description of it for more system info).

Note: As the TIOS memory manager assigns a handle to each allocated block, and as the total number of handles is limited, malloc is not good for algorithms where you need to allocate a large number of small blocks (as in implementations of linked lists which are usually seen in various C language books and tutorials). The same is true for all other TIOS memory management routines.

See also: realloc, calloc, free, malloc_throw


realloc_throw

void *realloc_throw (void *Ptr, unsigned long NewSize);

Performs realloc, and throws an error if not successful.

realloc_throw calls realloc and throws a memory error if there is not enough memory. Otherwise, it returns a pointer to the allocated block.


realloc

void *realloc (void *Ptr, unsigned long NewSize);

Reallocates allocated memory.

realloc attempts to shrink or expand the previously allocated block to NewSize bytes. The Ptr argument points to a memory block previously obtained by calling malloc, calloc, or realloc. It may also be NULL; in this case the function simply calls malloc.

realloc adjusts the size of the allocated block to NewSize, copying the contents to a new location if necessary (note that the block will not stay in high memory after the reallocation, but it will still remain locked; see other functions from this header file for more info). realloc returns the address of the reallocated block, which can be different than the address of the original block. If the block cannot be reallocated, realloc returns NULL.

Usually realloc keeps the current contents of the block intact; only the portion of the block which is newly allocated is not initialized and contains random content. However, unlike HeapRealloc, the function frees the block pointed to by Ptr if there was an error, so you can not assume that the data pointed to by Ptr is still valid. This is done because there is no way to guarantee that Ptr is still valid after the heap compression which HeapRealloc tries to perform (this function uses HeapRealloc internally).

Note: realloc is introduced to increase compatibility with ANSI C. It is better to use the official TIOS function HeapRealloc, which uses a system of handles to memory blocks.

See also: malloc, calloc, free, realloc_throw


H_NULL

#define H_NULL 0

A null-handle value.

H_NULL is a null-handle defined as a constant with value 0.


NULL

#define NULL ((void *) 0)

A null-pointer value.

NULL is a null-pointer value, defined as a pointer to the address 0.


Bool

enum Bool {FALSE, TRUE};

An enumeration to describe true or false values.

The enum Bool represents a boolean value, that is, either 'true' or 'false'. The constant FALSE equals 0; TRUE equals 1.


HANDLE

typedef unsigned short HANDLE;

Represents a handle associated with an allocated memory block.

The HANDLE type is mainly used to manage dynamically allocated memory using functions from alloc.h, but a lot of functions from other header files take instances of this type as parameters.

A handle points to a word-aligned block of memory, whose current address can be retrieved using HeapDeref.

See also: HeapAlloc, HeapFree, HLock, HeapUnlock, HeapDeref


HeapWalkCmds

AMS 2.00 or higher

enum HeapWalkCmds {H_WALK_VERIFY = 0, H_WALK_STATUS = 1, H_WALK_DUMP = 2, H_WALK_SYM = 3};

An enumeration describing the valid parameters for HeapWalk.


Return to the main index