Google
 

Trailing-Edge - PDP-10 Archives - BB-FB49A-RM - sources/sntmem.b36
There are no other files named sntmem.b36 in the archive.
%title 'SNT Memory Management'

module SNTMEM (ident = 'Version 1.00') =
begin

! Copyright (c) 1984, 1985 by
! DIGITAL EQUIPMENT CORPORATION, Maynard, Massachusetts
!
! This software is furnished under a license and may be used and  copied
! only  in  accordance  with  the  terms  of  such  license and with the
! inclusion of the above copyright notice.  This software or  any  other
! copies  thereof may not be provided or otherwise made available to any
! other person.  No title to and ownership of  the  software  is  hereby
! transferred.
!
! The information in this software is subject to change  without  notice
! and  should  not  be  construed  as  a commitment by Digital Equipment
! Corporation.
!
! Digital assumes no responsibility for the use or  reliability  of  its
! software on equipment which is not supplied by Digital.
!++
! FACILITY:	DECnet/SNA SNA Trace Utility memory manager.
!
! ABSTRACT:	This module provide routines to do utility support, i.e.
!               buffer allocation, enqueue/dequeue.
!
! ENVIRONMENT:	TOPS-20 Operating Systems, user mode.
!
! AUTHOR:	Son VoBa,               CREATION DATE: May 14, 1982.
!               
! MODIFIED BY:
!
! 	D. Brannon, 11-Oct-84 : VERSION 1.00
!
!--

!
! REQUIRED FILES
!

library 'MONSYM';                       ! Monitor symbols
library 'SNTDEF';                       ! SNT common definitions
require 'JSYS';                         ! TOPS-20 JSYS declarations

!
! FORWARD REFERENCES
!

forward routine
    MEM$GET,
    MEM$GET_MULTIPLE_BUFFERS,
    MEM$GET_SINGLE_BUFFER,
    MEM$INITIALIZE: novalue,
    MEM$RELINK: novalue,
    MEM$RETURN: novalue;

!
! EXTERNAL REFERENCES
!


external
    MEMORY: MEMORY_BUFFER_POOL,
    CONTROL: GLOBAL_CONTROL_BLOCK;

external routine
    USP$BUFFER_INITIALIZE: novalue,
    USP$LOCK: novalue,
    USP$UNLOCK: novalue;
%global_routine ('MEM$GET', COUNT) =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Routine to allocate memory buffer to requesting process.
!       If fail to allocate requested memory buffers, notify the
!       control terminal of the fact, wait 5 seconds, try it again.
!
! FORMAL PARAMETERS:
!
!       COUNT           Number of memory buffer units to be allocated
!                       contiguously. If negative or 0, assumed to be 1.
!
! ROUTINE VALUE:
!
!       The address of the buffer if allocated.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    literal
        MAXIMUM_TRIES = 10;

    local
        TRIES,
        BUFFER,
        MCB: ref MEMORY_CONTROL_BLOCK volatile;

    TRIES = MAXIMUM_TRIES;              ! Number of unsuccessful tries

    do begin
       USP$LOCK ($BUFFER_POOL);         ! Lock buffer pool

       MCB = CONTROL[GCB_MEMORY_CONTROL_BLOCK];

       ! Try to relink free buffers if there are indications that
       ! we might have run out. After that, check again, if same
       ! condition exists, we did run out of buffers.

       if .MCB[MCB_FREE_HEAD] geq $MEMORY_BUFFER_UNITS
       then MEM$RELINK ();

       if .MCB[MCB_FREE_HEAD] geq $MEMORY_BUFFER_UNITS
       then BUFFER = 0                  ! None left, return 0
       else begin
            if .COUNT leq 1
            then BUFFER = MEM$GET_SINGLE_BUFFER () ! Get buffer
            else begin                  ! Multiple units allocation
                 MEM$RELINK ();         ! Relink buffer list
                 BUFFER = MEM$GET_MULTIPLE_BUFFERS (.COUNT); ! Get buffers
                 end;
            end;

       USP$UNLOCK ($BUFFER_POOL);       ! Unlock buffer pool

       if .BUFFER neq 0                 ! Got the buffers
       then return .BUFFER;

       TRIES = .TRIES - 1;
       jsys_disms (2000);               ! Wait for 2 seconds
       end
    while (.TRIES gtr 0);

    jsys_psout (CH$ASCIZ ('No buffer'));
    jsys_haltf ();                      ! Dead lock, stop process

    return 0;
    end;                                ! End of MEM$GET
