/*
 *				t a l l o c . c
 */

/*)LIBRARY
*/

#ifdef	DOCUMENTATION

title	talloc	Threaded Storage Allocator Functions
index		Allocate space that can be easily deleted
index		Free space allocated by talloc()
index		Mark on current allocation thread

synopsis

	 char *
	 talloc(n)
	 unsigned n;

	 tfree(p)
	 char *p;

	 extern char *tmark;

description

	talloc() is like malloc(); it allocates space.  However, all this
	space is linked (threaded) together, and can be freed easily.  Thus:

		here = tmark;
		a = talloc(5);
		b = talloc(5);
		...
		tfree(here);

	The call to tfree() deletes a, b, and anything else allocated by
	talloc() between the point at which tmark was sampled and the call to
	tfree().

	Like malloc(), talloc() returns NULL if it can't get you space.

	It is safe to save tmark more than once; for example, if a function
	knows its caller has saved tmark, it needn't ensure that it always
	frees its space after an error; the caller's tfree() will get rid of
	everything.

	talloc() calls malloc(), and malloc() can be used without interfering
	with talloc(); tfree() has no effect on space allocated directly with
	malloc().

	Space allocated with talloc() must NEVER be passed to realloc() or
	free(); the pointers differ.

	Needless to say, passing a value to tfree() that was not obtained from
	tmark or which is obsolete because a value obtained earlier was
	already passed will cause trouble.

	The overhead involved in using talloc() instead of malloc() is one
	(char *) per call.

bugs

author

	Jerry Leichter

#endif

/*
 *)EDITLEVEL=09
 * Edit history
 * 0.0 18-May-81 JSL	Invention
 * 0.1 19-May-81 JSL	Fix bug in tfree()
 * 0.2 20-May-81 JSL	Cleanup; improved documentation
 */

#define NULL 0

extern char *malloc();

typedef union			/* Machine-dependent alignment constant */
	{ char u1;
	  char *u2;
	} ALIGN;
/* malloc() returns a pointer that is guaranteed to satisfy any alignment
 * constraint of its host machine.  talloc() should do the same.  talloc()
 * needs space for one character pointer for threading; type ALIGN must
 * guarantee (1) sufficient space for such a pointer and (2) that a pointer
 * returned by malloc(), + sizeof(ALIGN), also satisfies all alignment con-
 * straints.  For the PDP-11 and the VAX, word alignment is sufficient, and
 * a pointer is one word, so this is easy and requires no wasted space.  Other
 * machines may require more.
 */

struct p { char *pointer; };

static char *head = NULL;
char *tmark = &head;

char *
talloc(n)
unsigned n;
{	register char *space;
	if ((space = malloc(n + sizeof(ALIGN))) == NULL)
		return(NULL);
	((struct p *)tmark)->pointer = space;	/* link last to new */
	tmark = space;				/* point mark to new */
	((struct p *)space)->pointer = NULL;	/* clear link */
	return(space + sizeof(ALIGN));
}

tfree(p)
register char *p;
{	register char *q;

#ifdef DEBUG
	printf("tfree: head %o tmark %o p %o\n",&head,tmark,p);
#endif
	tmark = p;
	p = ((struct p *)p)->pointer;
	while (q = p)
	{	p = ((struct p *)q)->pointer;
#ifdef DEBUG
printf("Freeing %o\n",q);
#endif
		free(q);
	}	
	((struct p *)tmark)->pointer = NULL;
}
