Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# missing/alloca.c

Go to the documentation of this file.

    00001 /* alloca -- (mostly) portable public-domain implementation -- D A Gwyn
    00002
    00003    last edit:   86/05/30        rms
    00004    include config.h, since on VMS it renames some symbols.
    00005    Use xmalloc instead of malloc.
    00006
    00007    This implementation of the PWB library alloca() function,
    00008    which is used to allocate space off the run-time stack so
    00009    that it is automatically reclaimed upon procedure exit,
    00010    was inspired by discussions with J. Q. Johnson of Cornell.
    00011
    00012    It should work under any C implementation that uses an
    00013    actual procedure stack (as opposed to a linked list of
    00014    frames).  There are some preprocessor constants that can
    00015    be defined when compiling for your specific system, for
    00016    improved efficiency; however, the defaults should be okay.
    00017
    00018    The general concept of this implementation is to keep
    00019    track of all alloca()-allocated blocks, and reclaim any
    00020    that are found to be deeper in the stack than the current
    00021    invocation.  This heuristic does not reclaim storage as
    00022    soon as it becomes invalid, but it will do so eventually.
    00023
    00024    As a special case, alloca(0) reclaims storage without
    00025    allocating any.  It is a good idea to use alloca(0) in
    00026    your main control loop, etc. to force garbage collection.
    00027 */
    00028 #ifndef lint
    00029 static char     SCCSid[] = "@(#)alloca.c        1.1";   /* for the "what" utility */
    00030 #endif
    00031
    00032 #include "ruby/config.h"
    00033 #ifdef C_ALLOCA
    00034
    00035 #ifdef emacs
    00036 #ifdef static
    00037 /* actually, only want this if static is defined as ""
    00038    -- this is for usg, in which emacs must undefine static
    00039    in order to make unexec workable
    00040    */
    00041 #ifndef STACK_DIRECTION
    00042 you
    00043 lose
    00044 -- must know STACK_DIRECTION at compile-time
    00045 #endif /* STACK_DIRECTION undefined */
    00046 #endif /* static */
    00047 #endif /* emacs */
    00048
    00049 #ifdef X3J11
    00050 typedef void    *pointer;               /* generic pointer type */
    00051 #else
    00052 typedef char    *pointer;               /* generic pointer type */
    00053 #endif /* X3J11 */
    00054
    00055 #define NULL    0                       /* null pointer constant */
    00056
    00057 #ifdef RUBY_LIB_PREFIX
    00058 #define xmalloc ruby_xmalloc
    00059 #define xfree ruby_xfree
    00060 #endif
    00061
    00062 extern void     xfree();
    00063 extern pointer  xmalloc();
    00064
    00065 /*
    00066         Define STACK_DIRECTION if you know the direction of stack
    00067         growth for your system; otherwise it will be automatically
    00068         deduced at run-time.
    00069
    00070         STACK_DIRECTION > 0 => grows toward higher addresses
    00071         STACK_DIRECTION < 0 => grows toward lower addresses
    00072         STACK_DIRECTION = 0 => direction of growth unknown
    00073 */
    00074
    00075 #ifndef STACK_DIRECTION
    00076 #define STACK_DIRECTION 0               /* direction unknown */
    00077 #endif
    00078
    00079 #if STACK_DIRECTION != 0
    00080
    00081 #define STACK_DIR       STACK_DIRECTION /* known at compile-time */
    00082
    00083 #else   /* STACK_DIRECTION == 0; need run-time code */
    00084
    00085 static int      stack_dir;              /* 1 or -1 once known */
    00086 #define STACK_DIR       stack_dir
    00087
    00088 static void
    00089 find_stack_direction (/* void */)
    00090 {
    00091   static char   *addr = NULL;   /* address of first
    00092                                    `dummy', once known */
    00093   auto char     dummy;          /* to get stack address */
    00094
    00095   if (addr == NULL)
    00096     {                           /* initial entry */
    00097       addr = &dummy;
    00098
    00099       find_stack_direction ();  /* recurse once */
    00100     }
    00101   else                          /* second entry */
    00102     if (&dummy > addr)
    00103       stack_dir = 1;            /* stack grew upward */
    00104     else
    00105       stack_dir = -1;           /* stack grew downward */
    00106 }
    00107
    00108 #endif  /* STACK_DIRECTION == 0 */
    00109
    00110 /*
    00111         An "alloca header" is used to:
    00112         (a) chain together all alloca()ed blocks;
    00113         (b) keep track of stack depth.
    00114
    00115         It is very important that sizeof(header) agree with malloc()
    00116         alignment chunk size.  The following default should work okay.
    00117 */
    00118
    00119 #ifndef ALIGN_SIZE
    00120 #define ALIGN_SIZE      sizeof(double)
    00121 #endif
    00122
    00123 typedef union hdr
    00124 {
    00125   char  align[ALIGN_SIZE];      /* to force sizeof(header) */
    00126   struct
    00127     {
    00128       union hdr *next;          /* for chaining headers */
    00129       char *deep;               /* for stack depth measure */
    00130     } h;
    00131 } header;
    00132
    00133 /*
    00134         alloca( size ) returns a pointer to at least `size' bytes of
    00135         storage which will be automatically reclaimed upon exit from
    00136         the procedure that called alloca().  Originally, this space
    00137         was supposed to be taken from the current stack frame of the
    00138         caller, but that method cannot be made to work for some
    00139         implementations of C, for example under Gould's UTX/32.
    00140 */
    00141
    00142 static header *last_alloca_header = NULL; /* -> last alloca header */
    00143
    00144 pointer
    00145 alloca (size)                   /* returns pointer to storage */
    00146      unsigned   size;           /* # bytes to allocate */
    00147 {
    00148   auto char     probe;          /* probes stack depth: */
    00149   register char *depth = &probe;
    00150
    00151 #if STACK_DIRECTION == 0
    00152   if (STACK_DIR == 0)           /* unknown growth direction */
    00153     find_stack_direction ();
    00154 #endif
    00155
    00156   /* Reclaim garbage, defined as all alloca()ed storage that
    00157      was allocated from deeper in the stack than currently. */
    00158   {
    00159     register header     *hp;    /* traverses linked list */
    00160
    00161     for (hp = last_alloca_header; hp != NULL;)
    00162       if (STACK_DIR > 0 && hp->h.deep > depth
    00163           || STACK_DIR < 0 && hp->h.deep < depth)
    00164         {
    00165           register header       *np = hp->h.next;
    00166
    00167           xfree ((pointer) hp); /* collect garbage */
    00168
    00169           hp = np;              /* -> next header */
    00170         }
    00171       else
    00172         break;                  /* rest are not deeper */
    00173
    00174     last_alloca_header = hp;    /* -> last valid storage */
    00175   }
    00176
    00177   if (size == 0)
    00178     return NULL;                /* no allocation required */
    00179
    00180   /* Allocate combined header + user data storage. */
    00181
    00182   {
    00183     register pointer    new = xmalloc (sizeof (header) + size);
    00184     /* address of header */
    00185
    00186     ((header *)new)->h.next = last_alloca_header;
    00187     ((header *)new)->h.deep = depth;
    00188
    00189     last_alloca_header = (header *)new;
    00190
    00191     /* User storage begins just after header. */
    00192
    00193     return (pointer)((char *)new + sizeof(header));
    00194   }
    00195 }
    00196
    00197 #endif
    00198