%routine ('MEM$GET_MULTIPLE_BUFFERS', COUNT) =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Routine to allocate sequence of memory buffers.
!
! FORMAL PARAMETERS:
!
!       COUNT           Number of memory buffer units to be allocated
!                       contiguously.
!
! ROUTINE VALUE:
!
!       The address of the first buffer in the sequence if allocated.
!       Otherwise 0.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    local
        FOUND,
        BUFFER,
        MCB: ref MEMORY_CONTROL_BLOCK volatile,
        HEADERS: ref MEMORY_BUFFER_HEADERS,
        HEAD: ref MEMORY_BUFFER_HEADER,
        TAIL: ref MEMORY_BUFFER_HEADER,
        USED: ref MEMORY_BUFFER_HEADER;

    MCB = CONTROL[GCB_MEMORY_CONTROL_BLOCK];
    HEADERS = MCB[MCB_HEADERS];
    HEAD = HEADERS[(.MCB[MCB_FREE_HEAD] * $MEMORY_BUFFER_HEADER_SIZE),0,0,36,0];

    FOUND = $FALSE;                     ! Assume that we cannot allocate

    while not .FOUND
    do begin                            ! Scan free list for buffer sequence
       local HDR: ref MEMORY_BUFFER_HEADER;

       HDR = .HEAD;                     ! Get new buffer header of next chain
       FOUND = $TRUE;                   ! Pretend that we found the sequence

       ! Look ahead in the free link, starting with the buffer
       ! pointed to by HEAD. Upon exit, if successfull, HDR will
       ! point to the last buffer in the chain; otherwise, HEAD
       ! is update pointing to the next possible buffer chain.

       incr I from 1 to (.COUNT-1)
       do begin
          local NEXT;

          if (.HDR[MBH_FORWARD_LINK] lss $MEMORY_BUFFER_UNITS)
          and (.HDR[MBH_IDENTIFIER] eql (.HDR[MBH_FORWARD_LINK] - 1))
          then begin                    ! Next buffer is adjacent
               NEXT = .HDR[MBH_FORWARD_LINK] * $MEMORY_BUFFER_HEADER_SIZE;
               HDR = HEADERS[.NEXT,0,0,36,0];
               end
          else begin                    ! Next buffer is not adjacent
               if .HDR[MBH_FORWARD_LINK] geq $MEMORY_BUFFER_UNITS
               then return 0            ! This is the last in the list
               else begin               ! There are more buffers in the list
                    NEXT = .HDR[MBH_FORWARD_LINK] * $MEMORY_BUFFER_HEADER_SIZE;
                    HEAD = HEADERS[.NEXT,0,0,36,0];
                    end;

               FOUND = $FALSE;          ! Set flag to indicate failure
               exitloop;                ! Terminate current search
               end;
          end;

       if .FOUND
       then TAIL = .HDR;
       end;

    if not .FOUND                       ! If cannot allocate that many
    then return 0;                      ! buffers, return none allocated

    ! At this point, we have identified the allocated buffer sequence.
    ! The sequence is pointed to by HEAD as the starting buffer and
    ! TAIL as the last buffer. Allocate the buffer area and initialize it.

    BUFFER = MEMORY[(.HEAD[MBH_IDENTIFIER] * $MEMORY_BUFFER_SIZE)];
    USP$BUFFER_INITIALIZE (.BUFFER, .COUNT * $MEMORY_BUFFER_SIZE);

    ! If there are already buffers on the allocated link,
    ! Calculate the identifier of the last buffer of the link.
    ! Append new allocated buffers to the allocated linked list.

    if (USED = .MCB[MCB_ALLOCATED_TAIL]) neq -1
    then begin
         USED = HEADERS[(.USED * $MEMORY_BUFFER_HEADER_SIZE),0,0,36,0];
         USED[MBH_FORWARD_LINK] = .HEAD[MBH_IDENTIFIER];
         end;

    ! Update the head of the free link. If the allocate sequence is
    ! at the beginning of the free list, then just do straight update
    ! of the head of the free link; otherwise, snatch the sequence out
    ! of the free list and pluck the hole left behind without changing
    ! the head of the free link.

    if .MCB[MCB_FREE_HEAD] eql .HEAD[MBH_IDENTIFIER]
    then MCB[MCB_FREE_HEAD] = .TAIL[MBH_FORWARD_LINK]
    else begin
         local HD: ref MEMORY_BUFFER_HEADER, TL: ref MEMORY_BUFFER_HEADER;

         if (HD = .HEAD[MBH_BACKWARD_LINK]) neq -1
         then begin
              HD = HEADERS[(.HD * $MEMORY_BUFFER_HEADER_SIZE),0,0,36,0];
              HD[MBH_FORWARD_LINK] = .TAIL[MBH_FORWARD_LINK];
              end;

         if (TL = .TAIL[MBH_FORWARD_LINK]) lss $MEMORY_BUFFER_UNITS
         then begin
              TL = HEADERS[(.TL * $MEMORY_BUFFER_HEADER_SIZE),0,0,36,0];
              TL[MBH_BACKWARD_LINK] = .HEAD[MBH_BACKWARD_LINK];
              end;
         end;

    ! Go through the buffer header chain
    ! set appropriate flags and links

    HEAD[MBH_BACKWARD_LINK] = .MCB[MCB_ALLOCATED_TAIL];
    TAIL[MBH_LOCK] = $TRUE;
    TAIL[MBH_CLUSTER] = $FALSE;
    TAIL[MBH_FORWARD_LINK] = -1;

    USED = .HEAD;
    incr I from 1 to (.COUNT-1)
    do begin
       USED[MBH_LOCK] = $TRUE;
       USED[MBH_CLUSTER] = $TRUE;
       USED = HEADERS[(.USED[MBH_FORWARD_LINK] * $MEMORY_BUFFER_HEADER_SIZE),0,0,36,0];
       end;

    ! Update the tail of the allocated linked list

    MCB[MCB_ALLOCATED_TAIL] = .TAIL[MBH_IDENTIFIER];

    return .BUFFER;                     ! Return buffer address
    end;                                ! End of MEM$GET_MULTIPLE_BUFFERS
