# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. include include # SALLOC.X -- Stack management routines. Stack storage is allocated in # segments. Space for each segment is dynamically allocated on the heap. # Each segment contains a pointer to the previous segment to permit # reclamation of the space (see "Mem.hlp" for additional details). # This is a low level facility, hence any failure to allocate or deallocate # stack storage is fatal. # Segment header structure. The header size parameter SZ_STKHDR is defined # in because it is potentially machine dependent. SZ_STKHDR # must be chosen such that the maximum alignment criteria is maintained. define SH_BASE Memi[$1] # char pointer to base of segment define SH_TOP Memi[$1+1] # char pointer to top of segment + 1 define SH_OLDSEG Memi[$1+2] # struct pointer to header of prev.seg. # SALLOC -- Allocate space on the stack. procedure salloc (output_pointer, nelem, datatype) pointer output_pointer # buffer pointer (output) int nelem # number of elements of storage required int datatype # datatype of the storage elements int nchars, dtype include pointer sp, cur_seg common /salcom/ sp, cur_seg begin dtype = datatype if (dtype < 1 || dtype > MAX_DTYPE) call sys_panic (500, "salloc: bad datatype code") # Align stack pointer for any data type. Compute amount of # storage to be allocated. Always add space for at least one # extra char for the EOS in case a string is stored in the buffer. sp = (sp + SZ_MEMALIGN-1) / SZ_MEMALIGN * SZ_MEMALIGN + 1 if (dtype == TY_CHAR) nchars = nelem + 1 # add space for EOS else nchars = nelem * ty_size[dtype] + 1 # Check for stack overflow, add new segment if out of room. # Since SMARK must be called before SALLOC, cur_seg cannot be # null, but we check anyhow. if (cur_seg == NULL || sp + nchars >= SH_TOP(cur_seg)) call stk_mkseg (cur_seg, sp, nchars) if (dtype == TY_CHAR) output_pointer = sp else output_pointer = (sp-1) / ty_size[dtype] + 1 sp = sp + nchars # bump stack pointer end # SMARK -- Mark the position of the stack pointer, so that stack space # can be freed by a subsequent call to SFREE. This routine also performs # initialization of the stack, since it the very first routine called # during task startup. procedure smark (old_sp) pointer old_sp # value of the stack pointer (output) bool first_time pointer sp, cur_seg common /salcom/ sp, cur_seg data first_time /true/ begin if (first_time) { sp = NULL cur_seg = NULL call stk_mkseg (cur_seg, sp, SZ_STACK) first_time = false } old_sp = sp end # SFREE -- Free space on the stack. Return whole segments until segment # containing the old stack pointer is reached. procedure sfree (old_sp) pointer old_sp # previous value of the stack pointer pointer old_seg pointer sp, cur_seg common /salcom/ sp, cur_seg begin # The following is needed to avoid recursion when SFREE is called # by the IRAF main during processing of SYS_MSSTKUNFL. if (cur_seg == NULL) return # If the stack underflows (probably because of an invalid pointer) # it is a fatal error. while (old_sp < SH_BASE(cur_seg) || old_sp > SH_TOP(cur_seg)) { if (SH_OLDSEG(cur_seg) == NULL) call sys_panic (SYS_MSSTKUNFL, "Salloc underflow") old_seg = SH_OLDSEG(cur_seg) # discard segment call mfree (cur_seg, TY_STRUCT) cur_seg = old_seg } sp = old_sp # pop stack end # STK_MKSEG -- Create and add a new stack segment (link at head of the # segment list). Called during initialization, and upon stack overflow. procedure stk_mkseg (cur_seg, sp, segment_size) pointer cur_seg # current segment pointer sp # salloc stack pointer int segment_size # size of new stack segment int nchars, new_seg pointer coerce() int kmalloc() begin # Compute size of new segment, allocate the buffer. nchars = max (SZ_STACK, segment_size) + SZ_STKHDR if (kmalloc (new_seg, nchars / SZ_STRUCT, TY_STRUCT) == ERR) call sys_panic (SYS_MFULL, "Out of memory") # Output new stack pointer. sp = coerce (new_seg, TY_STRUCT, TY_CHAR) + SZ_STKHDR # Set up the segment descriptor. SH_BASE(new_seg) = sp SH_TOP(new_seg) = sp - SZ_STKHDR + nchars SH_OLDSEG(new_seg) = cur_seg # Make new segment the current segment. cur_seg = new_seg end