123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- /*
- alloca -- (mostly) portable public-domain implementation -- D A Gwyn
- 93/3/31 jimb
- Use xfree instead of free.
- 86/05/30 rms
- include config.h, since on VMS it renames some symbols.
- Use xmalloc instead of malloc.
- This implementation of the PWB library alloca() function,
- which is used to allocate space off the run-time stack so
- that it is automatically reclaimed upon procedure exit,
- was inspired by discussions with J. Q. Johnson of Cornell.
- It should work under any C implementation that uses an
- actual procedure stack (as opposed to a linked list of
- frames). There are some preprocessor constants that can
- be defined when compiling for your specific system, for
- improved efficiency; however, the defaults should be okay.
- The general concept of this implementation is to keep
- track of all alloca()-allocated blocks, and reclaim any
- that are found to be deeper in the stack than the current
- invocation. This heuristic does not reclaim storage as
- soon as it becomes invalid, but it will do so eventually.
- As a special case, alloca(0) reclaims storage without
- allocating any. It is a good idea to use alloca(0) in
- your main control loop, etc. to force garbage collection.
- */
- #ifndef lint
- static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */
- #endif
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #ifdef emacs
- #ifdef static
- /* actually, only want this if static is defined as ""
- -- this is for usg, in which emacs must undefine static
- in order to make unexec workable
- */
- #ifndef STACK_DIRECTION
- you
- lose
- -- must know STACK_DIRECTION at compile-time
- #endif /* STACK_DIRECTION undefined */
- #endif /* static */
- #endif /* emacs */
- #ifdef emacs
- #define free xfree
- #endif
- #ifndef alloca /* If compiling with GCC, this file's not needed. */
- #ifdef __STDC__
- typedef void *pointer; /* generic pointer type */
- #else
- typedef char *pointer; /* generic pointer type */
- #endif
- #define NULL 0 /* null pointer constant */
- extern pointer xmalloc ();
- /*
- Define STACK_DIRECTION if you know the direction of stack
- growth for your system; otherwise it will be automatically
- deduced at run-time.
- STACK_DIRECTION > 0 => grows toward higher addresses
- STACK_DIRECTION < 0 => grows toward lower addresses
- STACK_DIRECTION = 0 => direction of growth unknown
- */
- #ifndef STACK_DIRECTION
- #define STACK_DIRECTION 0 /* direction unknown */
- #endif
- #if STACK_DIRECTION != 0
- #define STACK_DIR STACK_DIRECTION /* known at compile-time */
- #else /* STACK_DIRECTION == 0; need run-time code */
- static int stack_dir; /* 1 or -1 once known */
- #define STACK_DIR stack_dir
- static void
- find_stack_direction (/* void */)
- {
- static char *addr = NULL; /* address of first
- `dummy', once known */
- auto char dummy; /* to get stack address */
- if (addr == NULL)
- { /* initial entry */
- addr = &dummy;
- find_stack_direction (); /* recurse once */
- }
- else /* second entry */
- if (&dummy > addr)
- stack_dir = 1; /* stack grew upward */
- else
- stack_dir = -1; /* stack grew downward */
- }
- #endif /* STACK_DIRECTION == 0 */
- /*
- An "alloca header" is used to:
- (a) chain together all alloca'ed blocks;
- (b) keep track of stack depth.
- It is very important that sizeof (header) agree with malloc
- alignment chunk size. The following default should work okay.
- */
- #ifndef ALIGN_SIZE
- #define ALIGN_SIZE sizeof (double)
- #endif
- typedef union hdr
- {
- char align[ALIGN_SIZE]; /* to force sizeof (header) */
- struct
- {
- union hdr *next; /* for chaining headers */
- char *deep; /* for stack depth measure */
- } h;
- } header;
- /*
- alloca ( size ) returns a pointer to at least `size' bytes of
- storage which will be automatically reclaimed upon exit from
- the procedure that called alloca. Originally, this space
- was supposed to be taken from the current stack frame of the
- caller, but that method cannot be made to work for some
- implementations of C, for example under Gould's UTX/32.
- */
- static header *last_alloca_header = NULL; /* -> last alloca header */
- pointer
- alloca (size) /* returns pointer to storage */
- unsigned size; /* # bytes to allocate */
- {
- auto char probe; /* probes stack depth: */
- register char *depth = &probe;
- #if STACK_DIRECTION == 0
- if (STACK_DIR == 0) /* unknown growth direction */
- find_stack_direction ();
- #endif
- /* Reclaim garbage, defined as all alloca'ed storage that
- was allocated from deeper in the stack than currently. */
- {
- register header *hp; /* traverses linked list */
- for (hp = last_alloca_header; hp != NULL;)
- if ((STACK_DIR > 0 && hp->h.deep > depth)
- || (STACK_DIR < 0 && hp->h.deep < depth))
- {
- register header *np = hp->h.next;
- free ((pointer) hp); /* collect garbage */
- hp = np; /* -> next header */
- }
- else
- break; /* rest are not deeper */
- last_alloca_header = hp; /* -> last valid storage */
- }
- if (size == 0)
- return NULL; /* no allocation required */
- /* Allocate combined header + user data storage. */
- {
- register pointer new = xmalloc (sizeof (header) + size);
- /* address of header */
- ((header *)new)->h.next = last_alloca_header;
- ((header *)new)->h.deep = depth;
- last_alloca_header = (header *)new;
- /* User storage begins just after header. */
- return (pointer)((char *)new + sizeof (header));
- }
- }
- #endif /* no alloca */
|