%routine ('MEM$GET_SINGLE_BUFFER') =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Routine to allocate single memory buffer.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       The address of the buffer if allocated, otherwise 0.
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    local
        BUFFER,
        HEADERS: ref MEMORY_BUFFER_HEADERS,
        MCB: ref MEMORY_CONTROL_BLOCK volatile,
        HEADER: ref MEMORY_BUFFER_HEADER,
        USED: ref MEMORY_BUFFER_HEADER;

    MCB = CONTROL[GCB_MEMORY_CONTROL_BLOCK];
    HEADERS = MCB[MCB_HEADERS];

    ! Allocate buffer area, then initialize it

    BUFFER = MEMORY[(.MCB[MCB_FREE_HEAD] * $MEMORY_BUFFER_SIZE)];
    USP$BUFFER_INITIALIZE (.BUFFER, $MEMORY_BUFFER_SIZE);

    ! Get the header of the new allocated buffer

    HEADER = HEADERS[(.MCB[MCB_FREE_HEAD] * $MEMORY_BUFFER_HEADER_SIZE),0,0,36,0];

    ! If there are already buffers on the allocated link,
    ! Calculate the indentifier of the last buffer of the link.
    ! Append new allocated buffer to the allocated linked list.

    if (USED = .MCB[MCB_ALLOCATED_TAIL]) neq -1
    then begin
         USED = HEADERS[(.USED * $MEMORY_BUFFER_HEADER_SIZE),0,0,36,0];
         USED[MBH_FORWARD_LINK] = .HEADER[MBH_IDENTIFIER];
         end;

    ! Update the head of the free linked list.

    MCB[MCB_FREE_HEAD] = .HEADER[MBH_FORWARD_LINK];
    HEADERS[.MCB[MCB_FREE_HEAD],MBH_BACKWARD_LINK] = -1;

    ! Set appropriate flags and links of the new
    ! allocated buffer header

    HEADER[MBH_LOCK] = $TRUE;
    HEADER[MBH_CLUSTER] = $FALSE;
    HEADER[MBH_BACKWARD_LINK] = .MCB[MCB_ALLOCATED_TAIL];
    HEADER[MBH_FORWARD_LINK] = -1;

    ! If it is the first allocated buffer, update the head of
    ! the allocated linked list

    if .MCB[MCB_ALLOCATED_HEAD] eql -1
    then MCB[MCB_ALLOCATED_HEAD] = .HEADER[MBH_IDENTIFIER];

    ! Update the tail of the allocated linked list

    MCB[MCB_ALLOCATED_TAIL] = .HEADER[MBH_IDENTIFIER];

    return .BUFFER;
    end;                                ! End of MEM$GET_SINGLE_BUFFER
