DataMuseum.dk

Presents historical artifacts from the history of:

RC4000/8000/9000

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about RC4000/8000/9000

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download

⟦c7866c076⟧ TextFile

    Length: 42240 (0xa500)
    Types: TextFile
    Names: »tnet2«

Derivation

└─⟦2c55ea56f⟧ Bits:30001844 SW-save af projekt 1000, Alarm-system
    └─⟦6b41451d2⟧ 
        └─⟦this⟧ »tnet2« 

TextFile

prefix return_empty;
procedure return_empty (var msg: reference; ok: boolean);
begin
msg^.u1 := input_msg;
msg^.u4 := empty_buf;
if ok then
msg^.u2 := result_ok
else
msg^.u2 := result_error;
return (msg);
end;

<* ************************************************* *>

prefix return_full;
procedure return_full (var msg: reference; ok: boolean);
begin
msg^.u1 := output_msg;
msg^.u4 := full_buf;
if ok then
msg^.u2 := result_ok
else
msg^.u2 := result_error;
return (msg);
end;

<* ************************************************ *>
(* this routine has been incorporated in  stdlib revision 6

prefix outnl;
procedure outnl (var z: zone);
begin
outchar (z, nl);
outend  (z);
end;
(* *)

<* ************************************************ *>

prefix outtime;
procedure outtime (var z: zone; t: timetype);
var
min, sec : integer;
begin
with t do
begin
outinteger (z, hours, 2);
outchar (z, '.');
min := seconds div 60;
sec := seconds mod 60;
outinteger (z, min div 10, 1);
outinteger (z, min mod 10, 1);
outchar (z, '.');
outinteger (z, sec div 10, 1);
outinteger (z, sec mod 10, 1);
end;
end;

<* ************************************************ *>

prefix print_msg;
procedure print_msg (var z: zone; var msg: reference; text: alfa);
begin
lock msg as buf:stdpart do
with buf do
begin
outtext (z, text);
outinteger (z, msg^.u1, 2);
outinteger (z, msg^.u2, 2);
outinteger (z, msg^.u3, 2);
outinteger (z, msg^.u4, 2);
outinteger (z, msg^.size, 4);
outinteger (z, first, 4);
outinteger (z, last,  4);
outinteger (z, next, 4);
outnl (z);
end;
end; <* print_msg *>

<* ************************************************ *>

process fpadriver(n: integer; var pdescr: proc_descrs; var sems: sem_arr);

const
<* definition of control-commands *>
reset_contr = 0;
repeat_int  = 2;
start_read  = 3;
<* definition of status-bits *>
st_parity_error      = 1;
st_reset_received    = 2;
st_disconnected      = 4;
st_autoload_received = 8;
st_receive_end       = 16;
st_timeout           = 32;
st_transmit_end      = 64;
<* definition of start char *>
block_start = #b10000110;  <* does not interfere with ncp-chars *>
<* definition of timers *>
read_period = 15; <* seconds *>
write_period = 15; <* seconds *>
after_error = 2; <* seconds pause *>

var
chm      : reference;
msg      : reference;
dummy    : integer;
start_char: integer;
mainsem  : ^ semaphore;
ch_ptr   : ^ array (1..maxint) of byte;
test     : boolean;
s        : integer;  <* last status read *>
result   : integer;  <* suggested result *>

zout     : zone;
out_pool : pool 1 of opbuffer;

procedure make_sense;
begin
sense (s, 0, chm);
if (s <> st_receive_end) and (s <> st_transmit_end) then
begin
result := result_error;
control (reset_contr, chm);
end
else
result := result_ok;
end;

begin
openopzone (zout, own.secret_pointer^(opsem), ref(zout.free), 1, out_pool, 2,7,0,0);
with pdescr(n) do
begin
dummy   := reservech (chm, first_devno_fpa - 1 + inc, 0);
mainsem := ref (sems(sem));
definetimer (true);
make_sense;

channel chm do
repeat <* forever *>

wait (msg, mainsem^);

test := pdescr(n).testval <> 0;
if test then print_msg (zout, msg, 'after wait:');

case msg^.u4 of

empty_buf:
begin
own.timer := read_period;
lock msg as buf: stdpart do
with buf, header do
begin
repeat
controlclr(start_read, chm);
inword (start_char, chm);
controlclr (repeat_int, chm);
inbyteblock(next, first, last, msg, chm);
make_sense;
until (own.timer = 0) or ((s and st_reset_received) = 0);
last := next - 1;
end;
if test then print_msg (zout, msg, 'after read:');
return_full (msg, (start_char = block_start) and (result = result_ok) and (not timedout));
end;

full_buf:
begin
own.timer := write_period;
ch_ptr := ptraddr(msg^.start);
lock msg as buf: stdpart do
with buf do
begin
outwordclr (0 <* irrel start char *>, chm);
outbyteblock (next, first, last-1, msg, chm);
controlclr (repeat_int, chm);
outwordclr (256 + ch_ptr^(last), chm);
end;
make_sense;
if test then print_msg (zout, msg, 'after write:');
return_empty (msg, (result = result_ok) and (not timedout));
if result <> result_ok then
begin
own.timer := after_error;
waitt;
end;
end;

end; <* case *>

until doomsday;

end; <* with pdescr *>
end; <* fpadriver *>

<* *********************************************************** *>

process hdlcdriver (n: integer; var pdescr: proc_descrs; var sems: sem_arr);

const

<* control commands *>
dma_reset    =  0*256;
trm_control  =  3*256;
mode_control =  5*256;
datalength   =  7*256;
setadrl      =  8*256;
setadrh      =  9*256;
setcntl      = 10*256;
setcnth      = 11*256;
setfll       = 12*256;
setflh       = 13*256;
setmsel      = 14*256;
start_rec    = 16*256;
start_xmit   = 17*256;
enable       = 18*256;
modem_control= 19*256;
step_pointer3= 20*256;
step_pointer0= 21*256;

<* sense registers *>
statusreg0   =  0*256;
countreg0    = 24*256;

<* xmit flags (high) *>
set_int      = 8;
set_teom     = 4;
clear_tsom   = 2;

<* xmit flags (low) *>
trm_valid    = 2;

<* rec flags (high) *>
exp_reom     = 4;

<* rec flags (low) *>
rec_valid    = 2;

<* status bits *>
rec_errors   = #h40fc;
xmit_errors  = #h1080;

<* modem bits *>
txe          = 2;
rxe          = 1;

<* timer periods *>
read_period  = 15; <* seconds *>
write_period = 10; <* seconds *>

var
mainsem   : ^ semaphore;
msg       : reference;
dev       : reference;
dummy     : integer;
ok        : boolean;
remcount  : integer;
status    : integer;

zout      : zone;
out_pool  : pool 1 of opbuffer;

procedure dodma (fh, fl, ctrl, period, mask: integer);
type
word = record h, l: byte end;
procedure asgn = asgnintset (var w: word; i: integer); external;
var
w: word;
begin
lock msg as buf: stdpart do
with buf do
begin

control (setmsel + msg^.start.base.mem_no, dev);
control (fh, dev);

asgn (w, first-last-1);
control (setcnth + w.h, dev);
control (setcntl + w.l, dev);

asgn (w, uadd(msg^.start.disp, first));
control (setadrh + w.h, dev);
control (setadrl + w.l, dev);

control (fl, dev);

control (step_pointer3, dev);

control (ctrl, dev);

own.timer := period;
controlclr (enable, dev);
if timedout then
begin
control (dma_reset, dev);
ok := false;
remcount := 0;
end
else
begin
sense (remcount, countreg0, dev);
sense (status, statusreg0, dev);
control (step_pointer0, dev);
ok := (status and mask) = 0;
end;

last := last + remcount;
end;

end; <* dodma *>

begin <* body of hdlc *>

with pdescr(n) do
begin
openopzone (zout, own.secret_pointer^(opsem), ref(zout.free), 1, out_pool, 2,7,0,0);
dummy := reservech (dev, first_devno_hdlc + inc - 1, 0);
definetimer (true);
mainsem := ref (sems(sem));

control (dma_reset, dev);
control (trm_control + 0, dev);
control (mode_control + 0, dev);
control (datalength + 0, dev);
control (modem_control + txe + rxe, dev);

channel dev do
repeat

wait (msg, mainsem^);
if testval <> 0 then print_msg (zout, msg, 'after wait:');
case msg^.u4 of
empty_buf:
begin
dodma (
setflh + exp_reom,
setfll + rec_valid,
setfll + 0-0-0, <* dummy *>
read_period,
rec_errors);
if testval <> 0 then print_msg (zout, msg, 'after read:');
return_full (msg, ok);
end;
full_buf:
begin
dodma(
setflh + set_int + set_teom + clear_tsom,
setfll + 0-0-0,
start_xmit + trm_valid,
write_period,
xmit_errors);
if testval <> 0 then print_msg (zout, msg, 'after write:');
return_empty (msg, ok);
end;
end;

until doomsday;
end;
end; <* hdlc driver *>

<* *********************************************************** *>

process gcidriver (n: integer; var pdescr: proc_descrs; var sems: sem_arr);

const
read_period  = 15; <* seconds *>
write_period = 10; <* seconds *>


var
mainsem   : ^ semaphore;
msg       : reference;
dev       : reference;
dummy     : integer;
newlast   : integer;
ok        : boolean;

zout      : zone;
out_pool  : pool 1 of opbuffer;

procedure get_last (var last: integer);
var
dummy : integer;
begin
with pdescr (n) do
begin
repeat
if testval <> 0 then
begin
outtext (zout, 'wait eoi#');
outnl (zout);
end;
controlclr (0, dev);
inword (dummy, dev);
until eoi or (own.timer = 0);
if own.timer = 0 then
last := 0
else
sense (last, 0, dev);
if testval <> 0 then
begin
outtext (zout, 'newlast=#');
outinteger (zout, last, 1);
outnl (zout);
end;
end;
end;

begin <* body of gci-driver *>

with pdescr(n) do
begin
openopzone (zout, own.secret_pointer^(opsem), ref(zout.free), 1, out_pool, 2,7,0,0);
dummy := reservech (dev, first_devno_gci + inc - 2 * ((inc + 1) and 1), 0);
definetimer (true);
mainsem := ref (sems(sem));

channel dev do
repeat <* forever *>

wait (msg, mainsem^);
if testval <> 0 then print_msg (zout, msg, 'after wait:');
case msg^.u4 of

empty_buf:
begin
repeat
own.timer := read_period;

<* get into sync *>
repeat
get_last (newlast);
until (own.timer = 0) or (newlast > 0);

ok := false;
if newlast > 0 then
lock msg as buf: stdpart do
with buf do
begin
controlclr (0, dev);
inwordblock (next, first, newlast or 1, msg, dev);
last := newlast;
ok := next > last;
end;
if testval <> 0 then print_msg (zout, msg, 'after read:');
get_last (newlast);
ok := ok and (not timedout);
until newlast <> -1;

return_full (msg, (newlast = 0) and ok);

end;

full_buf:
begin
own.timer := write_period;
repeat
lock msg as buf: stdpart do
with buf do
begin
controlclr (-1, dev);
controlclr (last, dev);
outwordblock (next, first, last or 1, msg, dev);
<* wait for the last interrupt *>
repeat
sense (dummy, 0, dev);
until ((dummy and 1) = 1) or (own.timer = 0);
ok := next > last;
end;
if testval <> 0 then print_msg (zout, msg, 'after write:');
until ok or (own.timer = 0);
controlclr (0, dev);
return_empty (msg, (not timedout) and ok);
end;

end; <* buffer type *>

until doomsday;

end; <* with pdescr *>
end; <* gcidriver *>

<* *********************************************************** *>

process onteldriver (n: integer; var pdescr: proc_descrs; var sems: sem_arr);

const
<* control-commands to ontel *>
reset       = 0;
ready       = 1;
start_read  = 4;
keyb_locked = 5;
start_write = 8;
end_write   = 10;
answer_void = 32;

<* status_bits from ontel *>
ontel_ready_xmit = 2;

<* dummy delay periods *>
loop_count = 1000;

<* timer-periods *>
read_period  = 15; <* seconds *>
write_period = 10; <* seconds *>

var
request_sem     : ^ semaphore;
reply_sem       : ^ semaphore;
msg             : reference;
ont_dev         : reference;

saved_header    : net_header;
transaction_no  : integer;
ontel_status    : integer;
cpu             : byte;
new_req_demanded: boolean;
accepted        : boolean;
dummy           : integer;

i               : integer;
zout            : zone;
out_pool        : pool 1 of opbuffer;


procedure busy_loop (count: integer);
begin
for count := count downto 0 do <* nothing but wait ... *>;
end;

procedure control_no_ack (c: integer; var dev: reference);
begin
control (c, dev); busy_loop (loop_count);
end;
begin <* body of ontel driver *>
with pdescr(n) do
begin
openopzone (zout, own.secret_pointer^(opsem), ref(zout.free), 1, out_pool, 2,7,0,0);
dummy := reservech (ont_dev, first_devno_ontel + inc - 1, 0);
definetimer (true);
request_sem  := ref (sems(sem));
reply_sem    := ref (sems(sem+1));
transaction_no := 0;

control_no_ack (reset, ont_dev);

channel ont_dev do
repeat <* forever *>

repeat <* until acceptable reply *>

case ctrwaitis (keyb_locked, msg, reply_sem^) of

a_interrupt:
begin <* terminal has timed out *>
sense (ontel_status, 0, ont_dev);
if testval <> 0 then
begin
outtext (zout, 'ontel void#');
outhex (zout, ontel_status, 6);
outnl (zout);
end;
accepted := (ontel_status and ontel_ready_xmit) <> 0;
if accepted then
begin <* ontel wants to send a new transaction *>
<* I don't know, if ontel really wants the following *>
control_no_ack (keyb_locked, ont_dev);
control_no_ack (answer_void, ont_dev);
new_req_demanded := true;
end;
end;

a_semaphore:
begin <* reply has arrived *>
lock msg as buf: stdpart do
with buf, header do
begin
if testval <> 0 then
begin
outtext ( zout, 'reply :#');
outinteger (zout, addr(1), 4);
outinteger (zout, transaction_no, 4);
outnl (zout);
end;
accepted := addr(1) = transaction_no;
if accepted then
begin
saved_header := header;
own.timer := write_period;
controlclr (start_write, ont_dev);
outbyteblock (next, size_stdpart, last, msg, ont_dev);
outword (255, ont_dev);
controlclr (end_write, ont_dev);
sense (ontel_status, 0, ont_dev);
<* maybe retrans, if wanted *>
if timedout then
control_no_ack (reset, ont_dev);
end;
end;
return_empty (msg, true);
end; <* reply *>

end; <* case *>

until accepted;

repeat
controlclr (ready, ont_dev);
sense (ontel_status, 0, ont_dev);
if testval <> 0 then
begin
outtext (zout, 'ontel int#');
outhex (zout, ontel_status, 6);
outnl (zout);
end;
until (ontel_status and ontel_ready_xmit) <> 0;

wait (msg, request_sem^);

lock msg as buf: request_buffer do
with buf, req_head, header do
begin
own.timer := read_period;
controlclr (start_read, ont_dev);
inbyteblock (next, size_stdpart, last, msg, ont_dev);
if timedout then
begin
control_no_ack (reset, ont_dev);
new_req_demanded := true;
end
else
begin
if testval <> 0 then
begin
outtext (zout, 'request:#');
if testval > 1 then
for i := 1 to next - size_stdpart do
begin
if i mod 10 = 1 then if i <> 1 then
begin
outnl (zout);
outfill (zout, sp, 8);
end;
outinteger (zout, ord(req_buf(i)), 4);
end;
outnl (zout);
end;
cpu := ord (req_buf(1));
if (cpu = #h30) or (cpu = #h3f) then
begin <* any rc8000 (or master), i.e. new request *>
new_req_demanded := false;
routing_mode     := new_request;
service_kind     := das_search;
req_buf(1)       := chr (#h31);  <* simulate cpu # 1 *>
end
else
begin <* specific rc8000, i.e. next-request *>
header           := saved_header;
routing_mode     := next_request;
end;
if not new_req_demanded then
last := next - 1;
cur        := 1;
transaction_no := (transaction_no + 1) mod 128;
addr(1)    := transaction_no;
end;
end; <* lock msg *>

if new_req_demanded then signal (msg, request_sem^)
else return_full (msg, true);

until doomsday;

end; <* with pdescr *>
end; <* onteldriver *>

<* *********************************************************** *>

process consdriver (n: integer; var pdescr: proc_descrs; var sems: sem_arr);

const
textlgth = 20;
rc8000_period = 15; <* seconds *>

var
msg            : reference;
emptysem       : ^ semaphore;
fullsem        : ^ semaphore;
i              : integer;
transaction_no : integer;
rep_count      : integer;
saved_last     : integer;
before_first   : boolean;
expecting_answ : boolean;

zin, zout      : zone;
in_pool        : pool 1 of opbuffer;
out_pool       : pool 1 of opbuffer;
in_sem         : semaphore;
act            : activation;
latest_time    : integer;

<* phony function... must be replaced later *>
function spec_waitst (var msg: reference; var sem: semaphore): activation;
begin
repeat
sensesem (msg, sem);
until (own.timer = latest_time) or (not nil(msg));
if nil(msg) then spec_waitst := a_delay
else             spec_waitst := a_semaphore;
end;

label
rep_input;

procedure alarm (text: array (1..textlgth) of char);
var
i: integer;
begin
for i := 1 to textlgth do
if text(i) = '#' then i := textlgth
else outchar (zout, text(i));
outnl (zout);
end;

begin
openopzone (zin, own.secret_pointer^(opsem), ref(in_sem), 1, in_pool, 1,7,0,0);
openopzone (zout, own.secret_pointer^(opsem), ref(zout.free), 1, out_pool, 2,7,0,0);
before_first   := true;
transaction_no := 0;

with pdescr(n) do
begin
emptysem := ref (sems(sem));
fullsem  := ref (sems(sem+1));
definetimer(true);
expecting_answ := false;
rep_count := 0;

repeat <* forever *>

if expecting_answ then
if testval = 0 then
act := waitst (msg, fullsem^)
else
act := spec_waitst (msg, fullsem^)
else
wait (msg, emptysem^);

if not (nil(msg)) then
case msg^.u4 of
empty_buf:
begin
lock msg as buf: request_buffer do
with buf, req_head, header do
rep_input:
begin
if rep_count <= 0 then
begin
opin (zin);  opwait (zin, in_pool);

i := 0;
repeat
if i < size_request then i := i + 1;
inchar (zin, req_buf(i));
until req_buf(i) = nl;
saved_last := i + size_stdpart;

<* check syntax *>
case req_buf(1) of
's':
begin
if i<3 then
begin
alarm ('type more data#');  goto rep_input;
end;
case req_buf(2) of
'a': service_kind := serv_a;
'b': service_kind := serv_b;
'c': service_kind := serv_c;
otherwise
begin
alarm ('no such service#');  goto rep_input;
end;
end;
routing_mode := new_request;  before_first := false;
i := 3;
end;
'p':
begin
if before_first then
begin
alarm ("don't start with p#");  goto rep_input;
end;
routing_mode := next_request;
i := 2;
end;
otherwise
begin
alarm ('only s or p#');  goto rep_input;
end;
end;

rep_count := 0;
while (rep_count <= 3200) and (req_buf(i) in (.'0'..'9'.)) do
begin
rep_count := rep_count * 10 + ord(req_buf(i)) - ord('0');
i := i + 1;
end;

own.timer := 32000;  <* prepare for time-test *>

end; <* if rep_count <= 0 *>

<* send request *>
last := saved_last;
cur := 1;
transaction_no := (transaction_no + 1) mod 128;
addr(1) := transaction_no;
end;

return_full (msg, true);

if testval = 0 then
begin
own.timer := rc8000_period;  <* expect answer soon *>
latest_time := 0;
end
else
latest_time := own.timer - rc8000_period;
expecting_answ := true;
end;

full_buf:
begin <* reply arrived *>
lock msg as buf: reply_buffer do
with buf, reply_head, header do
if addr(1) = transaction_no then
begin
if testval = 0 then
own.timer := 0;
expecting_answ := false;
rep_count := rep_count - 1;
if rep_count <= 0 then
begin
if testval <> 0 then
begin
outtext (zout, 'time was:#');
outinteger (zout, 32000-own.timer,3);
outtext (zout, 'seconds#');
outnl (zout);
own.timer := 0;
end;
for i := 1 to last - size_stdpart do
if reply_buf(i) <> nul then
outchar (zout, reply_buf(i));
outend (zout);
end;
end
else
alarm ('wrong answer#');
return_empty (msg, true);
end;
end

else

begin
alarm ('time out#');
own.timer := 0;
expecting_answ := false;
before_first := true;
rep_count := 0;
end;

until doomsday;

end; <* with pdescr *>
end; <* consdriver *>

<* ****************************************************** *>

process server (n: integer; var pdescr: proc_descrs; var sems: sem_arr);

var
msg      : reference;
answ     : reference;
emptysem : ^ semaphore;
fullsem  : ^ semaphore;
serv     : serv_range;
dist     : dist_range;
rout     : routing_modes;

begin
with pdescr(n) do
begin
emptysem := ref (sems(sem));
fullsem  := ref (sems(sem+1));

wait (answ, emptysem^);
lock answ as data: cap_buffer do
with data, cap_head, header do
begin
for serv := 1 to max_serv do
for dist := 0 to max_dist do cap(serv, dist) := 0;
if testval = 0 then
cap(serv_b, 0) := 1
else
cap(serv_c, 0) := 1;
last         := size_cap_buffer - 1;
routing_mode := inform;
cur          := 1;
end;
return_full (answ, true);

repeat <* forever *>
wait (msg, fullsem^);
lock msg as buf: stdpart do
with buf, header do
rout := routing_mode;

case rout of
reply: ; <* nothing *>
next_request,
new_request:
begin
wait (answ, emptysem^);
lock msg as buf1: request_buffer do
lock answ as buf2: request_buffer do
begin
buf2.req_head.last   := buf1.req_head.last;
buf2.req_head.header := buf1.req_head.header;
buf2.req_buf         := buf1.req_buf;
end;
lock answ as buf: reply_buffer do
with buf, reply_head, header do
begin
routing_mode := reply;
cur          := cur + 1;
end;
return_full (answ, true);
end;
inform: ; <* nothing *>
end;
return_empty (msg, true);

until doomsday;
end;
end; <* server *>

<* ******************************************************* *>

process router (var semvect: system_vector);

const
poll_accuracy = 2; <* number of seconds between poll_update *>
poll_period   = 10; <* seconds *>
no_of_outbufs = 8;

var
zin, zout: zone;
in_pool : pool 1 of opbuffer;
out_pool: pool no_of_outbufs of opbuffer;
local_time : timetype := timetype (0, 0);

var
pdescr   : proc_descrs;
sems     : sem_arr;
children : array (1..max_process) of
record
child : shadow;
end;
code_descr: array (prockinds) of
record
name : alfa;
size : integer;
prio : integer;
inc_count: integer;
end;

<* definition of child images *>
process fpa(n: integer; var pdescr: proc_descrs; var sems: sem_arr);
external;

process hdlc(n: integer; var pdescr: proc_descrs; var sems: sem_arr);
external;

process gci(n: integer; var pdescr: proc_descrs; var sems: sem_arr);
external;

process cons(n: integer; var pdescr: proc_descrs; var sems: sem_arr);
external;

process ontel(n: integer; var pdescr: proc_descrs; var sems: sem_arr);
external;

process bbm(n: integer; var pdescr: proc_descrs; var sems: sem_arr);
external;

process server(n: integer; var pdescr: proc_descrs; var sems: sem_arr);
external;



var
mainsem  : ^ semaphore;
msg      : reference;
test     : boolean;

ports    : array (ports_range) of
record
insem       : ^ semaphore;
outsem      : ^ semaphore;
pp          : 0 .. max_port;  <* index in 'portx' *>
proc_no     : 0 .. max_process; <* index in 'pdescr', used only for printouts *>
outstandings: integer; <* note: offset by one... *>
max_outs    : integer; <* note: offset by one... *>
last_status : byte;
end;

portx     : array (port_range) of
record
deliver_status : boolean;  <* true, when status must be sent *>
busy           : boolean;  <* true, while status is being sent *>
pno            : ports_range;  <* index in 'ports' *>
poll_time      : integer;
end;

capability : array (port_range, serv_range, dist_range) of boolean;

dists      : array (serv_range) of
record
last_p  : port_range;
min_dist: array (port_range) of 0..top_dist+1;
end;

status_pool : pool max_status of cap_buffer;
large_pool  : pool max_largepool of reply_buffer;
small_pool  : pool max_smallpool of request_buffer;

procedure testput (text: alfa; var m: reference);
var
i : integer;
begin
print_msg (zout, m, text);
lock m as buf: stdpart do
with buf, header do
begin
outinteger (zout, receiver, 7);
outinteger (zout, routing_mode, 2);
outinteger (zout, service_kind, 2);
outinteger (zout, cur, 3);
if pdescr(0).testval > 1 then
for i := 1 to cur do outinteger (zout, -addr(i), 1);
end;
outnl (zout);
end;

procedure alarm (text: alfa);
begin
outtext (zout, '*** error: #');
outtext (zout, text);
outnl (zout);
exception (0);
end;

procedure clean_pool (var poo: pool 1);
var msg: reference;
begin
while openpool (poo) do
begin
alloc (msg, poo, mainsem^);
case msg^.u4 of
empty_buf: return_full  (msg, false);
full_buf : return_empty (msg, false);
end;
end;
end;

procedure clean_sem (sem: ^ semaphore);
var
msg : reference;
begin
sensesem (msg, sem^);
while not nil(msg) do
begin
release (msg);
sensesem (msg, sem^);
end;
end;

procedure kill_all (from, upto: integer);
var
msg    : reference;
dummy  : integer;
p      : ports_range;
begin
if upto > max_process then upto := max_process;
if (from > 0) and (from <= max_process) then
repeat
with children(from) do
if not nil(child) then
begin
remove(child);
for p := 1 to max_ports do
with ports(p) do
if proc_no = from then
begin
clean_sem (insem);
clean_sem (outsem);
end;
end;
from := from + 1;
until from > upto;

<* provoke cleanup of buffers *>
dummy := reservech (msg, 0, 0);

clean_pool (small_pool);
clean_pool (large_pool);

end;  <* kill_all *>

procedure break_all (cause, from, upto: integer);
begin
if upto > max_process then upto := max_process;
if (from > 0) and (from <= max_process) then
repeat
with children(from) do
if not nil(child) then break (child, cause);
from := from + 1;
until from > upto;
end;

procedure run_all (from, upto: integer);
var
res : integer;
name_n : alfa;
i, n   : integer;
begin
kill_all (from, upto);
if upto > max_process then upto := max_process;
if (from > 0) and (from <= max_process) then
repeat
with children(from), pdescr(from), code_descr(kind) do
begin
name_n := name;
i := alfalength;
n := inc;
repeat
name_n(i) := chr (n mod 10 + ord('0'));
n := n div 10;
i := i - 1;
until n = 0;
repeat
name_n(i) := '_';
i := i-1;
until name_n(i) <> sp;
case kind of
fpa_kind   : res := create (name_n, fpa   (from, pdescr, sems), child, size);
hdlc_kind  : res := create (name_n, hdlc  (from, pdescr, sems), child, size);
gci_kind   : res := create (name_n, gci   (from, pdescr, sems), child, size);
cons_kind  : res := create (name_n, cons  (from, pdescr, sems), child, size);
ontel_kind : res := create (name_n, ontel (from, pdescr, sems), child, size);
bbm_kind   : res := create (name_n, bbm   (from, pdescr, sems), child, size);
server_kind: res := create (name_n, server(from, pdescr, sems), child, size);
end;
if res <> 0 then alarm ('create#');
start (child, prio);
end;
from := from + 1;
until from > upto;
end;

procedure test_all (t, from, upto: integer);
begin
if upto > max_process then upto := max_process;
if (from > -1) and (from <= max_process) then
repeat
with pdescr(from) do
testval := t;
from := from + 1;
until from > upto;
end;

procedure print_portx (from, upto: integer);
begin
if upto > max_port then upto := max_port;
if (from > 0) and (from <= max_port) then
begin
outtext (zout, 'p  port #');
outtext (zout, 'poll  st.#');
outtext (zout, '   busy#');
outnl (zout);
repeat
outinteger (zout, from, 2);
outchar (zout, ':');
with portx(from) do
begin
outinteger (zout, pno, 4);
outinteger (zout, poll_time, 5);
if deliver_status or busy then
begin
if deliver_status then outtext (zout, ' true #')
else                   outtext (zout, ' false#');
if busy then outtext (zout, ' true#')
else         outtext (zout, ' false#');
end;
end;
outnl (zout);
from := from + 1;
until from > upto;
end;
end;

procedure print_ports (from, upto: integer);
begin
if upto > max_ports then upto := max_ports;
if (from > 0) and (from <= max_ports) then
begin
outtext (zout, ' p  outs max#'); outtext (zout, ' inp outp#');
outnl (zout);
repeat
outinteger (zout, from, 2);
outchar (zout, ':');
with ports(from) do
begin
outinteger (zout, outstandings - 1, 4);
outinteger (zout, max_outs - 1, 4);
outinteger (zout, proc_no, 4);
if insem <> outsem then
outinteger (zout, proc_no+1, 4);
if last_status <> result_ok then
outtext (zout, ' down#');
end;
outnl (zout);
from := from + 1;
until from > upto;
end;
end;

procedure print_proc (from, upto: integer);
begin
if upto > max_process then upto := max_process;
if (from > 0) and (from <= max_process) then
begin
outtext (zout, ' i  name    #');
outtext (zout, '     #');
outtext (zout, ' inc sem tst#');
outtext (zout, ' state#');
outnl (zout);
repeat
outinteger (zout, from, 2);
outchar (zout, ':');  outchar (zout, sp);

with pdescr(from), children(from) do
begin
outtext (zout, code_descr(kind).name);
outinteger (zout, inc, 4);
outinteger (zout, sem, 4);
outinteger (zout, testval, 4);
if nil(child) then outtext (zout, ' removed#');
end;
outnl (zout);
from := from + 1;
until from > upto;
end;
end;

procedure write_all (from, upto: integer);
begin
if upto > max_sem then upto := max_sem;
if (from > -1) and (from <= max_sem) then
begin
outtext (zout, 'sem  state#');
outnl (zout);
repeat
outinteger(zout, from, 3);
if open(sems(from)) then     outtext (zout, '  open#')
else
if locked(sems(from)) then outtext (zout, '  locked#')
else                       outtext (zout, '  passive#');
outnl (zout);
from := from + 1;
until from > upto;
end;
end;

procedure print_cap (from, upto: integer);
var
p    : port_range;
serv : serv_range;
dist : dist_range;
begin
if (upto <= 0) or (upto > max_port) then upto := max_port;
if from <= 0 then from := 1;
if from <= max_port then
for p := from to upto do
begin
outtext (zout, 'port no =#');
outinteger (zout, p, 2);
outtext (zout, ', outstand.=#');
with portx(p), ports(pno) do
outinteger (zout, outstandings, 2);
outnl (zout);
for serv := 1 to max_serv do
begin
outtext (zout, 'service #');
outchar (zout, chr(64 + serv));
outchar (zout, ',');
outinteger (zout, dists(serv).min_dist(p),2);
outchar (zout, ':');
for dist := 0 to max_dist do
if capability (p, serv, dist) then
outtext (zout, ' * #')
else
outtext (zout, ' . #');
outnl (zout);
end;
end;
end;

procedure conversation;
var
ch    : char;
val,
from,
upto  : integer;

procedure read_from_to;
begin
ininteger (zin, from); ininteger (zin, upto);
end;

procedure read_val_from_to;
begin
ininteger (zin, val); read_from_to;
end;

procedure print_f_t (text: alfa);
begin
outtext (zout, text);
outtext (zout, ' <from> <to>#');
outnl (zout);
end;

procedure print_v_f_t (text: alfa);
begin
outtext (zout, text);
outtext (zout, ' <value>#');
outtext (zout, ' <from> <to>#');
outnl (zout);
end;

begin
opanswer (msg, zin); opwait (zin, in_pool);

repeat <* next command *>

repeat inchar (zin, ch) until ch <> sp;

case ch of
'r':  <* run <from> <to> *>
begin
read_from_to; run_all (from, upto);
end;
'b':  <* break <val> <from> <to> *>
begin
read_val_from_to; break_all (val, from, upto);
end;
'k':  <* kill <from> <to> *>
begin
read_from_to; kill_all (from, upto);
end;
't':  <* test <val> <from> <to> *>
begin
read_val_from_to; test_all (val, from, upto);
end;
'x': <* print portx <from> <to> *>
begin
read_from_to;  print_portx (from, upto);
end;
'p': <* print procs <from> <to> *>
begin
read_from_to;  print_ports (from, upto);
end;
'i': <* print pdescr (incarnations) <from> <to> *>
begin
read_from_to;  print_proc (from, upto);
end;
'w':  <* write <from> <to> *>
begin
read_from_to; write_all (from, upto);
end;
'c':  <* capability <from> <to> *>
begin
read_from_to;  print_cap (from, upto);
end;
'd':  <* date <hour> <min> <sec> *>
begin
read_val_from_to;
if (val >= 0) and (val < 24) and
(from >= 0) and (from < 60) and
(upto >= 0) and (upto < 60) then
if val + from + upto > 0 then
with local_time do
begin
hours := val;
seconds := from * 60 + upto;
end;
outtime (zout, local_time);
outnl (zout);
end;
'?',
'h': <* help *>
begin
print_f_t   ('r: run#');
print_v_f_t ('b: break#');
print_f_t   ('k: kill#');
print_v_f_t ('t: test#');
print_f_t   ('x: listportx#');
print_f_t   ('p: listports#');
print_f_t   ('i: listpdescr#');
print_f_t   ('w: listsems#');
print_f_t   ('c: list capab.#');
outtext (zout, 'd: date #');
outtext (zout, '<hour> <min>#');
outtext (zout, ' <sec>#');
outnl (zout);
end;
otherwise <* blind command *>
end;

repeat inchar (zin, ch) until (ch=nl) or (ch=';');

until ch=nl;

opin (zin);
end; <* conversation *>

procedure initialize;
var
i, p, inc_no, port_no, sem_no: integer;
serv : serv_range;
dist : dist_range;

procedure def_code (k: prockinds; var p: process_descriptor;
n: alfa; s: integer; pr: minpriority..maxpriority);
var
dummy : integer;
begin
with code_descr(k) do
begin
name := n;
size := s;
prio := pr;
inc_count := 0;
end;
dummy := link (n, p);
end;

procedure def_inc (k: prockinds);
begin
with pdescr(inc_no) do
with code_descr(k) do
begin
kind    := k;
inc_count := inc_count + 1;
inc     := inc_count;
testval := 0;
sem     := sem_no;
end;
inc_no := inc_no + 1;
end;

procedure def_port (insems: integer; max: integer; erlang: boolean);
begin
with ports (port_no) do
begin
insem        := ref (sems(sem_no));
outstandings := 1;       <* note: offset by one... *>
max_outs     := max + 1; <* note: offset by one... *>
last_status  := result_ok;
proc_no      := inc_no - 1;
sem_no       := sem_no + insems;
if erlang then
begin
pp := p;
with portx(p) do
begin
deliver_status := false;
busy           := false;
pno            := port_no;
poll_time      := poll_period;
end;
p := p + 1;
end
else
pp := 0;
end;
end;

procedure out_port (outsems: integer);
begin
with ports (port_no) do
if outsems <> 0 then
outsem := ref (sems(sem_no))
else
outsem := insem;
sem_no := sem_no + outsems;
port_no := port_no + 1;
end;

procedure alloc_bufs (n: integer; var p: pool 1);
var
msg   : reference;
i     : integer;
begin
for i := 1 to n do
begin
if not openpool (p) then alarm ('no bufs#');
alloc (msg, p, mainsem^);
lock msg as buf: stdpart do
with buf, header do
begin
receiver := port_no;
first    := first_buffer;
end;
msg^.u3 := 0;
return_empty (msg, false);
end;
end;

procedure def_end;
begin
if p       <> max_port    + 1 then alarm ('max_port#');
if inc_no  <> max_process + 1 then alarm ('max_process#');
if port_no <> max_ports   + 1 then alarm ('max_ports#');
if sem_no  <> max_sem     + 1 then alarm ('max_sem#');

if openpool (small_pool)       then alarm ('smallpool#');
if openpool (large_pool)       then alarm ('largepool#');
end;

begin <* body of initialize *>

mainsem := ref (sems(0));
definetimer (true);
openopzone (zin , semvect(operatorsem), mainsem,        1, in_pool,  1,7,0,0);
openopzone (zout, semvect(operatorsem), ref(zout.free), no_of_outbufs, out_pool, 2,7,0,0);
opin (zin);

outtext (zout, 'welcome...#');
outnl (zout);

def_code (fpa_kind   , fpa    , fpa_name    , fpa_size    , fpa_prio);
def_code (hdlc_kind  , hdlc   , hdlc_name   , hdlc_size   , hdlc_prio);
def_code (gci_kind   , gci    , gci_name    , gci_size    , gci_prio);
def_code (cons_kind  , cons   , cons_name   , cons_size   , cons_prio);
def_code (ontel_kind , ontel  , ontel_name  , ontel_size  , ontel_prio);
def_code (bbm_kind   , bbm    , bbm_name    , bbm_size    , bbm_prio);
def_code (server_kind, server , server_name , server_size , server_prio);

for p := 1 to max_port do
for serv := 1 to max_serv do
for dist := 0 to max_dist do
capability (p, serv, dist) := false;

for i := 1 to max_serv do
with dists(i) do
begin
last_p := max_port;
for p := 1 to max_port do min_dist(p) := top_dist + 1;
end;

p       := 1;
inc_no  := 1;
port_no := 1;
sem_no  := 1;

for i := 1 to no_of_fpa do
begin
def_inc (fpa_kind); def_port (1, outbufs_fpa, true); alloc_bufs (inbufs_fpa, large_pool);
def_inc (fpa_kind); out_port (1);
end;

for i := 1 to no_of_hdlc do
begin
def_inc (hdlc_kind); def_port (1, outbufs_hdlc, true); alloc_bufs (inbufs_hdlc, large_pool);
def_inc (hdlc_kind); out_port (1);
end;

for i := 1 to no_of_gci do
begin
def_inc (gci_kind); def_port (1, outbufs_gci, true); alloc_bufs (inbufs_gci, large_pool);
def_inc (gci_kind); out_port (1);
end;

for i := 1 to no_of_cons do
begin
def_inc (cons_kind); def_port (1, 1, false); alloc_bufs (inbufs_cons, small_pool);
out_port (1);
end;

for i := 1 to no_of_ontel do
begin
def_inc (ontel_kind); def_port (1, 1, false); alloc_bufs (inbufs_ontel, small_pool);
out_port (1);
end;

for i := 1 to no_of_bbm do
begin
def_inc (bbm_kind); def_port (1, outbufs_bbm, true); alloc_bufs (inbufs_bbm, large_pool);
out_port (0);
end;

for i := 1 to no_of_server do
begin
def_inc (server_kind); def_port (1, outbufs_server, true); alloc_bufs (inbufs_server, large_pool);
out_port (1);
end;

def_end;

test_all (0, 0, 0);  <* set test-pattern for router itself *>
run_all (1, max_process);

end; <* initialize *>

procedure deliver (var m: reference; p: integer);
begin
m^.u3 := p;
if p = 0 then
return_empty (msg, true)
else
begin
if test then testput ('sent#', m);
with ports(p) do
begin
signal (m, outsem^);
outstandings := outstandings + 1;
if pp <> 0 then
with portx(pp) do
poll_time := poll_period;
end;
end;
end;

function get_capability (pno: ports_range): boolean;
var
new_cap : boolean;
min     : integer;
p       : port_range;
serv    : serv_range;
dist    : dist_range;
begin
get_capability := false;
with ports(pno) do p := pp;
lock msg as data: cap_buffer do
for serv := 1 to max_serv do
begin
min := top_dist;
for dist := 0 to max_dist do
begin
new_cap := data.cap(serv, dist) = 1;
if capability (p, serv, dist) <> new_cap then
begin <* change *>
capability (p, serv, dist) := new_cap;
get_capability := true;
end;
if new_cap then
if min = top_dist then min := dist;
end;
with dists(serv) do
min_dist (p) := min + 1;
end;
return_empty (msg, true);
end; <* get_capability *>

function clear_capability (p: port_range): boolean;
var
serv: serv_range;
dist: dist_range;
begin
clear_capability := false;
for serv := 1 to max_serv do
begin
for dist := 0 to max_dist do
begin
if capability (p, serv, dist) then
clear_capability := true;
capability (p, serv, dist) := false;
end;
with dists(serv) do
min_dist (p) := top_dist + 1;
end;
end;

procedure send_capabilities;
var
i, p   : port_range;
serv   : serv_range;
dist   : dist_range;
sum    : boolean;
msg    : reference;
begin
for p := 1 to max_port do
with portx(p), ports(pno), children(proc_no) do
if deliver_status then
if not busy then
if not nil (child) then
if openpool (status_pool) then
begin
alloc (msg, status_pool, mainsem^);
deliver_status := false;
busy           := true;
lock msg as buf: cap_buffer do
with buf, cap_head, header do
begin
first        := first_buffer;
last         := size_cap_buffer - 1;
routing_mode := inform;
receiver     := -pno;
cur          := 1;
addr(cur)    := pno;
for serv := 1 to max_serv do
for dist := 0 to max_dist do
begin
sum := false;
if dist <> 0 then
for i := 1 to max_port do
if i <> p then
sum := sum or capability (i, serv, dist - 1);
cap(serv, dist) := ord(sum);
end;
end;
msg^.u1 := output_msg;
msg^.u2 := result_answer;
msg^.u4 := full_buf;
deliver (msg, pno);
end;
end;

function find_port (serv: serv_range): 0..max_ports;
var
port_1   , port_2    : integer;
mincost_1, mincost_2 : integer;
cost                 : integer;
i, p                 : integer;
begin
port_1 := 0;  mincost_1 := maxint;
port_2 := 0;  mincost_2 := maxint;

with dists(serv) do
begin
p := last_p;
for i := 1 to max_port do
begin
p := p mod max_port + 1;
if min_dist(p) <= top_dist then
with portx(p), ports(pno) do
begin
cost := min_dist(p) * outstandings;
if outstandings <= max_outs then
begin
if cost < mincost_1 then
begin
port_1 := p; mincost_1 := cost;
end;
end
else
begin
if cost < mincost_2 then
begin
port_2 := p; mincost_2 := cost;
end;
end;
end;
end;
if port_1 = 0 then port_1 := port_2;
if port_1 <> 0 then
begin
last_p := port_1;
port_1 := portx(port_1).pno;
end;
end;
find_port := port_1;
end;

procedure status_change (p: ports_range; new_status: byte);
var
i : port_range;
begin
with ports(p) do
begin
last_status := new_status;
if pp <> 0 then
if new_status = result_ok then
with portx(pp) do
begin
deliver_status := true;
send_capabilities;
end
else
if clear_capability (pp) then
begin
for i := 1 to max_port do
if i <> pp then
with portx (i) do
deliver_status := true;
send_capabilities;
end;
end;
outtime (zout, local_time);
outtext (zout, ' *** port #');
outinteger (zout, p, 2);
if new_status = result_ok then
outtext (zout, ' comming up#')
else
outtext (zout, ' gone down#');
outnl (zout);
end;

var
rec  : integer;
p    : integer;
rout : routing_modes;

begin <* main program of router *>
initialize;
own.timer := poll_accuracy;
with pdescr (0) do
repeat <* forever *>

case waitst (msg, mainsem^) of

a_delay:
begin <* time for updating poll_timers *>
own.timer := poll_accuracy;
with local_time do
begin
seconds := seconds + poll_accuracy;
if seconds >= 60*60 then
begin
seconds := seconds - 60*60;
hours   := hours + 1;
if hours >= 24 then
hours := 0;
end;
end;
for p := 1 to max_port do
with portx(p) do
if poll_time > 0 then
begin
poll_time := poll_time - poll_accuracy;
if poll_time <= 0 then
deliver_status := true;
end;
send_capabilities;
end;

a_semaphore:
begin
test := testval <> 0;
if ownertest (in_pool, msg) then conversation
else
case msg^.u4 of
empty_buf:
begin
if test then testput ('empty#', msg);
if msg^.u3 <> 0 then
begin
with ports(msg^.u3) do
begin
outstandings := outstandings - 1;
if last_status <> msg^.u2 then
status_change (msg^.u3, msg^.u2);
end;
msg^.u3 := 0;
end;
lock msg as buf: stdpart do
begin
buf.last := msg^.size * 2 - 1;
rec := buf.receiver;
end;
if rec < 0 then
begin <* inform-buffer has returned, use it again *>
with ports(-rec), portx(pp) do
busy := false;
release (msg);
send_capabilities;
end
else
signal (msg, ports(rec).insem^);
end;
full_buf:
if msg^.u3 <> 0 then
return_empty (msg, false)  <* driver was removed, and message returned *>
else
begin <* real message to the router *>
if test then testput ('got #', msg);
lock msg as buf: stdpart do
with buf, header do
begin
rec  := receiver;
with ports(rec) do
if last_status <> msg^.u2 then
status_change (rec, msg^.u2);
if msg^.u2 = result_ok then
begin
rout := routing_mode;
case rout of
reply        : cur := cur - 2;
next_request : cur := cur + 2;
new_request  :
begin
cur := cur + 2;
addr (cur-1) := rec;
addr (cur)   := find_port (service_kind);
end;
inform       : <* empty *>
end;
if cur > max_dist*2 then p := 0
else p := addr(cur);
end
else
begin <* bad status *>
rout := reply;
p    := 0;
end;
end; <* lock *>
case rout of
reply,
next_request,
new_request: deliver (msg, p);
inform:
begin
if get_capability (rec) then
begin
for p := 1 to max_port do
with portx(p), ports(pno) do
deliver_status := true;
send_capabilities;
end;
end;
end; <* case *>

end; <* full buf *>

end; <* case buffer-type *>
end;

end; <* case timeout-or-message *>

until doomsday;

end; <* router *>

<* ************************************************** *>

process s (var sem_vector: system_vector);

type
adamtype = record
name1 : alfa;
name2 : alfa;
aux1  : integer;
end;
opbuffer = record
first,last,next : integer;
name : alfa;
go      : array (16..17) of char;
databuf : array (20..97) of char;
end;

var
msg      : reference;
mainsem  : semaphore;
p        : pool 1 of opbuffer;
re_run   : boolean;

procedure adam (fct: byte; i: integer);
begin
msg^.u1 := fct;
lock msg as buf: adamtype do
with buf do
begin
name1 := 'router';
name2 := 'r ';
aux1  := i;
end;
signal (msg, sem_vector(adamsem)^);
wait (msg, mainsem);
end;

begin
(*$5 10 512*)  <* default create-size := 512 words *>
alloc (msg, p, mainsem);

adam (1 <* link*>   , 0-0-0);
repeat
adam (2 <* create *>, 2000);
adam (3 <* start *> , 0);

repeat

msg^.u1 := 1;
lock msg as buf: opbuffer do
with buf do
begin
first := 18;
last  := 97;
name  := 's ';
go    := '**';
end;
signal (msg, sem_vector (operatorsem)^);
wait (msg, mainsem);

lock msg as buf: opbuffer do
with buf do
re_run := go = 'go';

until re_run;

adam (5 <* remove *>, 0-0-0);

until false;
end;
.
▶EOF◀