Fang.[1]
Fang is a utility program for UNIVAC 1108 computers, written in 1972. UNIVAC's EXEC 8 had threads and async I/O for user programs, decades before UNIX. The machines were shared-memory multiprocessors. FANG uses those capabilities to parallelize copying jobs. The UNIVAC mainframes had plenty of I/O parallelism and many I/O devices, so this was a significant performance win.
See especially "schprocs". Those are the classic primitives from Dijkstra: P, V, and bounded buffers. That technology predates Go by 40 years. Here's Dijkstra's P function:
.
.
. DIJKSTRA P FUNCTION
.
.
. LA,U A0,<QUEUE>
. LMJ X11,P
. <RETURN> X5 DESTROYED
.
P* TS QHEAD,A0 LOCK THE QUEUE
LX X5,QN,A0 LOAD QUEUE COUNT (note: load)
ANX,U X5,1 BACK UP THE COUNT (note: Add Negative, i.e. subtract)
SX X5,QN,A0 REPLACE THE COUNT IN THE QUEUE (note: store)
TN X5 DO WE NEED TO DEACTIVATE HIM ? (note: Test Negative)
J PDONE NO. SKIP DEACTIVATION (note: Jump, i.e. branch)
ON TSQ=0 (note: this is an assembly-time ifdef)
LX X5,QHL,A0 LOAD BACK LINK OF QUEUE
SX X5,QHL,X4 PUT INTO BACK LINK OF ACTIVITY
SX X4,QFL,X5 CHAIN ACTIVITY TO LAST ACTIVITY
SA A0,QFL,X4 CHAIN HEAD TO NEW ACTIVITY
SX X4,QHL,A0 MAKE THE NEW ACTIVITY LAST ON QUEUE
CTS QHEAD,A0 RELEASE PROTECTION ON QUEUE HEAD
SCHDACT* DACT$ . DEACTIVATE PROCESS (note: system call)
OFF
ON TSQ (note: for later version of OS with alt wait fn)
C$TSQ QHEAD,A0 WAIT FOR C$TSA (note: system call)
OFF
J 0,X11 RETURN AFTER ACTIVATION
.
PDONE CTS QHEAD,A0 UNLOCK THE QUEUE (note: not a system call, just a macro. Stores 0.)
J 0,X11 RETURN
(Notes:
Instruction format is
OPERATOR REG,OFFSET,INDEXREG
The "TS" instruction is "Test and Set". That's atomic. If the flag is already set, an interrupt occurs and the OS does a
thread switch. CTS just clears the flag. Later versions of the
OS support C$TSQ and C$TSA, where the OS queues waiting test
and set operations.
X4 is the "switch list", the local data for the thread.)
[1] https://www.fourmilab.ch/documents/univac/fang/