%global_routine ('MEM$INITIALIZE') : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Initialize memory buffers.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       none
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    local
        HEADERS: ref MEMORY_BUFFER_HEADERS,
        MCB: ref MEMORY_CONTROL_BLOCK volatile;

    ! Initialize buffer pool area

    USP$BUFFER_INITIALIZE (MEMORY, $MEMORY_POOL_SIZE);

    ! Initialize control area

    MCB = CONTROL[GCB_MEMORY_CONTROL_BLOCK];
    MCB[MCB_ALLOCATED_HEAD] = -1;
    MCB[MCB_ALLOCATED_TAIL] = -1;
    MCB[MCB_FREE_HEAD] = 0;
    MCB[MCB_FREE_TAIL] = $MEMORY_BUFFER_UNITS - 1;
    HEADERS = MCB[MCB_HEADERS];

    ! Initialize buffer headers

    USP$BUFFER_INITIALIZE (MCB[MCB_HEADERS], $MEMORY_HEADERS);
    incr I from 0 to ($MEMORY_BUFFER_UNITS-1)
    do begin
       local HEADER: ref MEMORY_BUFFER_HEADER;

       HEADER = HEADERS[(.I * $MEMORY_BUFFER_HEADER_SIZE),0,0,36,0];
       HEADER[MBH_FLAGS] = 0;
       HEADER[MBH_FORWARD_LINK] = .I + 1;
       HEADER[MBH_IDENTIFIER] = .I;
       HEADER[MBH_BACKWARD_LINK] = .I - 1;
       end;

    return;
    end;                                ! End of MEM$INITIALIZE
%global_routine ('MEM$RELINK') : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Relink control linked list of the memory buffers.
!
! FORMAL PARAMETERS:
!
!       none
!
! ROUTINE VALUE:
!
!       none
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    local
        UCOUNT,
        FCOUNT,
        USED: ref MEMORY_BUFFER_HEADER,
        FREE: ref MEMORY_BUFFER_HEADER,
        HEADERS: ref MEMORY_BUFFER_HEADERS,
        MCB: ref MEMORY_CONTROL_BLOCK volatile;

    FREE = USED = FCOUNT = UCOUNT = 0;
    MCB = CONTROL[GCB_MEMORY_CONTROL_BLOCK];
    HEADERS = MCB[MCB_HEADERS];

    incr I from 0 to ($MEMORY_BUFFER_UNITS-1)
    do begin
       local HEADER: ref MEMORY_BUFFER_HEADER;

       HEADER = HEADERS[(.I * $MEMORY_BUFFER_HEADER_SIZE),0,0,36,0];

       if .HEADER[MBH_LOCK]
       then begin                       ! Found allocated buffer
            if .USED eql 0              ! Assign first allocated buffer to list
            then begin
                 USED = .HEADER;
                 USED[MBH_FORWARD_LINK] = -1;
                 USED[MBH_BACKWARD_LINK] = -1;
                 MCB[MCB_ALLOCATED_HEAD] = .I;
                 MCB[MCB_ALLOCATED_TAIL] = .I;
                 UCOUNT = .UCOUNT + 1;
                 end
            else begin                  ! Assign next allocated buffer to list
                 USED[MBH_FORWARD_LINK] = .I;
                 HEADER[MBH_BACKWARD_LINK] = .MCB[MCB_ALLOCATED_TAIL];
                 HEADER[MBH_FORWARD_LINK] = -1;
                 USED = .HEADER;
                 MCB[MCB_ALLOCATED_TAIL] = .I;
                 UCOUNT = .UCOUNT + 1;
                 end;
            end
       else begin                       ! Found free buffer
            if .FREE eql 0
            then begin                  ! Assign first free buffer to list
                 FREE = .HEADER;
                 FREE[MBH_FORWARD_LINK] = $MEMORY_BUFFER_UNITS;
                 FREE[MBH_BACKWARD_LINK] = -1;
                 MCB[MCB_FREE_HEAD] = .I;
                 MCB[MCB_FREE_TAIL] = .I;
                 FCOUNT = .FCOUNT + 1;
                 end
            else begin                  ! Assign next free buffer to list
                 FREE[MBH_FORWARD_LINK] = .I;
                 HEADER[MBH_BACKWARD_LINK] = .MCB[MCB_FREE_TAIL];
                 HEADER[MBH_FORWARD_LINK] = $MEMORY_BUFFER_UNITS;
                 FREE = .HEADER;
                 MCB[MCB_FREE_TAIL] = .I;
                 FCOUNT = .FCOUNT + 1;
                 end;
            end;
       end;

    if (.FCOUNT + .UCOUNT) neq $MEMORY_BUFFER_UNITS
    then begin
         jsys_psout (CH$ASCIZ ('Loose buffers'));
         jsys_haltf ();
         end;

    return;
    end;                                ! End of MEM$RELINK
