Trailing-Edge
-
PDP-10 Archives
-
bb-bt99s-bb
-
10,7/decmai/mx/mxnt10.r36
There are 10 other files named mxnt10.r36 in the archive. Click here to see a list.
! COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1985, 1989.
! ALL RIGHTS RESERVED.
!
! 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 THAT IS NOT SUPPLIED BY DIGITAL.
!++
! Facility: LSG DECnet Network Management
!
! Abstract: This file contains definitions that are specific to
! TOPS10.
!
! Environment: TOPS10
!
! Author: Stu Grossman, Creation date: June 1981
!
!--
!<BLF/PAGE>
!
! Other requirements for TOPS10
!
switches list (norequire); ! Suppress monitor symbol listing
require 'BLI:TENDEF'; ! Generic definitions
require 'BLI:UUOSYM'; ! Monitor symbols
undeclare %quote
DEBRK$; ! Fix definition of DEBRK. UUO
macro
DEBRK$ =
%O'047', 0, %O'000137' %; ! ...
!
! Un-Definitions for Tops-10 to prevent symbol conflicts
!
undeclare %quote
LOCK,
%quote INPUT,
%quote OUTPUT;
!
! Definitions for -36 instructions
!
literal
HRRI = %O'541', ! Half right to right immediate
HRLI = %O'505', ! Half right to left immediate
EXCH = %O'250', ! Exch register and memory
SETOM = %O'476', ! Set memory to all ones
SETZM = %O'402', ! Set memory to all zeros
AOSE = %O'352', ! Add one to memory, skip if eql 0
AOSN = %O'356', ! Add one and skip if non-zero
SOSGE = %O'375', ! Subtract one and skip if leq 0
PUSH = %O'261', ! Push value onto stack
POP = %O'262', ! Pop value from stack
PUSHJ = %O'260', ! Call routine, save return on stack
JSR = %O'264', ! Jump to subroutine. Uses no ACs
JRST = %O'254', ! Jump to addr
ADJSP = %O'105', ! Adjust stack pointer
MOVE = %O'200', ! Load value into AC
MOVEM = %O'202', ! Store value into memory
MOVEI = %O'201', ! Load effective address into register
BLT = %O'251'; ! Transfer memory block
!
literal
MEMSIZE = %O'121', ! Location containing first free word
! in memory.
CONTEXT_SIZE = %O'20'; ! Number of fullwords in a task's
! context (all the registers).
!
field
STACK_POINTER_FIELDS =
set
STACK_SIZE = [0, 18, 18, 1], ! Number of words left in stack
STACK_ADDRESS = [0, 0, 18, 0] ! Address of current word in stack
tes;
!<BLF/PAGE>
!
! Semaphore LOCK/UNLOCK macros
!
! macro: LOCK
! This macro attempts a semaphore lock. If the lock
! attempt is successful, a "true" value is returned.
!
! LOCK (SEMAPHORE)
!
! where SEMAPHORE is the address of a SEMAPHORE_BLOCK.
undeclare %quote
LOCK; ! Force override of definition of LOCK uuo
macro
LOCK (SEMA_ADDR) =
begin
builtin MACHSKIP;
bind SEMBLK = SEMA_ADDR : SEMAPHORE_BLOCK;
MACHSKIP (AOSE, 0, SEMBLK [SEMAPHORE])
end %;
!
! macro: UNLOCK
!
! This macro unlocks a semaphore that has been locked
! with a LOCK macro call.
!
! UNLOCK (SEMAPHORE)
!
! where SEMAPHORE is the address of a SEMAPHORE_BLOCK.
macro
UNLOCK (SEMA_ADDR) =
begin
builtin MACHOP;
bind SEMBLK = SEMA_ADDR : SEMAPHORE_BLOCK;
MACHOP (SETOM, 0, SEMBLK [SEMAPHORE]);
end %;
!<BLF/PAGE>
!
! Task scheduling macros
!
! macro: CONTEXT_SWITCH
!
! This macro swaps the current task with the
! specified future task.
!
! CONTEXT_SWITCH (NEW_TASK)
!
! where NEW_TASK is the address of the new task's task block.
macro
CONTEXT_SWITCH (NEW_TASK) =
begin
external routine SS_SWITCH; ! System specific routine
SS_SWITCH (NEW_TASK);
end %;
!
! macro: CURRENT_TASK
!
! This macro returns the address of the
! current task's task block.
macro
CURRENT_TASK =
begin
external CURTSK; ! Cell containing current task
.CURTSK
end %;
!
! macro: TASK_INITIALIZE
!
! This macro initializes a task's task block.
! Specifically it sets up the stack and the
! starting address so that the task will swap
! context properly the first time that it
! is scheduled.
!
! TASK_INITIALIZE (TASK_BLOCK, STACK_SIZE)
!
! where TK_BLOCK is the task's task block address
! STACK_SIZE is the number of fullwords its stack.
macro
TASK_INITIALIZE (TK_BLOCK, STACK_SIZE) =
begin
external routine SS_TINIT; ! System specific routine
SS_TINIT (TK_BLOCK, STACK_SIZE);
end %;
!
! macro: STOP_PROGRAM
!
! Make NML die gracefully by calling code at RENTER in
! NMUT10.MAC.
!
macro
STOP_PROGRAM =
begin
external routine
NMLDIE;
NMLDIE ();
end %;
!<BLF/PAGE>
!
! macro: INTERRUPT_DATA_BASE
!
! This macro defines the interrupt vector tables
! and any other miscellaneous variables that are
! required by the interrupt system.
macro
INTERRUPT_DATA_BASE =
compiletime
EXTRA=0;
%debug (ALWAYS, %assign(EXTRA,100)); ! Extra stack needed for debuggery
macro
INTERRUPT_LEVEL_FLAG = ATINTL %quote %;!Define pseudoname for global symbol
literal
INTERRUPT_STACK_SIZE = 100 + EXTRA; ! Number of words in a interrupt stack
global
VECTAB : vector [10], ! Routine to call for each channel
DATTAB : vector [10], ! Data to pass to interrupt routine
APRTAB : vector [2], ! Routine to call for APR traps
INTERRUPT_LEVEL_FLAG : initial (0);! Says we are at interrupt level
!+
! The following table is used by the interrupt routine for network I/O.
! It associates the channel number (as supplied by the interrupt vector block)
! with the appropriate LINK_INFO block. In this way, the correct routine gets
! waken up by the interrupt level.
!-
global
NETLNK : vector [10] initial (rep 10 of (0)); !Support up to 10 links
!
! Stack and pointer for interrupt level 1
!
own
STACK1 : vector [INTERRUPT_STACK_SIZE],
LEV1STK : block [1] field (STACK_POINTER_FIELDS)
preset ([STACK_SIZE] = -INTERRUPT_STACK_SIZE,
[STACK_ADDRESS] = STACK1-1);
!
! Stack and pointer for interrupt level 2
!
own
STACK2 : vector [INTERRUPT_STACK_SIZE],
LEV2STK : block [1] field (STACK_POINTER_FIELDS)
preset ([STACK_SIZE] = -INTERRUPT_STACK_SIZE,
[STACK_ADDRESS] = STACK2);
!
!
! Stack and pointer for interrupt level 3
!
!own
! STACK3 : vector [INTERRUPT_STACK_SIZE],
! LEV3STK : block [1] field (STACK_POINTER_FIELDS)
! preset ([STACK_SIZE] = -INTERRUPT_STACK_SIZE,
! [STACK_ADDRESS] = STACK3);
!
!
! Define channels on each interrupt level.
!
macro
LEVEL1_INTERRUPT_SET =
0, 1, 2, 3, 4, 5, 6, 7, 8, 9 %quote %;
macro
LEVEL2_INTERRUPT_SET =
0, 1 %quote %;
!
! Vector routines for each interrupt channel.
!
macro
$$INT_FORWARDS [CHNNO] =
%name ('CSRV', CHNNO) : novalue %quote %;
macro
$$INT_APR_FORWARDS [CHNNO] =
%name ('APRTP', CHNNO) : novalue %quote %;
macro
LEVEL1_VECTOR_ROUTINES [] =
forward routine
$$INT_FORWARDS (%remaining);
$$LEV1_ROUTINE (%remaining);
%quote %;
macro
$$LEV1_ROUTINE [CHNNO] =
routine %name ('CSRV', CHNNO) : novalue =
begin
literal P = %O'17';
external PIVEC : blockvector [8,4] field(PI_VECTOR_FIELDS);
external CRSACS;
builtin MACHOP, UUO;
%debug(ALWAYS, (MACHOP (SETOM, 0, INTERRUPT_LEVEL_FLAG);))
MACHOP (EXCH, P, LEV1STK);
MACHOP (PUSH, P, 1);
MACHOP (MOVEI, 1, PIVEC [CHNNO, PI_VEC_OLDPC]);
MACHOP (PUSH, P, 1);
MACHOP (PUSH, P, DATTAB + CHNNO);
MACHOP (PUSHJ, P, .(VECTAB + CHNNO), 0, 0);
MACHOP (ADJSP, P, -2);
MACHOP (POP, P, 1);
MACHOP (EXCH, P, LEV1STK);
%debug(ALWAYS, (MACHOP (SETZM, 0, INTERRUPT_LEVEL_FLAG);))
UUO (1, DEBRK$);
! This should never return, but if you screwed up it would
end %quote %;
macro
LEV1INT [CHNNO] =
[CHNNO, PI_VEC_NEWPC] = %name ('CSRV', CHNNO),
[CHNNO, PI_VEC_FLAGS] = PS$VTO %quote %;
macro
LEVEL2_VECTOR_ROUTINES [] =
forward routine
$$INT_APR_FORWARDS (%remaining);
$$LEV2_ROUTINE (%remaining);
%quote %;
macro
$$LEV2_ROUTINE [CHNNO] =
routine %name ('APRTP', CHNNO) : novalue =
begin
literal P = %O'17';
external APRVEC : blockvector [2,2] field (APR_VECTOR_FIELDS);
builtin MACHOP, UUO;
MACHOP (EXCH, P, LEV2STK);
MACHOP (PUSH, P, 1);
MACHOP (MOVEI, 1, APRVEC [CHNNO, APR_VEC_OLDPC]);
MACHOP (PUSH, P, 1);
MACHOP (PUSH, P, DATTAB + CHNNO);
MACHOP (PUSHJ, P, .(APRTAB + CHNNO), 0, 0);
MACHOP (ADJSP, P, -2);
MACHOP (POP, P, 1);
MACHOP (EXCH, P, LEV2STK);
MACHOP (JRST, 2, APRVEC [CHNNO, APR_VEC_OLDPC], 0, 1);
end %quote %;
macro
LEV2INT [CHNNO] =
[CHNNO, APR_VEC_NEWPC] = JRST ^ 27 + %name ('APRTP', CHNNO) %quote %;
field
PI_VECTOR_FIELDS =
set
PI_VEC_NEWPC = [$PSVNP, 0, 36, 0], ! Interrupt vector
PI_VEC_OLDPC = [$PSVOP, 0, 36, 0], ! Address for DEBRK
PI_VEC_FLAGS = [$PSVFL, 0, 36, 0], ! Flags
PI_VEC_STATUS = [$PSVIS, 0, 36, 0] ! Status of this interrupt
tes;
field
APR_VECTOR_FIELDS =
set
APR_VEC_OLDPC = [0, 0, 36, 0], ! (E) of a JSR
APR_VEC_NEWPC = [1, 0, 36, 0] ! JRST to hi-seg routine
tes;
LEVEL1_VECTOR_ROUTINES (LEVEL1_INTERRUPT_SET);
LEVEL2_VECTOR_ROUTINES (LEVEL2_INTERRUPT_SET);
!
! Interrupt channel table
!
global
PIVEC : blockvector [10, 4] field (PI_VECTOR_FIELDS)
preset (LEV1INT (LEVEL1_INTERRUPT_SET)),
APRVEC : blockvector [2, 2] field (APR_VECTOR_FIELDS)
preset (LEV2INT (LEVEL2_INTERRUPT_SET));
%;
!<BLF/PAGE>
!
! Interrupt system operation macros
!
! macro: CLEAR_INTERRUPT_SYSTEM
!
! This macro clears the interrupt system. All interrupts
! disabled.
!
macro
CLEAR_INTERRUPT_SYSTEM =
begin
register T1;
builtin UUO;
T1 = PS$FOF + PS$FCP;
UUO (1, PISYS$(T1));
end %;
!
! macro: INITIALIZE_INTERRUPT_SYSTEM
!
! This macro setups any initial values needed in
! the interrupt data base and informs the operating
! system about the interrupt vector tables.
!
macro
INITIALIZE_INTERRUPT_SYSTEM =
begin
builtin UUO;
register T1;
external PIVEC : blockvector [6,4];
external INTNST;
T1 = PIVEC;
UUO (1, PIINI$(T1));
INTNST = -1;
end %;
!
! New form INTERRUPT handling
!
macro
TIMER_INTERRUPT_ROUTINE =
: TIMER_INTERRUPT_LINKAGE %,
NETWORK_INTERRUPT_ROUTINE =
(CHANNEL_STATUS) : NETWORK_INTERRUPT_LINKAGE %,
NI_RECEIVER_INTERRUPT_ROUTINE =
: NI_RECEIVER_INTERRUPT_LINKAGE %,
IPCF_INTERRUPT_ROUTINE =
: IPCF_INTERRUPT_LINKAGE %;
macro
INTERRUPT_LINKAGE =
pushj :
linkage_regs (15,13,1)
preserve (0,2,3,4,5,6,7,8,9,10,11,12,14)
%;
linkage
VANILLA_INTERRUPT_LINKAGE = INTERRUPT_LINKAGE,
TIMER_INTERRUPT_LINKAGE = INTERRUPT_LINKAGE,
NETWORK_INTERRUPT_LINKAGE = INTERRUPT_LINKAGE,
NI_RECEIVER_INTERRUPT_LINKAGE = INTERRUPT_LINKAGE,
IPCF_INTERRUPT_LINKAGE = INTERRUPT_LINKAGE;
macro
INTERRUPT_ROUTINE [] =
(
%remaining
) : VANILLA_INTERRUPT_LINKAGE
%warn('Best to Use ???_INTERRUPT_ROUTINE') %;
!
! Macro - ALLOCATE_NETLNK
!
! Function - This macro searches NETLNK for a 0 entry and installs the
! channel number and the LINK_INFO block address into that slot.
!
! Parameters -
!
! CHAN The NSP. channel to be used
! INFBLK The address of the LINK_INFO block
!
!-
macro
ALLOCATE_NETLNK (CHAN, INFBLK) =
begin
external NETLNK : vector [10];
%debug (always,
begin
if (CHAN) gtr 9 or .NETLNK [CHAN] neq 0 then
TASK_ERROR ('Bad channel number in ALLOCATE_NETLNK');
end;)
NETLNK [CHAN] = INFBLK;
end
%;
macro
SEARCH_NETLNK (CHAN) =
begin
external NETLNK : vector [10];
%debug (always,
begin
if (CHAN) gtr 9 then
TASK_ERROR ('Channel out of range in DEALLOCATE_NETLNK');
end;)
.NETLNK [CHAN]
end
%;
macro
DEALLOCATE_NETLNK (CHAN) =
begin
external NETLNK : vector [10];
%debug (always,
begin
if (CHAN) gtr 9 or CHAN leq 0 then
TASK_ERROR ('Bad channel numbet given to DEALLOCATE_NETLNK');
end;)
NETLNK [CHAN] = 0;
end
%;
!
! Macro - ALLOCATE_INTERRUPT_CHANNEL
!
! Function - This macro searchs the interrupt channel table
! for a free channel.
!
! Paramaters -
!
! I_ROUTINE Routine to call when interrupt occurs on channel
! I_DATA Data to pass to interrupt routine when called
!
! Return value -
!
! -1 No channel available
! >0 Channel number
!
macro
ALLOCATE_INTERRUPT_CHANNEL (I_ROUTINE, I_DATA) =
begin
local RESULT;
external
VECTAB : vector [10],
DATTAB : vector [10];
RESULT = -1;
incr INDEX from 0 to 9 do
if .VECTAB [.INDEX] eql 0
then
begin
RESULT = .INDEX;
exitloop;
end;
%if not %null (I_ROUTINE)
%then
if .RESULT neq -1
then VECTAB [.RESULT] = I_ROUTINE;
%fi
%if not %null (I_DATA)
%then
if .RESULT neq -1
then DATTAB [.RESULT] = I_DATA;
%fi
.RESULT
end %;
!
! Macro - RELEASE_INTERRUPT_CHANNEL
!
! Function - This macro flags that an interrupt channel is
! now available for use
!
! Parameters -
!
! CHANNEL Channel number to release
!
macro
RELEASE_INTERRUPT_CHANNEL (CHANNEL) =
begin
external VECTAB : vector [10];
VECTAB [CHANNEL] = 0;
end %;
! System specific time interface
!
! This set of macros allows transparent manipulation of "time"
! in a particular system. The macros are defined to read time
! from the operating system, read time with a offset, compare time,
! set and clear interrupts on time.
!
!
! Time block structure
!
! This structure defines the format needed for a specific
! system to store a internal time/date value.
literal
TIME_BLOCK_SIZE = 1,
TIME_BLOCK_ALLOCATION = 1;
macro
TIME_BLOCK =
vector [1] %;
!
! macro: TIME_PLUS
!
! This macro adds the second argument (which is in units of
! seconds) to the first argument which is a time block.
!
macro
TIME_PLUS (TIME, SECONDS) =
begin
bind TBLK = TIME : TIME_BLOCK;
TBLK [0] = .TBLK[0] + SECONDS ^ 18 / (24 * 60 * 60)
end %;
!
! macro: TIME_DIFFERENCE_SECONDS
!
! This macro computes the difference of two internal format
! times. Its two arguments are the addresses of the TIME_BLOCKs.
! Its value is the difference between the two times in seconds
macro
TIME_DIFFERENCE_SECONDS (TIME1, TIME2) =
begin
bind TBLK1 = TIME1 : TIME_BLOCK,
TBLK2 = TIME2 : TIME_BLOCK;
builtin
ash;
ash (((.TBLK1[0] - .TBLK2[0]) * 24 * 60 * 60 + 1 ^ 17), -18)
end
%;
!
! macro: TIME_CURRENT
!
! This macro returns the current time in
! the host operating systems time format.
! This is the format needed to set timer
! interrupts.
!
! TIME_CURRENT (OFFSET, TIM_BLK)
!
! where OFFSET is the number of seconds to add to the
! actual current time.
! TIM_BLK is the address of the time block in which
! to store the resulting time.
macro
TIME_CURRENT (OFFSET, TIM_BLK) =
begin
bind TBLK = TIM_BLK : TIME_BLOCK;
builtin UUO;
register T1;
T1 = _CNDTM;
UUO (1, GETTAB(T1));
TBLK [0] = .T1 + OFFSET * 3;
end %;
!
! macro: TIME_INTERRUPT_CLEAR
!
! This macro clears all outstanding timer interrupts.
!
macro
TIME_INTERRUPT_CLEAR =
begin
builtin UUO;
register T1;
T1 = %o '777777'; ! Make time for next interrupt be infinity
UUO (1, PITMR$(T1));
end %;
!
! macro: TIME_INTERRUPT_SET
!
! This macro sets a time interrupt. It also
! defines the routine to be called when the
! interrupt occurs.
!
! Note that since the interrupt channel is
! hard coded the time interrupt must be unique.
!
! TIME_INTERRUPT_SET (TIME_BLK, TROUTINE)
!
! where TIM_BLK is the time in the future for a interrupt
! ROUTINE is the address of the interrupt service routine
macro
TIME_INTERRUPT_SET (TIM_BLK, TROUTINE) =
begin
bind TBLK = TIM_BLK : block [1];
builtin UUO;
register T1, T2, T3;
external VECTAB : vector [10];
local ARGLST : vector [3];
own TIMER_CHANNEL : initial (-1);
! Compute the daytime in seconds
T2 = _CNDTM;
UUO (1, GETTAB(T2));
! Compute the amount of time (in seconds) to be hibered
! .T2 = the current time, TBLK contains the wakeup time
T2 = TIME_DIFFERENCE_SECONDS (TBLK, T2);
! If .T2 (the amount of time to be hibered) leq 0 then the wakeup
! time has passed, in which case we call TROUTINE immediately.
if .T2 leq 0 then
TROUTINE()
else
begin
! Now set up the PISYS to trap on the timer interrupt
if (.TIMER_CHANNEL eql -1) then
begin
TIMER_CHANNEL = ALLOCATE_INTERRUPT_CHANNEL (TROUTINE);
ARGLST [0] = $PCTMR;
ARGLST [1] = (.TIMER_CHANNEL * 4) ^ 18;
ARGLST [2] = 0;
T1 = PS$FAC + ARGLST;
UUO (1, PISYS$(T1));
end;
! Tell the monitor when to wake us up
UUO (1, PITMR$(T2));
end
end %;
!
! macro: TIME_SET_NULL
!
! This macro sets a time block to a null value.
! This value is used as a sentinel to check for
! a valid time value (null/not null).
!
! TIME_SET_NULL (TIM_BLK)
!
! where TIM_BLK is the address of the time block.
macro
TIME_SET_NULL (TIM_BLK) =
begin
bind TBLK = TIM_BLK : TIME_BLOCK;
TBLK [0] = -1;
end %;
!
! macro: TIME_NOT_NULL
!
! This macro checks to the value in a time block
! to see if it is not null (see TIME_SET_NULL).
!
! TIME_NOT_NULL (TIM_BLK)
!
! where TIM_BLK is the address of the time block to test.
macro
TIME_NOT_NULL (TIM_BLK) =
begin
bind TBLK = TIM_BLK : TIME_BLOCK;
.TBLK [0] neq -1
end %;
!
! macro: TIME_NULL
!
! This macro checks to the value in a time block
! to see if it is null (see TIME_SET_NULL).
!
! TIME_NULL (TIM_BLK)
!
! where TIM_BLK is the address of the time block to test.
macro
TIME_NULL (TIM_BLK) =
begin
bind TBLK = TIM_BLK : TIME_BLOCK;
.TBLK [0] eql -1
end %;
!
! macro: TIME_COPY
!
! This macro copies the time from one time block
! to another time block.
!
! TIME_COPY (TO_BLK, FRM_BLK)
!
! where TO_BLK is the time block to copy the time to.
! FRM_BLK is the time block to copy the time from.
macro
TIME_COPY (TO_BLK, FRM_BLK) =
begin
bind TOBLK = TO_BLK : TIME_BLOCK,
FRMBLK = FRM_BLK : TIME_BLOCK;
TOBLK [0] = .FRMBLK [0];
end %;
!
! macro: TIME_TEST
!
! This macro tests the chronological relation of
! the values in two time blocks. The test operator
! is specified as an argument to the macro. The
! value returned by this macro is a boolean (true/false)
! from the test "TB1 TST_FNC TB2" (i.e. TB1 lss TB2).
!
! TIME_TEST (TBLK1, TST_FNC, TBLK2)
!
! where TBLK1 is the first time block.
! TST_FNC is the test operator (LSS, GTR, EQL,..etc)
! TBLK2 is the second time time.
macro
TIME_TEST (TBLK1, TST_FNC, TBLK2) =
begin
bind TIMBLK1 = TBLK1 : TIME_BLOCK,
TIMBLK2 = TBLK2 : TIME_BLOCK;
.TIMBLK1 [0] TST_FNC .TIMBLK2 [0]
end %;
!
!<BLF/PAGE>
!
! macro: ARITHMETIC_OVERFLOW
!
! This macro enables interrupts on arithmetic errors.
! The routine specified will be called when an error
! occurs.
macro
ARITHMETIC_OVERFLOW (E_ROUTINE) =
begin
builtin UUO;
external VECTAB : vector [10];
local ARGLST : vector [3];
register T1;
APRTAB [0] = E_ROUTINE;
ARGLST [0] = 1;
ARGLST [1] = $UTAOF;
ARGLST [2] = JSR^27 + APRVEC [0, APR_VEC_OLDPC];
T1 = $UTSET ^ 18 + ARGLST;
UUO (1 ,UTRP$(T1));
end %;
! macro: STACK_OVERFLOW
!
! This macro enables interrupts on push down list
! overflows. The routine specified will be called
! when an error occurs.
macro
STACK_OVERFLOW (E_ROUTINE) =
begin
builtin UUO;
external VECTAB : vector [10];
local ARGLST : vector [3];
register T1;
APRTAB [1] = E_ROUTINE;
ARGLST [0] = 1;
ARGLST [1] = $UTPOV;
ARGLST [2] = JSR^27 + APRVEC [1, APR_VEC_OLDPC];
T1 = $UTSET ^ 18 + ARGLST;
UUO (1 ,UTRP$(T1));
end %;
! macro: ILLEGAL_INSTRUCTION
!
! This macro enables interrupts on illegal instruction
! traps. The routine specified will be called when an
! error occurs.
macro
ILLEGAL_INSTRUCTION (E_ROUTINE) =
begin
builtin UUO;
external VECTAB : vector [10];
local ARGLST : vector [3];
register T1;
T1 = ALLOCATE_INTERRUPT_CHANNEL (E_ROUTINE);
ARGLST [0] = $PCIUU;
ARGLST [1] = (.T1 * 4) ^ 18;
ARGLST [2] = 0;
T1 = PS$FAC + ARGLST;
UUO (1, PISYS$(T1));
end %;
! macro: ILLEGAL_MEMORY_REFERENCE
!
! This macro enables interrupts on illegal memory reads
! and writes. The routine specified will be called when
! an error occurs.
macro
ILLEGAL_MEMORY_REFERENCE (E_ROUTINE) =
begin
builtin UUO;
external VECTAB : vector [10];
local ARGLST : vector [3];
register T1;
T1 = ALLOCATE_INTERRUPT_CHANNEL (E_ROUTINE);
ARGLST [0] = $PCIMR;
ARGLST [1] = (.T1 * 4) ^ 18;
ARGLST [2] = 0;
T1 = PS$FAC + ARGLST;
UUO (1, PISYS$(T1));
end %;
! macro: SYSTEM_RESOURCE_FAILURE
!
! This macro enables interrupts on system resource
! allocation failures. The routine specified will
! be called when an error occurs.
macro
SYSTEM_RESOURCE_FAILURE (E_ROUTINE) =
begin
builtin UUO;
external VECTAB : vector [10];
local ARGLST : vector [3];
register T1;
T1 = ALLOCATE_INTERRUPT_CHANNEL (E_ROUTINE);
ARGLST [0] = $PCXEJ;
ARGLST [1] = (.T1 * 4) ^ 18;
ARGLST [2] = 0;
T1 = PS$FAC + ARGLST;
UUO (1, PISYS$(T1));
end %;
!<BLF/PAGE>
!
! macro: ACTIVATE_INTERRUPT
!
! This macro enables a specific interrupt. The
! variable HANDLE points to the relevant interrupt
! data base.
macro
ACTIVATE_INTERRUPT (CHANNEL) =
%;
! begin
! builtin UUO;
! register T1;
! local PISARG : vector [3];
!
! PISARG [0] = .HANDLE_TAB [.HANDLE, HT_REASON];
! PISARG [1] = (4 * .HANDLE_TAB [.HANDLE, HT_CHANNEL]) ^ 18;
! PISARG [2] = 0;
!
! T1 = PS$FAC + PISARG;
! UUO (1, PISYS$(T1));
! end %;
!
! macro: DEACTIVATE_INTERRUPT
!
! This macro disables a specific interrupt. The
! variable HANDLE is the index into the HANDLE_TAB
! interrup data base.
macro
DEACTIVATE_INTERRUPT (CHANNEL) =
%;
! begin
! builtin UUO;
! register T1;
! local PISARG : vector [3];
!
! PISARG [0] = .HANDLE_TAB [.HANDLE, HT_REASON];
! PISARG [1] = (4 * .HANDLE_TAB [.HANDLE, HT_CHANNEL]) ^ 18;
! PISARG [2] = 0;
!
! T1 = PS$FRC + PISARG;
! UUO (1, PISYS$(T1));
! end %;
!<BLF/PAGE>
!
! macro: INTERRUPT_ON
!
! This macro enables the interrupt system. If nested
! INTERRUPT_OFF calls have been made, this call only
! decrements the nesting count.
macro
INTERRUPT_ON =
begin
builtin UUO, MACHSKIP;
register T1;
external INTNST; ! Interrupt nesting count
T1 = PS$FON;
if not MACHSKIP (SOSGE, 0, INTNST) then UUO (1, PISYS$(T1));
end %;
!
! macro: INTERRUPT_OFF
!
! This macro turns the interrupt system off. It
! also increments the nesting count of times that
! it has been turned off.
macro
INTERRUPT_OFF =
begin
register T1;
builtin UUO, MACHSKIP;
external INTNST;
T1 = PS$FOF;
if not MACHSKIP (AOSN, 0, INTNST) then
UUO (1, PISYS$(T1)); ! Turn interrupt system off
end %;
!<BLF/PAGE>
!
! System specific interrupt system internal macros
!
! macro: SET_*_INTERRUPT
!
! These macro sets up a interrupt specified
! by HANDLE_TAB [.HANDLE, *] (the interrupt
! data base indexed by the handle).
macro
SET_FILE_INTERRUPT =
TASK_ERROR ('File interrupts not ready yet.') %;
macro
SET_TIMER_INTERRUPT =
TASK_ERROR ('Timer interrupts not ready yet.') %;
macro
SET_NETWORK_INTERRUPT =
TASK_ERROR ('Network interrupts not ready yet.') %;
!<BLF/PAGE>
!
! Wait Block Structure
!
! This defines the WAIT_BLOCK used in timing out waiting for events,
! specifically those waits implemented by calling NMU$SCHED_WAIT.
!
$field WAIT_BLOCK_FIELDS =
set
WAITING_TASK = [$address], !task block addr, to ref semaphore
$ALIGN (FULLWORD)WAIT_EVENT = [$address], !addr of event block to wait on
$ALIGN (FULLWORD)WAIT_TIME = [$sub_block (TIME_BLOCK_SIZE)] !time at which to 'wake'
tes
;
!
literal
WAIT_BLOCK_SIZE = $field_set_size;
!
macro
WAIT_BLOCK =
block [WAIT_BLOCK_SIZE] field (WAIT_BLOCK_FIELDS)%;
!
!
! Memory allocation
!
! macro: CORE_GET
!
! This macro gets a block of memory from the
! operating system of the specified size. The
! address of the block is returned as the value
! of the macro.
!
! CORE_GET (BLOCK_SIZE)
!
! where BLOCK_SIZE is the number of fullwords to be allocated.
macro
CORE_GET (BLKSIZE) =
begin
literal $JBFF = %o '121',
$JBREL = %o '44';
local BLKADDR;
register T1;
builtin UUO;
BLKADDR = .$JBFF; ! Get current .JBFF value
if .$JBFF + (BLKSIZE) - 1 GTR .$JBREL then
begin
T1 = .$JBFF + (BLKSIZE) - 1;
if UUO (1,CORE(T1)) then
begin
$JBFF = .$JBFF + (BLKSIZE);
.BLKADDR
end
else 0
end
else
begin
$JBFF = .$JBFF + (BLKSIZE);
.BLKADDR
end
end %;
!<BLF/PAGE>
!
! Process sleep and wakeup
!
! macro: PROCESS_SLEEP
!
! This macro puts the current process to
! sleep for the specified amount of time.
! The process is not guaranteed to sleep
! the specified amount.
!
! PROCESS_SLEEP (TIME)
!
! where TIME is the number of seconds to sleep.
macro
PROCESS_SLEEP (TIME) =
begin
builtin UUO;
register T1;
T1 = TIME * 1000 + HB$RWP + HB$RWT;
UUO (1, HIBER(T1));
end %;
!
! macro: PROCESS_WAKE
!
! This macro wakes up the current process.
! It may be called at interrupt level to
! complement the PROCESS_SLEEP function.
!
macro
PROCESS_WAKE =
begin
builtin
UUO;
register
T1;
T1 = 0; ! Wake up this job
UUO (1,WAKE(T1));
end %;
!
!<BLF/PAGE>
!
! IPCF functions
!macro
! $MUTIL (LEN, ARGBLK, FUNC, ERROR) =
!
! begin
! builtin JSYS;
! local RESULT;
! register T1=1, T2=2;
! T1 = LEN;
! T2 = ARGBLK;
! ARGBLK [0] = FUNC;
! RESULT = JSYS (-1, MUTIL_, T1, T2);
! ERROR = .T1;
! .RESULT
! end %;
macro
$MSEND (LEN, PDB, ERROR) =
begin
local RESULT;
builtin UUO;
register T1;
T1 = LEN ^ 18 + PDB;
RESULT = UUO (1, IPCFS$(T1));
ERROR = .T1;
.RESULT
end %;
macro
$MRECV (LEN, PDB, ERROR) =
begin
local RESULT;
builtin UUO;
register T1;
T1 = LEN ^ 18 + PDB;
RESULT = UUO (1, IPCFR$(T1));
ERROR = .T1;
.RESULT
end %;
!<BLF/PAGE>
!
! Network interface macros
!
! System specific fields for the LINK_INFO_BLOCK
!
macro
$strblk (n) =
$sub_block(1+(n+3)/4) %;
macro
LINK_SYSTEM_SPECIFIC_FIELDS =
LINK_NSP_CHN = [$integer], ! NSP link channel
LINK_NSP_STATUS = [$integer], ! NSP status word
LINK_READ_CONNECT_DATA = [$integer], ! Flag we read in connect data
!
! The following set of field definitions contains the complete set
! of arguments and data for an NSP. connect block.
!
LINK_NSP_CBLK = [$sub_block (8)], ! NSP Connect block
! Individual fields are accessed by $NDxxx symbols
! Define storage for all the fields pointed to by the connect block
LINK_NSP_HOST = [$strblk (6)], ! Node name
LINK_NSP_SOURCE_PDB = [$sub_block (5)],! NSP source PDB
LINK_NSP_SRC_PN = [$strblk (16)], ! Process name string
LINK_NSP_DEST_PDB = [$sub_block (5)], ! NSP destination PDB
LINK_NSP_DST_PN = [$strblk (16)], ! Process name string
LINK_NSP_USERID = [$strblk (39)], ! User ID
LINK_NSP_PASSWD = [$strblk (39)], ! Password
LINK_NSP_ACCOUN = [$strblk (39)], ! Account string
LINK_NSP_DATA = [$strblk (16)] ! User data
%,
STRING_BLOCK (n) =
block [1+(n*3)/4] field (STRING_BLOCK_FIELDS) %,
INIT_STRING (ADDR, LENGTH) =
STRBLK [ADDR, STRING_HEADER] = 1 + ( LENGTH + 3 ) / 4 %;
structure
STRBLK [OFFSET, POS, SIZE; NUMCHARS] =
[1 + (NUMCHARS + 3)/4]
(STRBLK + OFFSET)<POS, SIZE>;
field
STRING_BLOCK_FIELDS =
set
STRING_HEADER = [0, 0, 36], ! ** Contains next 2 fields
LENGTH_CHARS = [0, 18, 18], ! Length in characters
LENGTH_WORDS = [0, 0, 18], ! Length in words
STRING = [1, 0, 36] ! Start of string
tes;
!
! Macro: LOCAL_NODE_NUMBER
!
! This macro returns the local node number. It
! puts it into a byte string pointed to by the
! supplied byte pointer.
!
! LOCAL_NODE_NUMBER (NODE_PTR)
!
! where NODE_PTR is the address of a byte pointer that
! is updated when done.
!
macro
LOCAL_NODE_NUMBER (NODE_PTR) =
begin
builtin UUO;
local NTMAN_BLOCK : vector [$NTMAX];
register T1;
NTMAN_BLOCK [$NTCNT] = $NTMAX;
NTMAN_BLOCK [$NTENT] = $NTNOD;
NTMAN_BLOCK [$NTFNC] = $NTREX; ! Return local node number
NTMAN_BLOCK [$NTBPT] = .NODE_PTR;
NTMAN_BLOCK [$NTBYT] = 3;
T1 = NTMAN_BLOCK;
UUO (1, NTMAN$ (T1));
NODE_PTR = ch$plus (.NODE_PTR, 2); ! Don't forget to update this
end %;
!
! macro: LOCAL_NODE_NAME
!
! This macro returns the local node name in a
! counted ASCII string. The node name is written
! into the string pointed to by the supplied byte
! pointer and the first byte is the number of characters
! in the node name.
!
! LOCAL_NODE_NAME (NODE_PTR)
!
! where NODE_PTR is the address of a byte pointer
macro
LOCAL_NODE_NAME (NODE_PTR) =
begin
builtin UUO;
register T1;
local
NAME_BUFFER : vector [ch$allocation (8, 2 + 7)],
NTMAN_BLOCK : vector [$NTMAX];
NTMAN_BLOCK [$NTCNT] = $NTMAX;
NTMAN_BLOCK [$NTENT] = $NTNOD;
NTMAN_BLOCK [$NTFNC] = $NTREX; ! Return local node number
NTMAN_BLOCK [$NTBPT] = ch$ptr (NAME_BUFFER,,8);
NTMAN_BLOCK [$NTBYT] = 3;
T1 = NTMAN_BLOCK;
UUO (1, NTMAN$ (T1));
NTMAN_BLOCK [$NTCNT] = $NTMAX;
NTMAN_BLOCK [$NTFNC] = $NTMAP; ! Map number to node id
NTMAN_BLOCK [$NTBPT] = ch$ptr (NAME_BUFFER,,8);
NTMAN_BLOCK [$NTBYT] = 9;
T1 = NTMAN_BLOCK;
UUO (1, NTMAN$ (T1));
ch$move (7, ch$ptr (NAME_BUFFER, 2, 8), .NODE_PTR);
end %;
!
! Set up arguments for NSP. by turning CONNECT_BLOCKs
! into LINK_INFO blocks
!
macro
BUILD_LINK_INFO_BLOCK (CONN_BLK, LINK_INFO) =
begin
bind LI = LINK_INFO : LINK_INFO_BLOCK,
LI_NSP = LI [LINK_NSP_CBLK] : vector [8],
LI_NSP_DST = LI [LINK_NSP_DEST_PDB] : vector [5],
LI_NSP_SRC = LI [LINK_NSP_SOURCE_PDB] : vector [5],
CB = CONN_BLK : CONNECT_BLOCK;
external routine USER_NAME;
LI [LINK_NSP_CHN] = 0;
LI [LINK_READ_CONNECT_DATA] = 0; ! Say we haven't read connect data yet
! Set up all pointers in the Connect block
LI_NSP [$NSCNL] = 8;
LI_NSP [$NSCND] = LI [LINK_NSP_HOST];
LI_NSP [$NSCSD] = LI [LINK_NSP_SOURCE_PDB];
LI_NSP [$NSCDD] = LI [LINK_NSP_DEST_PDB];
LI_NSP [$NSCUS] = LI [LINK_NSP_USERID];
LI_NSP [$NSCPW] = LI [LINK_NSP_PASSWD];
LI_NSP [$NSCAC] = LI [LINK_NSP_ACCOUN];
LI_NSP [$NSCUD] = LI [LINK_NSP_DATA];
! Initialize the source Process Desrciptor Block
LI_NSP_SRC [$NSDFL] = 3;
LI_NSP_SRC [$NSDFM] = 0;
LI_NSP_SRC [$NSDOB] = 0;
LI_NSP_SRC [$NSDPP] = 0;
LI_NSP_SRC [$NSDPN] = LI [LINK_NSP_SRC_PN];
! Initialize the destination Process Descriptor Block
LI_NSP_DST [$NSDFL] = 3;
LI_NSP_DST [$NSDFM] = 0;
LI_NSP_DST [$NSDOB] = 0;
LI_NSP_DST [$NSDPP] = 0;
LI_NSP_DST [$NSDPN] = LI [LINK_NSP_DST_PN];
! Initialize all string blocks
INIT_STRING (LI [LINK_NSP_HOST], 6);
INIT_STRING (LI [LINK_NSP_SRC_PN], 16);
INIT_STRING (LI [LINK_NSP_DST_PN], 16);
INIT_STRING (LI [LINK_NSP_USERID], 39);
INIT_STRING (LI [LINK_NSP_PASSWD], 39);
INIT_STRING (LI [LINK_NSP_ACCOUN], 39);
INIT_STRING (LI [LINK_NSP_DATA], 16);
! Set up strings in the Connect block
begin
!
! Set up Node (or Host if you prefer) name
!
if .CB [CB_HOST_LENGTH] neq 0 then
begin
STRBLK [ LI [LINK_NSP_HOST], LENGTH_CHARS] = .CB [CB_HOST_LENGTH];
ch$move(.CB [CB_HOST_LENGTH],
ch$plus(.CB [CB_HOST],3),
ch$ptr(STRBLK [ LI [LINK_NSP_HOST], STRING],,8));
end;
!
! Set up source PDB
!
if .CB [CB_TASK_LENGTH] neq 0 then
begin
LI_NSP_SRC [$NSDFL] = 5;
LI_NSP_SRC [$NSDFM] = 1;
STRBLK [ LI [LINK_NSP_SRC_PN], LENGTH_CHARS] =
.CB [CB_TASK_LENGTH];
ch$move(.CB [CB_TASK_LENGTH],
.CB [CB_TASK],
ch$ptr(STRBLK [ LI [LINK_NSP_SRC_PN], STRING],,8));
end
else
begin
LI_NSP_SRC [$NSDFL] = 3;
LI_NSP_SRC [$NSDFM] = 0;
LI_NSP_SRC [$NSDOB] = 27;
end;
!
! Set up destination PDB
!
if .CB [CB_OBJECT] eql 0 then
begin
LI_NSP_DST [$NSDFL] = 5;
LI_NSP_DST [$NSDFM] = 1;
if .CB [CB_DESCRIPTOR_LENGTH] neq 0 then
begin
STRBLK [ LI [LINK_NSP_DST_PN], LENGTH_CHARS] =
.CB [CB_DESCRIPTOR_LENGTH];
ch$move(.CB [CB_DESCRIPTOR_LENGTH],
.CB [CB_DESCRIPTOR],
ch$ptr(STRBLK [ LI [LINK_NSP_DST_PN], STRING],,8));
end;
end
else LI_NSP_DST [$NSDOB] = .CB [CB_OBJECT];
!
! Add optional userid attribute
!
if .CB [CB_USERID_LENGTH] neq 0 then
begin
STRBLK [ LI [LINK_NSP_USERID], LENGTH_CHARS] =
.CB [CB_USERID_LENGTH];
ch$move(.CB [CB_USERID_LENGTH],
.CB [CB_USERID],
ch$ptr(STRBLK [ LI [LINK_NSP_USERID], STRING],,8));
end;
!
! Add optional password attribute
!
if .CB [CB_PASSWORD_LENGTH] neq 0 then
begin
STRBLK [ LI [LINK_NSP_PASSWD], LENGTH_CHARS] =
.CB [CB_PASSWORD_LENGTH];
ch$move(.CB [CB_PASSWORD_LENGTH],
.CB [CB_PASSWORD],
ch$ptr(STRBLK [ LI [LINK_NSP_PASSWD], STRING],,8));
end;
!
! Add optional account attribute
!
if .CB [CB_ACCOUNT_LENGTH] neq 0 then
begin
STRBLK [ LI [LINK_NSP_ACCOUN], LENGTH_CHARS] =
.CB [CB_ACCOUNT_LENGTH];
ch$move(.CB [CB_ACCOUNT_LENGTH],
.CB [CB_ACCOUNT],
ch$ptr(STRBLK [ LI [LINK_NSP_ACCOUN], STRING],,8));
end;
!
! Add optional data attribute
!
if .CB [CB_DATA_LENGTH] neq 0 then
begin
STRBLK [ LI [LINK_NSP_DATA], LENGTH_CHARS] =
.CB [CB_DATA_LENGTH];
ch$move(.CB [CB_DATA_LENGTH],
.CB [CB_DATA],
ch$ptr(STRBLK [ LI [LINK_NSP_DATA], STRING],,8));
end;
end
end %;
!
! Macro - OPEN_FOR_CONNECTION
!
! Function - This macro opens a logical link. If it is a source
! link, the connect is sent. If it is a target link
! it opens for possible connection.
!
! Parameters -
!
! LINK_INFO Address of link info block
!
! Return value -
!
! $true Link is setup for connection properly
! $false Link setup failed
macro
OPEN_FOR_CONNECTION (LINK_INFO) =
begin
builtin UUO;
register T1;
external
DATTAB : vector [10],
VECTAB : vector [10],
NETLNK : vector [10],
PIVEC : blockvector [6, 4];
bind LI = LINK_INFO : LINK_INFO_BLOCK;
local NSPARG : vector [5], PISARG : vector [3];
own LINK_INTERRUPT_CHANNEL : initial (-1);
!
! Get channel for link
!
NSPARG [$NSAA1] = LI [LINK_NSP_CBLK];
NSPARG [$NSAA2] = 0;
NSPARG [$NSAA3] = 0;
if .LI [LINK_TYPE] eql SOURCE_LINK
then NSPARG [$NSAFN] = $NSFEA ^ 18 + 5
else NSPARG [$NSAFN] = $NSFEP ^ 18 + 5;
T1 = NSPARG;
if UUO (1, NSP$(T1))
then
begin
LI [LINK_NSP_CHN] = .NSPARG [$NSACH] and %o'777777';
ALLOCATE_NETLNK (.NSPARG [$NSACH] and %o '777777', LI);
!
! Set up the PI system
!
if .LINK_INTERRUPT_CHANNEL eql -1
then
begin
LINK_INTERRUPT_CHANNEL =
ALLOCATE_INTERRUPT_CHANNEL (NETWORK_EVENT,
0);
DATTAB [.LINK_INTERRUPT_CHANNEL] = PIVEC + $PSVIS + 4 *
.LINK_INTERRUPT_CHANNEL;
PISARG [0] = $PCNSP;
PISARG [1] = (.LINK_INTERRUPT_CHANNEL * 4) ^ 18;
PISARG [2] = 0;
T1 = PS$FAC + PISARG;
UUO (1, PISYS$(T1))
end; ! End of if .LINK_INTERRUPT_CHANNEL eql -1
NSPARG [$NSAFN] = $NSFPI ^ 18 + 3;
NSPARG [$NSAA1] = %o'777777';
T1 = NSPARG;
if UUO (1, NSP$(T1)) then $true else $false
end
else
begin
%debug (NETWORK_TRANSITIONS,
(TRACE_INFO ('NSP UUO did not skip. Reason: %O',.T1)));
$false
end
end
%;
macro
ACCEPT_NETWORK_CONNECT (LINK_INFO, DATA_LEN, DATA_PTR) =
begin
bind LI = LINK_INFO : LINK_INFO_BLOCK;
begin
builtin UUO;
local NSPARG : vector [3],
USER_DATA : STRING_BLOCK (16);
register T1;
INIT_STRING (USER_DATA, 16);
STRBLK [USER_DATA, LENGTH_CHARS] = DATA_LEN;
ch$move (DATA_LEN,
DATA_PTR,
ch$ptr(STRBLK [USER_DATA, STRING],, 8));
NSPARG [$NSAFN] = $NSFAC ^ 18 + 3;
NSPARG [$NSACH] = .LI [LINK_NSP_CHN];
NSPARG [$NSAA1] = USER_DATA;
T1 = NSPARG;
UUO (1, NSP$(T1));
end;
begin
local
WAITING ;
WAITING = $TRUE ;
while .WAITING
do begin
READ_LINK_STATUS (LINK_INFO) ;
if (WAITING = not ((LINK_CONNECTED (LINK_INFO)) or
(LINK_DISCONNECTED (LINK_INFO))))
then NMU$SCHED_SLEEP (1) ;
end;
end;
end %;
macro
REJECT_NETWORK_CONNECT (LINK_INFO, REASON, DATA_LEN, DATA_PTR) =
begin
bind LI = LINK_INFO : LINK_INFO_BLOCK;
builtin UUO;
local NSPARG : vector [3],
USER_DATA : STRING_BLOCK (16);
register T1;
INIT_STRING (USER_DATA, 16);
ch$move (DATA_LEN,
DATA_PTR,
ch$ptr(STRBLK [USER_DATA, STRING],, 8));
STRBLK [USER_DATA, LENGTH_CHARS] = DATA_LEN;
NSPARG [$NSAFN] = $NSFRJ ^ 18 + 3;
NSPARG [$NSACH] = .LI [LINK_NSP_CHN];
NSPARG [$NSAA1] = USER_DATA;
T1 = NSPARG;
UUO (1, NSP$(T1));
end %;
macro
LINK_OPEN (LINK_INFO) =
begin
bind LI = LINK_INFO : LINK_INFO_BLOCK,
LS = LI [LINK_NSP_STATUS];
(if .LI [LINK_TYPE] eql SOURCE_LINK
then (POINTR(.LS, NS$STA) eql $NSSRN)
else (POINTR(.LS, NS$STA) eql $NSSCR))
end %;
macro
LINK_CONNECTED (LINK_INFO) =
begin
bind LI = LINK_INFO : LINK_INFO_BLOCK,
LS = LI [LINK_NSP_STATUS];
(POINTR (.LS, NS$STA) eql $NSSRN)
end %;
macro
LINK_DISCONNECTED (LINK_INFO) =
begin
bind LI = LINK_INFO : LINK_INFO_BLOCK,
LS = LI [LINK_NSP_STATUS];
(
! **** Do Soon ****
! Figure out how RJ and DR states relate to this mess!
! ((.LS and NS$LWU) neq 0)
! or
(POINTR (.LS, NS$STA) eql $NSSDR)
or
(POINTR (.LS, NS$STA) eql $NSSLK))
end %;
macro
CONNECT_WAIT (LINK_INFO) =
begin
bind LI = LINK_INFO : LINK_INFO_BLOCK,
LS = LI [LINK_NSP_STATUS];
(if .LI [LINK_TYPE] eql SOURCE_LINK
then (POINTR(.LS, NS$STA) eql $NSSCS)
else (POINTR(.LS, NS$STA) eql $NSSCW))
end %;
macro
READ_MESSAGE (LINK_INFO, BUFFER_LEN, BUFFER_PTR) =
begin
builtin UUO;
bind LI = LINK_INFO : LINK_INFO_BLOCK,
LS = LI [LINK_NSP_STATUS];
local CHAR_READ;
! local CHAR_READ, READ_WAIT;
CHAR_READ = 0;
while $TRUE do
begin
local NSPARG : vector [4];
register T1;
NSPARG [$NSAFN] = $NSFDR ^ 18 + 5;
NSPARG [$NSACH] = .LI [LINK_NSP_CHN];
NSPARG [$NSAA1] = BUFFER_LEN;
NSPARG [$NSAA2] = BUFFER_PTR;
T1 = NSPARG;
if not UUO (1, NSP$(T1)) then return -2; !Error occured
CHAR_READ = BUFFER_LEN - .NSPARG [$NSAA1];
if (.CHAR_READ neq 0) or ((.NSPARG [$NSAFN] and NS$EOM) neq 0)
then exitloop;
if not NMU$SCHED_WAIT (LI [LINK_EVENT], 2*.ntimo) then return -1;
end;
.CHAR_READ
end
%;
macro
WRITE_MESSAGE (LINK_INFO, BUFFER_LEN, BUFFER_PTR) =
begin
bind LI = LINK_INFO : LINK_INFO_BLOCK,
LS = LI [LINK_NSP_STATUS];
builtin
UUO;
local
RESULT,
NSPARG : vector [4];
register
T1;
NSPARG [$NSAFN] = NS$EOM + $NSFDS ^ 18 + 4;
NSPARG [$NSACH] = .LI [LINK_NSP_CHN];
NSPARG [$NSAA1] = BUFFER_LEN;
NSPARG [$NSAA2] = BUFFER_PTR;
T1 = NSPARG;
while ((RESULT = UUO (1, NSP$(T1))) and .NSPARG [$NSAA1] neq 0) do
begin
NMU$SCHED_SLEEP (2);
T1 = NSPARG;
end;
.RESULT
end %;
macro
WRITE_STRING (LINK_INFO, BUFFER_LEN, BUFFER_PTR) =
begin
bind LI = LINK_INFO : LINK_INFO_BLOCK;
builtin UUO;
local WRITE_WAIT, RESULT;
WRITE_WAIT = $true;
while .WRITE_WAIT do
begin
READ_LINK_STATUS (LINK_INFO);
if LINK_CONNECTED (LINK_INFO)
then
if not
begin
local NSPARG : vector [5];
register T1;
NSPARG [$NSAFN] = $NSFRS ^ 18 + 5;
NSPARG [$NSACH] = .LI [LINK_NSP_CHN];
T1 = NSPARG;
UUO (1, NSP$(T1));
if (NS$NDR and .NSPARG [$NSACH]) eql 0
then $true
else $false
end
then NMU$SCHED_SLEEP (2)
else
begin
local NSPARG : vector [5];
register T1;
NSPARG [$NSAFN] = $NSFDS ^ 18 + 5;
NSPARG [$NSACH] = .LI [LINK_NSP_CHN];
NSPARG [$NSAA1] = BUFFER_LEN;
NSPARG [$NSAA2] = BUFFER_PTR;
T1 = NSPARG;
RESULT = UUO (1, NSP$(T1));
WRITE_WAIT = $false;
end
else WRITE_WAIT = $false;
end;
.RESULT
end %;
macro
ABORT_LINK (LINK_INFO, REASON, DATA_LEN, DATA_PTR) =
begin
bind LI = LINK_INFO : LINK_INFO_BLOCK;
builtin UUO;
local NSPARG : vector [5],
DATA : STRING_BLOCK (16);
register T1;
INIT_STRING (DATA, 16);
STRBLK [DATA, LENGTH_CHARS] = DATA_LEN;
ch$move (DATA_LEN,
DATA_PTR,
ch$ptr(STRBLK [DATA, STRING],, 8));
NSPARG [$NSAFN] = $NSFPI ^ 18 + 3;
NSPARG [$NSACH] = .LI [LINK_NSP_CHN];
NSPARG [$NSAA1] = 0;
T1 = NSPARG;
UUO (1, NSP$(T1));
NSPARG [$NSAFN] = $NSFAB ^ 18 + 5;
NSPARG [$NSAA1] = DATA;
T1 = NSPARG;
if not UUO (1, NSP$(T1))
then
begin
NSPARG [$NSAFN] = $NSFRL ^ 18 + 5;
T1 = NSPARG;
UUO (1, NSP$(T1));
end;
DEALLOCATE_NETLNK (.LI[LINK_NSP_CHN] and %o '777777');
end %;
macro
CLOSE_LINK (A, DATA_LEN, DATA_PTR) =
begin
builtin UUO;
local NSPARG : vector [3],
DATA : STRING_BLOCK (16);
register T1;
INIT_STRING (DATA, 16);
NSPARG [$NSAFN] = $NSFPI ^ 18 + 3;
NSPARG [$NSACH] = .LINK_INFO [LINK_NSP_CHN];
NSPARG [$NSAA1] = 0;
T1 = NSPARG;
UUO (1, NSP$(T1));
DEALLOCATE_NETLNK (.LINK_INFO [LINK_NSP_CHN] and %o '777777');
STRBLK [DATA, LENGTH_CHARS] = DATA_LEN;
ch$move (DATA_LEN, DATA_PTR, ch$ptr(STRBLK[DATA, STRING],, 8));
NSPARG [$NSAFN] = $NSFSD ^ 18 + 3; ! Synchronus disconnect
NSPARG [$NSACH] = .LINK_INFO [LINK_NSP_CHN];
NSPARG [$NSAA1] = DATA;
T1 = NSPARG;
UUO (1, NSP$(T1));
while $TRUE do ! Loop till we get a DC or UUO fails
begin
NSPARG [$NSAFN] = $NSFRS ^ 18 + 2;
T1 = NSPARG;
if not UUO (1, NSP$(T1)) then exitloop;
if (.NSPARG [$NSACH] and NS$STA) eql $NSSDS ^ 18 then
NMU$SCHED_SLEEP (5) else exitloop;
end;
NSPARG [$NSAFN] = $NSFRL ^ 18 + 2;
T1 = NSPARG;
UUO (1, NSP$(T1));
end %;
macro
READ_LINK_STATUS (LINK_INFO) =
begin
bind LI = LINK_INFO : LINK_INFO_BLOCK;
builtin UUO;
local NSPARG : vector [5];
register T1;
NSPARG [$NSAFN] = $NSFRS ^ 18 + 5;
NSPARG [$NSACH] = .LI [LINK_NSP_CHN];
T1 = NSPARG;
if not UUO (1, NSP$(T1)) then NSPARG [$NSACH] = 0;
LI [LINK_NSP_STATUS] = .NSPARG[$NSACH];
end %;
macro
READ_CONNECT_DATA (INFO_BLOCK) =
begin
bind LI = INFO_BLOCK : LINK_INFO_BLOCK,
LI_DST_PDB = LI [LINK_NSP_DEST_PDB] : vector [5],
LI_SRC_PDB = LI [LINK_NSP_SOURCE_PDB] : vector [5];
if .LI [LINK_READ_CONNECT_DATA] eql 0 then
begin
builtin UUO;
local NSPARG : vector [5];
register T1;
LI [LINK_READ_CONNECT_DATA] = 1;
LI_DST_PDB [$NSDFL] = LI_SRC_PDB [$NSDFL] = 5;
NSPARG [$NSAFN] = $NSFRI ^ 18 + 5;
NSPARG [$NSACH] = .LI [LINK_NSP_CHN];
NSPARG [$NSAA1] = LI [LINK_NSP_CBLK];
NSPARG [$NSAA2] = 0;
NSPARG [$NSAA3] = 0;
T1 = NSPARG;
UUO (1, NSP$(T1));
if .STRBLK [ LI [LINK_NSP_HOST], LENGTH_CHARS] eql 0 then
begin
external routine NMU$TEXT;
UUO(0, PJOB(T1));
NSPARG [0] = $DNSLS ^ 18 + $DNNOD + 1;
NSPARG [$DNJCN] = .T1 ^ 18 + .LI[LINK_NSP_CHN];
T1 = NSPARG;
UUO (1, DNET$(T1));
NSPARG[$DNNOD+1] = .NSPARG[$DNNOD]<0,10,0>;
NSPARG[$DNNOD] = .NSPARG[$DNNOD]<10,6,0>;
STRBLK [ LI [LINK_NSP_HOST], LENGTH_CHARS] = NMU$TEXT(
%ref(ch$ptr(STRBLK [ LI [LINK_NSP_HOST], STRING],,8)),
6,ch$ptr(uplit(%asciz '%D.%D')),2,NSPARG[$DNNOD]);
end;
end ;
end
%;
macro
READ_USER_NAME (CONN_BLOCK, INFO_BLOCK) =
begin
bind CB = CONN_BLOCK : CONNECT_BLOCK,
LI = INFO_BLOCK : LINK_INFO_BLOCK;
READ_CONNECT_DATA (INFO_BLOCK);
CB [CB_USERID] = ch$ptr (CB [CB_USERID_BUFFER] ,, 8);
ch$move (.STRBLK [ LI [LINK_NSP_USERID], LENGTH_CHARS],
ch$ptr (STRBLK [ LI [LINK_NSP_USERID], STRING],,8),
.CB [CB_USERID]);
CB [CB_USERID_LENGTH] =
.STRBLK [ LI [LINK_NSP_USERID], LENGTH_CHARS];
end %;
macro
READ_ACCOUNT_STRING (CONN_BLOCK, INFO_BLOCK) =
begin
bind CB = CONN_BLOCK : CONNECT_BLOCK,
LI = INFO_BLOCK : LINK_INFO_BLOCK;
READ_CONNECT_DATA (INFO_BLOCK);
CB [CB_ACCOUNT] = ch$ptr (CB [CB_ACCOUNT_BUFFER],, 8);
ch$move (.STRBLK [ LI [LINK_NSP_ACCOUN], LENGTH_CHARS],
ch$ptr (STRBLK [ LI [LINK_NSP_ACCOUN], STRING],,8),
.CB [CB_ACCOUNT]);
CB [CB_ACCOUNT_LENGTH] =
.STRBLK [ LI [LINK_NSP_ACCOUN], LENGTH_CHARS];
end %;
macro
READ_PASSWORD_STRING (CONN_BLOCK, INFO_BLOCK) =
begin
bind CB = CONN_BLOCK : CONNECT_BLOCK,
LI = INFO_BLOCK : LINK_INFO_BLOCK;
READ_CONNECT_DATA (INFO_BLOCK);
CB [CB_PASSWORD] = ch$ptr (CB [CB_PASSWORD_BUFFER],, 8);
ch$move (.STRBLK [ LI [LINK_NSP_PASSWD], LENGTH_CHARS],
ch$ptr (STRBLK [ LI [LINK_NSP_PASSWD], STRING],,8),
.CB [CB_PASSWORD]);
CB [CB_PASSWORD_LENGTH] =
.STRBLK [ LI [LINK_NSP_PASSWD], LENGTH_CHARS];
end %;
macro
READ_OPTIONAL_DATA (CONN_BLOCK, INFO_BLOCK) =
begin
bind CB = CONN_BLOCK : CONNECT_BLOCK,
LI = INFO_BLOCK : LINK_INFO_BLOCK;
READ_CONNECT_DATA (INFO_BLOCK);
CB [CB_DATA] = ch$ptr (CB [CB_DATA_BUFFER],, 8);
ch$move (.STRBLK [ LI [LINK_NSP_DATA], LENGTH_CHARS],
ch$ptr (STRBLK [ LI [LINK_NSP_DATA], STRING],,8),
.CB [CB_DATA]);
CB [CB_DATA_LENGTH] = .STRBLK [ LI [LINK_NSP_DATA], LENGTH_CHARS];
end %;
macro
READ_OBJECT_TYPE (CONN_BLOCK, INFO_BLOCK) =
begin
bind CB = CONN_BLOCK : CONNECT_BLOCK,
LI = INFO_BLOCK : LINK_INFO_BLOCK,
LI_NSP_DST = LI [LINK_NSP_DEST_PDB] : vector [5];
READ_CONNECT_DATA (INFO_BLOCK);
CB [CB_OBJECT] = .LI_NSP_DST [$NSDOB];
end %;
macro
READ_HOST_ID (CONN_BLOCK, INFO_BLOCK) =
begin
bind CB = CONN_BLOCK : CONNECT_BLOCK,
LI = INFO_BLOCK : LINK_INFO_BLOCK;
READ_CONNECT_DATA (INFO_BLOCK);
CB [CB_HOST] = ch$ptr (CB [CB_HOST_BUFFER],, 8);
CB [CB_HOST_LENGTH] = 3 + .STRBLK[ LI[LINK_NSP_HOST],LENGTH_CHARS];
PUTB ( 0, CB [CB_HOST]);
PUTB ( 0, CB [CB_HOST]);
PUTB ( .CB [CB_HOST_LENGTH] - 3, CB [CB_HOST]);
ch$move (.CB [CB_HOST_LENGTH],
ch$ptr (STRBLK [ LI [LINK_NSP_HOST], STRING],,8),
.CB [CB_HOST]);
CB [CB_HOST] = ch$ptr (CB [CB_HOST_BUFFER],, 8);
end %;
macro
READ_DESCRIPTOR (CONN_BLOCK, INFO_BLOCK) =
begin
bind CB = CONN_BLOCK : CONNECT_BLOCK,
LI = INFO_BLOCK : LINK_INFO_BLOCK;
READ_CONNECT_DATA (INFO_BLOCK);
CB [CB_DESCRIPTOR] = ch$ptr (CB [CB_DESCRIPTOR_BUFFER],, 8);
ch$move (.STRBLK [ LI [LINK_NSP_DST_PN], LENGTH_CHARS],
ch$ptr (STRBLK [ LI [LINK_NSP_DST_PN], STRING],,8),
.CB [CB_DESCRIPTOR]);
CB [CB_DESCRIPTOR_LENGTH] =
.STRBLK [ LI [LINK_NSP_DST_PN], LENGTH_CHARS];
end %;
macro
READ_REJECT_CODE (CONN_BLOCK, INFO_BLOCK) =
begin
bind CB = CONN_BLOCK : CONNECT_BLOCK,
LI = INFO_BLOCK : LINK_INFO_BLOCK,
LS = LI [LINK_NSP_STATUS];
local NSPARG : vector [4];
register T1;
builtin UUO;
NSPARG [$NSAFN] = $NSFRD ^ 18 + 4;
NSPARG [$NSACH] = .LI [LINK_NSP_CHN];
NSPARG [$NSAA2] = 0;
T1 = NSPARG;
if not UUO (1, NSP$(T1)) then
begin
bind
STATE_TO_REJECT_MAP = uplit (
0, ! 0
0, ! .NSSCW==1 ;Connect Wait
0, ! .NSSCR==2 ;Connect Received
0, ! .NSSCS==3 ;Connect Sent
7, ! .NSSRJ==4 ;Remote node rejected Connect Init
0, ! .NSSRN==5 ;Link is Up and Running
9, ! .NSSDR==6 ;Disconnect Received
0, ! .NSSDS==7 ;Disconnect Sent
0, ! .NSSDC==10 ;Disconnect Confirmed
38, ! .NSSCF==11 ;No Confidence
38, ! .NSSLK==12 ;No Link
39, ! .NSSCM==13 ;No Communication
32 ! .NSSNR==14 ;No Resources
) : vector [%o '15'];
NSPARG [$NSAA2] = .STATE_TO_REJECT_MAP [POINTR (.LS, NS$STA)];
end;
CB [CB_REJECT_CODE] = .NSPARG [$NSAA2];
end %;
macro
NETWORK_INTERRUPT_CLEAR (LINK_INFO) =
%;
!<BLF/PAGE>
!
! Local Modes:
! Mode:Fundamental
! Comment Start:!
! Comment Column:40
! Comment Rounding:+1
! Auto Save Mode:2
! End: