Annotation of embedaddon/lrzsz/lib/alloca.c, revision 1.1
1.1 ! misho 1: /* alloca.c -- allocate automatically reclaimed memory
! 2: (Mostly) portable public-domain implementation -- D A Gwyn
! 3:
! 4: This implementation of the PWB library alloca function,
! 5: which is used to allocate space off the run-time stack so
! 6: that it is automatically reclaimed upon procedure exit,
! 7: was inspired by discussions with J. Q. Johnson of Cornell.
! 8: J.Otto Tennant <jot@cray.com> contributed the Cray support.
! 9:
! 10: There are some preprocessor constants that can
! 11: be defined when compiling for your specific system, for
! 12: improved efficiency; however, the defaults should be okay.
! 13:
! 14: The general concept of this implementation is to keep
! 15: track of all alloca-allocated blocks, and reclaim any
! 16: that are found to be deeper in the stack than the current
! 17: invocation. This heuristic does not reclaim storage as
! 18: soon as it becomes invalid, but it will do so eventually.
! 19:
! 20: As a special case, alloca(0) reclaims storage without
! 21: allocating any. It is a good idea to use alloca(0) in
! 22: your main control loop, etc. to force garbage collection. */
! 23:
! 24: #ifdef HAVE_CONFIG_H
! 25: #include "config.h"
! 26: #endif
! 27:
! 28: /* If compiling with GCC, this file's not needed. */
! 29: #ifndef alloca
! 30:
! 31: #ifdef emacs
! 32: #ifdef static
! 33: /* actually, only want this if static is defined as ""
! 34: -- this is for usg, in which emacs must undefine static
! 35: in order to make unexec workable
! 36: */
! 37: #ifndef STACK_DIRECTION
! 38: you
! 39: lose
! 40: -- must know STACK_DIRECTION at compile-time
! 41: #endif /* STACK_DIRECTION undefined */
! 42: #endif /* static */
! 43: #endif /* emacs */
! 44:
! 45: /* If your stack is a linked list of frames, you have to
! 46: provide an "address metric" ADDRESS_FUNCTION macro. */
! 47:
! 48: #if defined (CRAY) && defined (CRAY_STACKSEG_END)
! 49: long i00afunc ();
! 50: #define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
! 51: #else
! 52: #define ADDRESS_FUNCTION(arg) &(arg)
! 53: #endif
! 54:
! 55: #if __STDC__
! 56: typedef void *pointer;
! 57: #else
! 58: typedef char *pointer;
! 59: #endif
! 60:
! 61: #define NULL 0
! 62:
! 63: /* Different portions of Emacs need to call different versions of
! 64: malloc. The Emacs executable needs alloca to call xmalloc, because
! 65: ordinary malloc isn't protected from input signals. On the other
! 66: hand, the utilities in lib-src need alloca to call malloc; some of
! 67: them are very simple, and don't have an xmalloc routine.
! 68:
! 69: Non-Emacs programs expect this to call use xmalloc.
! 70:
! 71: Callers below should use malloc. */
! 72:
! 73: #ifndef emacs
! 74: #if 0
! 75: #define malloc xmalloc
! 76: extern pointer xmalloc ();
! 77: #else
! 78: static void *
! 79: xmalloc(s)
! 80: unsigned long s;
! 81: {
! 82: void *p=(void *)malloc(s);
! 83: if (!p) {
! 84: const char *meld="out of memory in alloca\n";
! 85: write(2,meld,strlen(meld));
! 86: exit(1);
! 87: }
! 88: return p;
! 89: }
! 90: #define malloc xmalloc
! 91: #endif
! 92: #endif
! 93:
! 94: /* Define STACK_DIRECTION if you know the direction of stack
! 95: growth for your system; otherwise it will be automatically
! 96: deduced at run-time.
! 97:
! 98: STACK_DIRECTION > 0 => grows toward higher addresses
! 99: STACK_DIRECTION < 0 => grows toward lower addresses
! 100: STACK_DIRECTION = 0 => direction of growth unknown */
! 101:
! 102: #ifndef STACK_DIRECTION
! 103: #define STACK_DIRECTION 0 /* Direction unknown. */
! 104: #endif
! 105:
! 106: #if STACK_DIRECTION != 0
! 107:
! 108: #define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
! 109:
! 110: #else /* STACK_DIRECTION == 0; need run-time code. */
! 111:
! 112: static int stack_dir; /* 1 or -1 once known. */
! 113: #define STACK_DIR stack_dir
! 114:
! 115: static void
! 116: find_stack_direction ()
! 117: {
! 118: static char *addr = NULL; /* Address of first `dummy', once known. */
! 119: auto char dummy; /* To get stack address. */
! 120:
! 121: if (addr == NULL)
! 122: { /* Initial entry. */
! 123: addr = ADDRESS_FUNCTION (dummy);
! 124:
! 125: find_stack_direction (); /* Recurse once. */
! 126: }
! 127: else
! 128: {
! 129: /* Second entry. */
! 130: if (ADDRESS_FUNCTION (dummy) > addr)
! 131: stack_dir = 1; /* Stack grew upward. */
! 132: else
! 133: stack_dir = -1; /* Stack grew downward. */
! 134: }
! 135: }
! 136:
! 137: #endif /* STACK_DIRECTION == 0 */
! 138:
! 139: /* An "alloca header" is used to:
! 140: (a) chain together all alloca'ed blocks;
! 141: (b) keep track of stack depth.
! 142:
! 143: It is very important that sizeof(header) agree with malloc
! 144: alignment chunk size. The following default should work okay. */
! 145:
! 146: #ifndef ALIGN_SIZE
! 147: #define ALIGN_SIZE sizeof(double)
! 148: #endif
! 149:
! 150: typedef union hdr
! 151: {
! 152: char align[ALIGN_SIZE]; /* To force sizeof(header). */
! 153: struct
! 154: {
! 155: union hdr *next; /* For chaining headers. */
! 156: char *deep; /* For stack depth measure. */
! 157: } h;
! 158: } header;
! 159:
! 160: static header *last_alloca_header = NULL; /* -> last alloca header. */
! 161:
! 162:
! 163: /* Return a pointer to at least SIZE bytes of storage,
! 164: which will be automatically reclaimed upon exit from
! 165: the procedure that called alloca. Originally, this space
! 166: was supposed to be taken from the current stack frame of the
! 167: caller, but that method cannot be made to work for some
! 168: implementations of C, for example under Gould's UTX/32. */
! 169:
! 170: pointer
! 171: alloca (size)
! 172: unsigned size;
! 173: {
! 174: auto char probe; /* Probes stack depth: */
! 175: register char *depth = ADDRESS_FUNCTION (probe);
! 176:
! 177: #if STACK_DIRECTION == 0
! 178: if (STACK_DIR == 0) /* Unknown growth direction. */
! 179: find_stack_direction ();
! 180: #endif
! 181:
! 182: /* Reclaim garbage, defined as all alloca'd storage that
! 183: was allocated from deeper in the stack than currently. */
! 184:
! 185: {
! 186: register header *hp; /* Traverses linked list. */
! 187:
! 188: for (hp = last_alloca_header; hp != NULL;)
! 189: if ((STACK_DIR > 0 && hp->h.deep > depth)
! 190: || (STACK_DIR < 0 && hp->h.deep < depth))
! 191: {
! 192: register header *np = hp->h.next;
! 193:
! 194: free ((pointer) hp); /* Collect garbage. */
! 195:
! 196: hp = np; /* -> next header. */
! 197: }
! 198: else
! 199: break; /* Rest are not deeper. */
! 200:
! 201: last_alloca_header = hp; /* -> last valid storage. */
! 202: }
! 203:
! 204: if (size == 0)
! 205: return NULL; /* No allocation required. */
! 206:
! 207: /* Allocate combined header + user data storage. */
! 208:
! 209: {
! 210: register pointer new = malloc (sizeof (header) + size);
! 211: /* Address of header. */
! 212:
! 213: ((header *) new)->h.next = last_alloca_header;
! 214: ((header *) new)->h.deep = depth;
! 215:
! 216: last_alloca_header = (header *) new;
! 217:
! 218: /* User storage begins just after header. */
! 219:
! 220: return (pointer) ((char *) new + sizeof (header));
! 221: }
! 222: }
! 223:
! 224: /* brute force hack around glibc-2.0.4 together with lcc
! 225: (need -D_BSD_SOURCE for u_long, but then get "alloca.h",
! 226: which #defines alloca to be __alloca). -- uwe
! 227: */
! 228: pointer __alloca (size) unsigned size;
! 229: { return alloca(size); }
! 230:
! 231: #if defined (CRAY) && defined (CRAY_STACKSEG_END)
! 232:
! 233: #ifdef DEBUG_I00AFUNC
! 234: #include <stdio.h>
! 235: #endif
! 236:
! 237: #ifndef CRAY_STACK
! 238: #define CRAY_STACK
! 239: #ifndef CRAY2
! 240: /* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
! 241: struct stack_control_header
! 242: {
! 243: long shgrow:32; /* Number of times stack has grown. */
! 244: long shaseg:32; /* Size of increments to stack. */
! 245: long shhwm:32; /* High water mark of stack. */
! 246: long shsize:32; /* Current size of stack (all segments). */
! 247: };
! 248:
! 249: /* The stack segment linkage control information occurs at
! 250: the high-address end of a stack segment. (The stack
! 251: grows from low addresses to high addresses.) The initial
! 252: part of the stack segment linkage control information is
! 253: 0200 (octal) words. This provides for register storage
! 254: for the routine which overflows the stack. */
! 255:
! 256: struct stack_segment_linkage
! 257: {
! 258: long ss[0200]; /* 0200 overflow words. */
! 259: long sssize:32; /* Number of words in this segment. */
! 260: long ssbase:32; /* Offset to stack base. */
! 261: long:32;
! 262: long sspseg:32; /* Offset to linkage control of previous
! 263: segment of stack. */
! 264: long:32;
! 265: long sstcpt:32; /* Pointer to task common address block. */
! 266: long sscsnm; /* Private control structure number for
! 267: microtasking. */
! 268: long ssusr1; /* Reserved for user. */
! 269: long ssusr2; /* Reserved for user. */
! 270: long sstpid; /* Process ID for pid based multi-tasking. */
! 271: long ssgvup; /* Pointer to multitasking thread giveup. */
! 272: long sscray[7]; /* Reserved for Cray Research. */
! 273: long ssa0;
! 274: long ssa1;
! 275: long ssa2;
! 276: long ssa3;
! 277: long ssa4;
! 278: long ssa5;
! 279: long ssa6;
! 280: long ssa7;
! 281: long sss0;
! 282: long sss1;
! 283: long sss2;
! 284: long sss3;
! 285: long sss4;
! 286: long sss5;
! 287: long sss6;
! 288: long sss7;
! 289: };
! 290:
! 291: #else /* CRAY2 */
! 292: /* The following structure defines the vector of words
! 293: returned by the STKSTAT library routine. */
! 294: struct stk_stat
! 295: {
! 296: long now; /* Current total stack size. */
! 297: long maxc; /* Amount of contiguous space which would
! 298: be required to satisfy the maximum
! 299: stack demand to date. */
! 300: long high_water; /* Stack high-water mark. */
! 301: long overflows; /* Number of stack overflow ($STKOFEN) calls. */
! 302: long hits; /* Number of internal buffer hits. */
! 303: long extends; /* Number of block extensions. */
! 304: long stko_mallocs; /* Block allocations by $STKOFEN. */
! 305: long underflows; /* Number of stack underflow calls ($STKRETN). */
! 306: long stko_free; /* Number of deallocations by $STKRETN. */
! 307: long stkm_free; /* Number of deallocations by $STKMRET. */
! 308: long segments; /* Current number of stack segments. */
! 309: long maxs; /* Maximum number of stack segments so far. */
! 310: long pad_size; /* Stack pad size. */
! 311: long current_address; /* Current stack segment address. */
! 312: long current_size; /* Current stack segment size. This
! 313: number is actually corrupted by STKSTAT to
! 314: include the fifteen word trailer area. */
! 315: long initial_address; /* Address of initial segment. */
! 316: long initial_size; /* Size of initial segment. */
! 317: };
! 318:
! 319: /* The following structure describes the data structure which trails
! 320: any stack segment. I think that the description in 'asdef' is
! 321: out of date. I only describe the parts that I am sure about. */
! 322:
! 323: struct stk_trailer
! 324: {
! 325: long this_address; /* Address of this block. */
! 326: long this_size; /* Size of this block (does not include
! 327: this trailer). */
! 328: long unknown2;
! 329: long unknown3;
! 330: long link; /* Address of trailer block of previous
! 331: segment. */
! 332: long unknown5;
! 333: long unknown6;
! 334: long unknown7;
! 335: long unknown8;
! 336: long unknown9;
! 337: long unknown10;
! 338: long unknown11;
! 339: long unknown12;
! 340: long unknown13;
! 341: long unknown14;
! 342: };
! 343:
! 344: #endif /* CRAY2 */
! 345: #endif /* not CRAY_STACK */
! 346:
! 347: #ifdef CRAY2
! 348: /* Determine a "stack measure" for an arbitrary ADDRESS.
! 349: I doubt that "lint" will like this much. */
! 350:
! 351: static long
! 352: i00afunc (long *address)
! 353: {
! 354: struct stk_stat status;
! 355: struct stk_trailer *trailer;
! 356: long *block, size;
! 357: long result = 0;
! 358:
! 359: /* We want to iterate through all of the segments. The first
! 360: step is to get the stack status structure. We could do this
! 361: more quickly and more directly, perhaps, by referencing the
! 362: $LM00 common block, but I know that this works. */
! 363:
! 364: STKSTAT (&status);
! 365:
! 366: /* Set up the iteration. */
! 367:
! 368: trailer = (struct stk_trailer *) (status.current_address
! 369: + status.current_size
! 370: - 15);
! 371:
! 372: /* There must be at least one stack segment. Therefore it is
! 373: a fatal error if "trailer" is null. */
! 374:
! 375: if (trailer == 0)
! 376: abort ();
! 377:
! 378: /* Discard segments that do not contain our argument address. */
! 379:
! 380: while (trailer != 0)
! 381: {
! 382: block = (long *) trailer->this_address;
! 383: size = trailer->this_size;
! 384: if (block == 0 || size == 0)
! 385: abort ();
! 386: trailer = (struct stk_trailer *) trailer->link;
! 387: if ((block <= address) && (address < (block + size)))
! 388: break;
! 389: }
! 390:
! 391: /* Set the result to the offset in this segment and add the sizes
! 392: of all predecessor segments. */
! 393:
! 394: result = address - block;
! 395:
! 396: if (trailer == 0)
! 397: {
! 398: return result;
! 399: }
! 400:
! 401: do
! 402: {
! 403: if (trailer->this_size <= 0)
! 404: abort ();
! 405: result += trailer->this_size;
! 406: trailer = (struct stk_trailer *) trailer->link;
! 407: }
! 408: while (trailer != 0);
! 409:
! 410: /* We are done. Note that if you present a bogus address (one
! 411: not in any segment), you will get a different number back, formed
! 412: from subtracting the address of the first block. This is probably
! 413: not what you want. */
! 414:
! 415: return (result);
! 416: }
! 417:
! 418: #else /* not CRAY2 */
! 419: /* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
! 420: Determine the number of the cell within the stack,
! 421: given the address of the cell. The purpose of this
! 422: routine is to linearize, in some sense, stack addresses
! 423: for alloca. */
! 424:
! 425: static long
! 426: i00afunc (long address)
! 427: {
! 428: long stkl = 0;
! 429:
! 430: long size, pseg, this_segment, stack;
! 431: long result = 0;
! 432:
! 433: struct stack_segment_linkage *ssptr;
! 434:
! 435: /* Register B67 contains the address of the end of the
! 436: current stack segment. If you (as a subprogram) store
! 437: your registers on the stack and find that you are past
! 438: the contents of B67, you have overflowed the segment.
! 439:
! 440: B67 also points to the stack segment linkage control
! 441: area, which is what we are really interested in. */
! 442:
! 443: stkl = CRAY_STACKSEG_END ();
! 444: ssptr = (struct stack_segment_linkage *) stkl;
! 445:
! 446: /* If one subtracts 'size' from the end of the segment,
! 447: one has the address of the first word of the segment.
! 448:
! 449: If this is not the first segment, 'pseg' will be
! 450: nonzero. */
! 451:
! 452: pseg = ssptr->sspseg;
! 453: size = ssptr->sssize;
! 454:
! 455: this_segment = stkl - size;
! 456:
! 457: /* It is possible that calling this routine itself caused
! 458: a stack overflow. Discard stack segments which do not
! 459: contain the target address. */
! 460:
! 461: while (!(this_segment <= address && address <= stkl))
! 462: {
! 463: #ifdef DEBUG_I00AFUNC
! 464: fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
! 465: #endif
! 466: if (pseg == 0)
! 467: break;
! 468: stkl = stkl - pseg;
! 469: ssptr = (struct stack_segment_linkage *) stkl;
! 470: size = ssptr->sssize;
! 471: pseg = ssptr->sspseg;
! 472: this_segment = stkl - size;
! 473: }
! 474:
! 475: result = address - this_segment;
! 476:
! 477: /* If you subtract pseg from the current end of the stack,
! 478: you get the address of the previous stack segment's end.
! 479: This seems a little convoluted to me, but I'll bet you save
! 480: a cycle somewhere. */
! 481:
! 482: while (pseg != 0)
! 483: {
! 484: #ifdef DEBUG_I00AFUNC
! 485: fprintf (stderr, "%011o %011o\n", pseg, size);
! 486: #endif
! 487: stkl = stkl - pseg;
! 488: ssptr = (struct stack_segment_linkage *) stkl;
! 489: size = ssptr->sssize;
! 490: pseg = ssptr->sspseg;
! 491: result += size;
! 492: }
! 493: return (result);
! 494: }
! 495:
! 496: #endif /* not CRAY2 */
! 497: #endif /* CRAY */
! 498:
! 499: #endif /* no alloca */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>