%global_routine ('MEM$RETURN', ADDRESS) : novalue =

!++
! FUNCTIONAL DESCRIPTION:
!
!       Return the memory buffer to free pool.
!
! FORMAL PARAMETERS:
!
!       ADDRESS         Address of the buffer to be returned.
!
! ROUTINE VALUE:
!
!       none
!
! SIDE EFFECTS:
!
!       none
!
!--

    begin

    local
        IDENTIFIER,
        CHAINED,
        MCB: ref MEMORY_CONTROL_BLOCK volatile,
        PREV: ref MEMORY_BUFFER_HEADER,
        NEXT: ref MEMORY_BUFFER_HEADER,
        FREE: ref MEMORY_BUFFER_HEADER,
        HEADER: ref MEMORY_BUFFER_HEADER,
        HEADERS: ref MEMORY_BUFFER_HEADERS;

    USP$LOCK ($BUFFER_POOL);            ! Lock memory buffer pool

    MCB = CONTROL[GCB_MEMORY_CONTROL_BLOCK];
    HEADERS = MCB[MCB_HEADERS];
    IDENTIFIER = (.ADDRESS - MEMORY) / $MEMORY_BUFFER_SIZE;
    HEADER = HEADERS[(.IDENTIFIER * $MEMORY_BUFFER_HEADER_SIZE),0,0,36,0];
    NEXT = .HEADER;

    do begin
       HEADER = .NEXT;
       CHAINED = .HEADER[MBH_CLUSTER];

       if (PREV = .HEADER[MBH_BACKWARD_LINK]) neq -1
       then begin                       ! Update link of previous buffer
            PREV = HEADERS[(.PREV * $MEMORY_BUFFER_HEADER_SIZE),0,0,36,0];
            PREV[MBH_FORWARD_LINK] = .HEADER[MBH_FORWARD_LINK];
            end;

       if (NEXT = .HEADER[MBH_FORWARD_LINK]) neq -1
       then begin                       ! Update link of next buffer
            NEXT = HEADERS[(.NEXT * $MEMORY_BUFFER_HEADER_SIZE),0,0,36,0];
            NEXT[MBH_BACKWARD_LINK] = .HEADER[MBH_BACKWARD_LINK];
            end;

       HEADER[MBH_FLAGS] = 0;           ! Clear all flags
       FREE = HEADERS[(.MCB[MCB_FREE_TAIL] * $MEMORY_BUFFER_HEADER_SIZE),0,0,36,0];
       FREE[MBH_FORWARD_LINK] = .HEADER[MBH_IDENTIFIER];
       HEADER[MBH_BACKWARD_LINK] = .MCB[MCB_FREE_TAIL];
       HEADER[MBH_FORWARD_LINK] = $MEMORY_BUFFER_UNITS;
       MCB[MCB_FREE_TAIL] = .HEADER[MBH_IDENTIFIER];
       end
    while .CHAINED and (.NEXT neq -1);  ! Release all chained buffers

    if .MCB[MCB_ALLOCATED_TAIL] eql .HEADER[MBH_IDENTIFIER]
    then MCB[MCB_ALLOCATED_TAIL] = (if .PREV neq -1
                                    then .PREV[MBH_IDENTIFIER]
                                    else .PREV);

    USP$UNLOCK ($BUFFER_POOL);          ! Unlock memory buffer pool

    return;
    end;                                ! End of MEM$RETURN
end                                   ! End of TSTMEM module
eludom
! Local Modes:
! Mode:BLISS
! Auto Save Mode:2
! Comment Column:40
! Comment Rounding:+1
! End: