mirror of
https://github.com/PDP-10/its.git
synced 2026-02-15 12:26:27 +00:00
SYSENG;FDDEFS (already in SYSTEM), SYSENG;NETWRK (already in SYSNET), and SYSTEM;DMPCPY (already in SYSENG).
645 lines
14 KiB
Plaintext
Executable File
645 lines
14 KiB
Plaintext
Executable File
; -*- Midas -*-
|
||
|
||
title NETIME - Get the time from the network.
|
||
|
||
rdtim=:702200,, ; KS10 clock instructions.
|
||
wrtim=:702600,,
|
||
clk==:500 ; PD clock on KA10s and MX-KL
|
||
|
||
a=:1
|
||
b=:2
|
||
c=:3
|
||
d=:4
|
||
e=:5
|
||
t=:6
|
||
tt=:7
|
||
|
||
p=:17
|
||
|
||
ttyoch==:1
|
||
netoch==:2
|
||
nnetch==:<20-netoch>/2
|
||
netich==:netoch+nnetch
|
||
utilch==:2
|
||
|
||
call=:pushj p,
|
||
return=:popj p,
|
||
save==:push p,
|
||
rest==:pop p,
|
||
flose=:.lose %lsfil
|
||
slose=:.lose %lssys
|
||
pause=:.break 16,100000
|
||
quit=:.logout 1,
|
||
tyo=:.iot ttyoch,
|
||
|
||
define conc foo,bar
|
||
foo!bar!termin
|
||
|
||
%f==:1,,525252 ; Flags in LH(0)
|
||
%fhsts==:000002 ; Host table loaded?
|
||
%ftime==:000004 ; Timer
|
||
|
||
repeat nnetch, conc %fnet,\.rpcnt,==:1_<netich+.rpcnt>
|
||
|
||
netmsk==:<1_nnetch-1>_netich
|
||
|
||
define syscall name,args
|
||
.call [setz ? sixbit /name/ ? args(400000)]
|
||
termin
|
||
|
||
popbj1: rest b
|
||
popj1: aosa (p)
|
||
popbj: rest b
|
||
cpopj: return
|
||
|
||
datime"$$svng==:1
|
||
datime"$$out==:1
|
||
datime"$$abs==:1
|
||
.insrt dsk:syseng;datime >
|
||
|
||
format"$$time==:1
|
||
format"datime==:datime"twdasc
|
||
format"time==:datime"timasc
|
||
format"date==:datime"datasc
|
||
format"$$pcode==:1
|
||
.insrt dsk:syseng;format >
|
||
|
||
outstr: syscall siot,[movei ttyoch ? a ? b]
|
||
slose
|
||
return
|
||
|
||
define format &string&,args
|
||
call [
|
||
call $format
|
||
.zzz.==-1
|
||
irp arg,,[args]
|
||
save arg
|
||
.zzz.==.irpcnt
|
||
termin
|
||
hrroi a,[ascii string]
|
||
movei b,.length string
|
||
movni c,.zzz.+1
|
||
jrst format"format]
|
||
termin
|
||
|
||
$forma: save a
|
||
save b
|
||
save c
|
||
save [.+2]
|
||
jrst @-4(p)
|
||
rest c
|
||
rest b
|
||
rest a
|
||
rest (p)
|
||
return
|
||
|
||
; Hosts are arranged first into three groups by approximate speed and
|
||
; reliability. Each group is in alphabetical order. Presumably there is
|
||
; little correlation between a machine's speed and reliability, and the
|
||
; alphabetical position of its name.
|
||
|
||
hosts:
|
||
|
||
; Ask the reliable ITS machines first. They are all on subnet 6 and tend
|
||
; to answer quickly.
|
||
|
||
<(sixbit /AI/)>,,[asciz "AI"]
|
||
<(sixbit /MC/)>,,[asciz "MC"]
|
||
<(sixbit /ML/)>,,[asciz "ML"]
|
||
|
||
; File servers tend to be up. Approximately in the order that they seem
|
||
; likely to come up after a mass shutdown.
|
||
|
||
[asciz "REAGAN"]
|
||
[asciz "ZERMATT"]
|
||
[asciz "GOLDILOCKS"]
|
||
[asciz "LIVE-OAK"]
|
||
[asciz "PYGMALION"]
|
||
[asciz "HEPHAESTUS"]
|
||
|
||
; Ordinary hosts. Alphabetical order.
|
||
|
||
[asciz "BIGBOOTE"]
|
||
[asciz "CROSBY"]
|
||
[asciz "DIALUP-CHAOS"]
|
||
[asciz "GAAK"]
|
||
[asciz "MINTAKA"]
|
||
[asciz "OTIS"]
|
||
[asciz "PIGPEN"]
|
||
[asciz "SAFFRON"]
|
||
[asciz "SINATRA"]
|
||
|
||
; Unreliable hosts start here. Putting hosts that tend to not answer at
|
||
; the end keeps them from acting as a bottleneck. (It also gives them less
|
||
; time to respond...)
|
||
|
||
<(sixbit /MD/)>,,[asciz "MD"]
|
||
[asciz "GOLEM"]
|
||
[asciz "LSD"]
|
||
[asciz "EMACK-AND-BOLIOS"]
|
||
|
||
nhosts==:.-hosts
|
||
|
||
;;; Parameters that can be patched:
|
||
|
||
setp: -1 ; 0 => don't actually set the time.
|
||
|
||
wait: 20.*60. ; Wait 20 seconds polling other hosts.
|
||
0 ? 0 ? 0 ; Zeros for .REALT just in case...
|
||
|
||
numerq: 2 ; Ceiling of 2/3 of the hosts that respond
|
||
denomq: 3 ; must agree on the time.
|
||
|
||
minq: 4 ; Insist on at least 4 hosts with times in
|
||
; agreement.
|
||
|
||
spread: 400. ; Times agree if they differ by less than
|
||
; 400 seconds (6 mins 40 secs)
|
||
|
||
days: 3 ; If machine looks like it was down for
|
||
; this many days, then require a human to
|
||
; set the time.
|
||
|
||
filesn: sixbit /DRAGON/ ; The creation date of this file is some
|
||
filen1: sixbit /DRAGON/ ; indication of what time the system last
|
||
filen2: sixbit /HOARD/ ; thought it was.
|
||
|
||
.scalar lstime ; Creation date of above file.
|
||
|
||
.insrt dsk:system;chsdef >
|
||
.vector opkt(%cpmxw) ; Output packet
|
||
.vector ipkt(%cpmxw) ; Input packet
|
||
|
||
.vector state(nnetch) ; What each net channel is working on.
|
||
|
||
.vector times(nhosts) ; The time reported by each host.
|
||
; In seconds since January 1, 1900, GMT.
|
||
|
||
.vector atimes(nhosts) ; The time we believe the host looked at
|
||
; his clock. In 60ths of a second since
|
||
; system was booted.
|
||
|
||
.scalar count ; The number of outstanding time requests.
|
||
|
||
lpdl==:100.
|
||
.vector pdl(lpdl) ; The usual.
|
||
|
||
.scalar itsnam ; The name of this machine in SIXBIT.
|
||
|
||
usrvar: sixbit /OPTION/ ? tlo %opint\%opopc
|
||
sixbit /MASK/ ? move [%pirlt\%piioc\%piwro\%pimpv\%pilos\%piilo]
|
||
sixbit /MSK2/ ? movei netmsk
|
||
lusrvar==:.-usrvar
|
||
|
||
go: .pdtime b,
|
||
.suset [.rsuppro,,a]
|
||
came b,[-1]
|
||
jumpl a,[quit]
|
||
movsi b,(sixbit /T00/)
|
||
skipl a
|
||
movsi b,(sixbit /TTY/)
|
||
syscall open,[[.uao\%tjdis,,ttyoch] ? b]
|
||
skipa
|
||
jrst go1
|
||
movei tt,5*30.
|
||
.sleep tt,
|
||
jrst go
|
||
|
||
go1: move tt,[%rlfls\%rlset,,wait]
|
||
.realt tt,
|
||
movsi 0,netmsk ; initial flags
|
||
move p,[-lpdl,,pdl-1]
|
||
move tt,[-lusrvar,,usrvar]
|
||
syscall usrvar,[movei %jself ? tt]
|
||
slose
|
||
syscall sstatu,[repeat 6,[ ? movem itsnam]]
|
||
slose
|
||
syscall open,[[.uai\%donrf,,utilch] ? [sixbit /DSK/]
|
||
filen1 ? filen2 ? filesn]
|
||
jrst nofile
|
||
syscall rfdate,[movei utilch ? movem lstime]
|
||
flose
|
||
.close utilch,
|
||
irps sym,,[ka10p,kl10p,ks10p,pdtime,fyear]
|
||
.scalar sym
|
||
move tt,[squoze 0,sym]
|
||
.eval tt,
|
||
.lose
|
||
movem tt,sym
|
||
termin
|
||
move tt,[squoze 0,ksfreq]
|
||
.eval tt,
|
||
movei tt,<<1000._12.>+30.>/60.
|
||
movem tt,ksfreq
|
||
|
||
movei a,netgo
|
||
movem a,state+0
|
||
move tt,[state+0,,state+1]
|
||
blt tt,state+nnetch-1
|
||
setzm times+0
|
||
move tt,[times+0,,times+1]
|
||
blt tt,times+nhosts-1
|
||
movei a,%corfc
|
||
dpb a,[$cpkop opkt]
|
||
movei a,4
|
||
dpb a,[$cpknb opkt]
|
||
move a,[.byte 8 ? "T ? "I ? "M ? "E]
|
||
movem a,opkt+%cpkdt
|
||
setzm count
|
||
hrloi c,-1-nhosts ; C: aobjn into hosts
|
||
loop: tlnn netmsk\%ftime
|
||
.hang
|
||
tlze %ftime
|
||
jrst timout
|
||
jffo .+1
|
||
movei b,17.-netich
|
||
sub b,a ; B: current net channel
|
||
move t,state(b)
|
||
hlrz d,t ; D: usually current host
|
||
jrst (t)
|
||
|
||
tsint:
|
||
loc 42
|
||
-ltsint,,tsint
|
||
loc tsint
|
||
0,,p
|
||
%piioc ? 0 ? 0 ? 0 ? iocint ; synchronous
|
||
%pirlt ? 0 ? 0 ? 0 ? timint
|
||
0 ? netmsk ? 0 ? 0 ? netint
|
||
%piwro\%pimpv\%pilos\%piilo ? 0 ? -1 ? -1 ? badint
|
||
ltsint==:.-tsint
|
||
|
||
dismis: setz ? sixbit /DISMIS/ ? setz p
|
||
|
||
badint: .close ttyoch, ; Close TTY channel to let hacker log in
|
||
.value ; Leave a corpse
|
||
|
||
netint: tso -3(p)
|
||
.call dismis
|
||
slose
|
||
|
||
timint: tlo %ftime
|
||
.call dismis
|
||
slose
|
||
|
||
iocint: save t
|
||
aos -1(p)
|
||
hrrz t,-1(p)
|
||
caie t,iocok+1
|
||
.lose
|
||
rest t
|
||
.call dismis
|
||
slose
|
||
|
||
netgo: aobjp c,nomore
|
||
hllz a,hosts(c)
|
||
camn a,itsnam ; Is this us?
|
||
jrst netgo
|
||
hrrz a,hosts(c)
|
||
call look
|
||
jrst netgo ; Must be gone or something?
|
||
dpb a,[$cpkda opkt]
|
||
syscall chaoso,[movei netich(b) ? movei netoch(b)]
|
||
jrst netgo ; Chaosnet full? Broken?
|
||
tdz netbit(b)
|
||
syscall pktiot,[movei netoch(b) ? movei opkt]
|
||
slose
|
||
.rdtime tt,
|
||
movem tt,atimes(c) ; Begin our wait
|
||
hrrzi a,netin
|
||
hrli a,(c)
|
||
movem a,state(b)
|
||
aos count
|
||
jrst loop
|
||
|
||
netin: sos count
|
||
iocok:: syscall pktiot,[movei netich(b) ? movei ipkt]
|
||
jrst netgo ; IOC ints return to here.
|
||
.rdtime tt,
|
||
addm tt,atimes(d) ; End our wait (computes average in 60ths)
|
||
ldb t,[$cpkop ipkt]
|
||
caie t,%coans
|
||
jrst netgo
|
||
ldb t,[341000,,ipkt+%cpkdt]
|
||
dpb t,[001000,,times(d)]
|
||
ldb t,[241000,,ipkt+%cpkdt]
|
||
dpb t,[101000,,times(d)]
|
||
ldb t,[141000,,ipkt+%cpkdt]
|
||
dpb t,[201000,,times(d)]
|
||
ldb t,[041000,,ipkt+%cpkdt]
|
||
dpb t,[301000,,times(d)]
|
||
jrst netgo
|
||
|
||
netbit: repeat nnetch, 1_<netich+.rpcnt>,,0
|
||
|
||
nomore: syscall close,[movei netich(b)]
|
||
slose
|
||
syscall close,[movei netoch(b)]
|
||
slose
|
||
tdz netbit(b)
|
||
movei a,[ jfcl ? .lose ]
|
||
movem a,state(b)
|
||
skipe count
|
||
jrst loop
|
||
jrst setime
|
||
|
||
.vector sorted(nhosts) ; Sorted indices of times.
|
||
|
||
timout::
|
||
setime: skipn setp
|
||
jrst sort
|
||
setoi tt,
|
||
.iotlsr tt,
|
||
;; Set time relative to -now-.
|
||
skipe ks10p
|
||
rdtim kstime
|
||
skipn ks10p
|
||
datai clk,clktim
|
||
sort: .rdtime e,
|
||
lsh e,1 ; E: system time in 60ths
|
||
addi e,30. ; (for rounding later)
|
||
setzi b, ; B: # entries sorted so far
|
||
movsi a,-nhosts ; A: aobjn into TIMES
|
||
skipn c,times(a) ; C: time
|
||
sortlp: aobjn a,.-1 ; Skip people who didn't answer
|
||
jumpge a,vote
|
||
move t,e ; Compute time since he looked at his clock
|
||
sub t,atimes(a)
|
||
idivi t,60. ; Convert to seconds (rounded)
|
||
add c,t
|
||
movem c,times(a)
|
||
skipn d,b ; D: candidate index for insertion
|
||
jrst sort0
|
||
sort1: move tt,sorted-1(d)
|
||
camge c,times(tt)
|
||
sojg d,sort1
|
||
sort0: movei tt,(d)
|
||
subi tt,1(b)
|
||
hrli d,(tt) ; D: aobjn into part or SORTED to move
|
||
movei tt,(a) ; The index to insert
|
||
exch tt,sorted(d)
|
||
aobjn d,.-1
|
||
aoja b,sortlp
|
||
|
||
.scalar ntimes ; The number of people who responded.
|
||
.scalar quorum ; The size of a quorum
|
||
|
||
vote: movem b,ntimes
|
||
imul b,numerq
|
||
add b,denomq
|
||
soj b,
|
||
idiv b,denomq
|
||
camge b,minq
|
||
move b,minq
|
||
movem b,quorum
|
||
setzi a,0 ; A: index of possible lowest good time
|
||
soj b, ; B: must agree with A for quorum
|
||
low: caml b,ntimes
|
||
jrst nogo
|
||
move tt,sorted(b)
|
||
move t,times(tt)
|
||
move tt,sorted(a)
|
||
sub t,times(tt)
|
||
camg t,spread
|
||
jrst gotlow
|
||
aoj a,
|
||
aoja b,low
|
||
|
||
gotlow: move b,ntimes
|
||
movei c,-1(b) ; C: index of possible highest good time
|
||
sub b,quorum ; B: must agree with C for quorum
|
||
high: move tt,sorted(c)
|
||
move t,times(tt)
|
||
move tt,sorted(b)
|
||
sub t,times(tt)
|
||
camg t,spread
|
||
jrst gotime
|
||
soj b,
|
||
soja c,high
|
||
|
||
.scalar lowest ; Index of lowest of good times.
|
||
.scalar highest ; Index of highest of good times.
|
||
.scalar median ; Index of median of good times.
|
||
.scalar host ; Pointer to ASCIZ name of winning host.
|
||
.scalar time ; Winning network time.
|
||
.scalar qtime ; Winning network time in disk format.
|
||
.scalar qzone ; SIXBIT timezone of QTIME.
|
||
.scalar year ; Year of winner.
|
||
.scalar ticks ; PD-ticks since January 1 of winner.
|
||
.scalar ksfreq ; KS-tick per PD-tick
|
||
.vector kstime(2) ; Set time relative to this.
|
||
.scalar clktim ; Or this.
|
||
|
||
s%d==:24.*60.*60.
|
||
s%y==:365.*s%d
|
||
s%est==:datime"estdif*60.*60.
|
||
gotime: movem a,lowest
|
||
movem c,highest
|
||
addi c,1(a)
|
||
lsh c,-1
|
||
movem c,median
|
||
move tt,sorted(c)
|
||
hrro a,hosts(tt)
|
||
movem a,host
|
||
move a,times(tt)
|
||
movem a,time
|
||
call cvtime
|
||
movem e,qzone
|
||
movem a,qtime
|
||
move b,lstime
|
||
call datime"timsub
|
||
add a,spread ; Allow for the usual fuzz...
|
||
jumpl a,past
|
||
move tt,days
|
||
imuli tt,s%d
|
||
camle a,tt
|
||
jrst future
|
||
ldb b,[.bp datime"tm%yr,qtime] ; EST and EDT always agree about
|
||
movei tt,1900.(b) ; the year!
|
||
movem tt,year
|
||
subi b,1 ; (Compensates for the fact that 1900. was
|
||
idivi b,4 ; not a leap year. (Screws up if you give
|
||
addi c,1 ; a time in 1900., but who cares?))
|
||
imul b,[4*s%y+s%d]
|
||
imul c,[s%y]
|
||
add b,c ; B: Seconds from 1/1/00 to this year.
|
||
move a,time
|
||
subi a,s%est ; GMT -> EST
|
||
sub a,b
|
||
imuli a,60.
|
||
movem a,ticks
|
||
skipn setp
|
||
jrst nsetp
|
||
|
||
skipn ks10p
|
||
jrst notks
|
||
dmove a,kstime
|
||
hrrz a,a ; Clear possible gubbish from high bits.
|
||
div a,ksfreq ; KS-ticks -> PD-ticks
|
||
jrst doit
|
||
|
||
notks: move a,clktim
|
||
tlz a,600000 ; Clear possible gubbish from high bits.
|
||
;; On a KA if this is zero then apparently the PD clock is off.
|
||
;; Fix this code to deal with that if you try to bring this code up
|
||
;; on a KA (see PDSET program). (Where did you find a working ITS
|
||
;; KA10 anyway?)
|
||
skipe ka10p
|
||
.lose
|
||
doit: sub a,ticks ; A: offset for loading into PDTIME
|
||
format "~&Setting the time to be ~Q ~S ~
|
||
(supplied by ~A).~&",[qtime,qzone,host]
|
||
move tt,fyear
|
||
hrli tt,year
|
||
.setloc tt,
|
||
move tt,pdtime
|
||
hrli tt,a
|
||
.setloc tt,
|
||
skipa ; This is supposed to give the SETLOC
|
||
skipa ; a chance to happen before starting the
|
||
.hang ; clock.
|
||
setoi tt,
|
||
.iotlsr tt,
|
||
skipe kl10p
|
||
cono clk,400007 ; Start clock on KL
|
||
skipn ks10p
|
||
quit
|
||
rdtim t
|
||
hrli t,1729.
|
||
wrtim t
|
||
quit
|
||
|
||
nsetp: format "~&Would have set the time to be ~Q ~S (supplied by ~A).~
|
||
~& FYEAR/ ~D. PDTIME/ ~D.~&",[qtime,qzone,host,year,ticks]
|
||
call table
|
||
quit
|
||
|
||
notset: format "
|
||
|
||
Attention!
|
||
|
||
Attention!
|
||
|
||
The time could not be set because:"
|
||
call (a)
|
||
format "~&It will be necessary for someone to set the time~@
|
||
manually by logging in and running :PDSET.~2&"
|
||
quit
|
||
|
||
nofile: jsp a,notset
|
||
format "~&There was an error accessing the file ~
|
||
~S;~S ~S.",[filesn,filen1,filen2]
|
||
return
|
||
|
||
bogus: format "~&The best time, ~Q ~S (supplied by ~A),",[qtime,qzone,host]
|
||
call (a)
|
||
format "~Q, the creation date of ~
|
||
~S;~S ~S.",[lstime,filesn,filen1,filen2]
|
||
return
|
||
|
||
future: jsp a,notset
|
||
jsp a,bogus
|
||
format " was more than~&~D day~P beyond ",[days]
|
||
return
|
||
|
||
past: jsp a,notset
|
||
jsp a,bogus
|
||
format " was~&prior to "
|
||
return
|
||
|
||
nogo: jsp a,notset
|
||
skipn t,ntimes
|
||
jrst nogo0
|
||
camge t,quorum
|
||
jrst nogo1
|
||
format "~&Of the ~D answer~P recieved, ~
|
||
no ~D agreed to within ~D seconds.",[ntimes,quorum,spread]
|
||
return
|
||
|
||
nogo0: format "~&No host responded."
|
||
return
|
||
|
||
nogo1: format "~&Only ~D host~P responded.",ntimes
|
||
return
|
||
|
||
;;; CALL TABLE: Print a table of everything we know.
|
||
table: save a
|
||
save b
|
||
save e
|
||
format "~&~D host~P responded.",ntimes
|
||
skipe count
|
||
format " ~D outstanding request~P.",count
|
||
movei b,0
|
||
tablel: caml b,ntimes
|
||
jrst tablex
|
||
move tt,sorted(b)
|
||
move a,times(tt)
|
||
call cvtime
|
||
move tt,sorted(b)
|
||
hrro t,hosts(tt)
|
||
format "~&~3<~D~>: ~Q ~S ~A",[b,a,e,t]
|
||
aoja b,tablel
|
||
|
||
tablex: format "~&Low=~D High=~D Median=~D",[lowest,highest,median]
|
||
format "~&Quorum=~D Spread=~D sec.~&",[quorum,spread]
|
||
rest e
|
||
rest b
|
||
rest a
|
||
return
|
||
|
||
;;; CALL CVTIME: Convert network time to local disk format time word.
|
||
;;; A (arg): network time
|
||
;;; A (val): disk format date
|
||
;;; E (val): SIXBIT of timezone
|
||
cvtime: subi a,s%est ; GMT -> EST
|
||
call datime"sectim ; -> disk format date
|
||
save b
|
||
movei b,60.*60.
|
||
call datime"odayl
|
||
skipa e,[sixbit /EDT/]
|
||
skipa e,[sixbit /EST/]
|
||
call datime"timadd
|
||
rest b
|
||
return
|
||
|
||
netwrk"$$hstmap==:1
|
||
netwrk"$$hostnm==:1
|
||
netwrk"$$symlook==:1
|
||
netwrk"$$chaos==:1
|
||
.insrt dsk:sysnet;netwrk >
|
||
|
||
;;; CALL LOOK: Look up the Chaosnet address of a host.
|
||
;;; A (arg): address of ASCIZ string
|
||
;;; A (val): host number
|
||
;;; Skips if the host is found.
|
||
look: save b
|
||
tloe %fhsts
|
||
jrst look1
|
||
save a
|
||
movei a,ffpage
|
||
movei b,utilch
|
||
.iopush utilch,
|
||
call netwrk"hstmap
|
||
.lose
|
||
.iopop utilch,
|
||
rest a
|
||
look1: call netwrk"hstlook
|
||
jrst popbj
|
||
rest b
|
||
aos (p)
|
||
return
|
||
|
||
cnstnts:
|
||
constants
|
||
|
||
patch::
|
||
pat: block 100.
|
||
|
||
variables
|
||
|
||
ffaddr: -1 ; Make memory exist
|
||
|
||
ffpage==:<ffaddr+1777>_-12
|
||
|
||
end go
|