Machine-Independent MDL for TOPS-20 and VAX.
[pdp10-muddle.git] / mim / development / mim / vax / mimlib / forks.mud
diff --git a/mim/development/mim/vax/mimlib/forks.mud b/mim/development/mim/vax/mimlib/forks.mud
new file mode 100644 (file)
index 0000000..9690e6d
--- /dev/null
@@ -0,0 +1,631 @@
+<PACKAGE "FORKS">
+
+<ENTRY FORK FORK-STATUS? CONTINUE-FORK PASS-TTY-DOWN TAKE-TTY-BACK
+       WAIT-FORK STOP-FORK RUN-FORK RUN-PIPED>
+<ENTRY GET-INPUT GET-OUTPUT>
+<ENTRY FORK-STATUS-QUIT FORK-STATUS-KILLED FORK-STATUS-DIED
+       FORK-STATUS-DEAD FORK-STATUS-RUNNING FORK-STATUS-STOPPED
+       FORK-STATUS-WAIT>
+
+<USE "NEWSTRUC" "PIPES">
+
+<ENV-COND (("MACHINE" "VAX")
+          <NEW-CHANNEL-TYPE FORK <>
+                            GET-INPUT GET-INPUT
+                            GET-OUTPUT GET-INPUT
+                            FORK-STATUS? TEST-FORK-STATUS
+                            READ-BYTE FORK-READ
+                            READ-BUFFER FORK-READ
+                            READ-SAFE-BUFFER FORK-READ
+                            WRITE-BYTE FORK-WRITE
+                            WRITE-BUFFER FORK-WRITE
+                            ;"READ-MEMORY ;FORK-READ-MEMORY
+                            ;WRITE-MEMORY ;FORK-WRITE-MEMORY
+                            ;READ-ACS ;FORK-READ-ACS
+                            ;WRITE-ACS ;FORK-WRITE-ACS"
+                            CONTINUE-FORK CONTINUE-FORK
+                            KILL-FORK KILL-FORK
+                            CLOSE KILL-FORK
+                            PASS-TTY-DOWN PASS-TTY-DOWN
+                            TAKE-TTY-BACK TAKE-TTY-BACK
+                            WAIT-FORK WAIT-FORK
+                            STOP-FORK STOP-FORK
+                            OPEN OPEN-FORK
+                            PRINT-DATA FORK-PRINT-DATA>)>
+
+<NEWSTRUC FORK VECTOR
+         FORK-ID FIX
+         FORK-GRP FIX
+         FORK-STS FIX
+         FORK-DATA FIX
+         FORK-INPUT <OR CHANNEL FIX FALSE>
+         FORK-OUTPUT <OR CHANNEL FIX FALSE>>
+
+<MSETG ST-BIT-TTY-WAIT *400000*>
+<MSETG ST-BIT-HAD-TTY *200000*>
+<MSETG ST-BIT-TTY *100000*>
+<MSETG ST-BIT-RUNNING *40000*>
+<MSETG ST-BIT-DEAD *20000*>
+<MSETG ST-BIT-OTHER *777*>
+<MSETG ST-OTH-KILLED *1*>
+<MSETG ST-OTH-QUIT 2>
+<MSETG ST-OTH-DIED 3>
+
+<MSETG TERM-CONT *177*>
+
+<MSETG STATUS-TTY <CHTYPE <ORB ,ST-BIT-TTY ,ST-BIT-RUNNING> FIX>>
+<MSETG STATUS-RUNNING ,ST-BIT-RUNNING>
+<MSETG STATUS-KILLED <CHTYPE <ORB ,ST-BIT-DEAD ,ST-OTH-KILLED> FIX>>
+<MSETG STATUS-DIED <CHTYPE <ORB ,ST-BIT-DEAD ,ST-OTH-DIED> FIX>>
+<MSETG STATUS-QUIT <CHTYPE <ORB ,ST-BIT-DEAD ,ST-OTH-QUIT> FIX>>
+
+<DEFMAC FORK-STS? ('FORK 'BIT)
+  <FORM NOT
+       <FORM 0? <FORM ANDB <FORM FORK-STS .FORK> .BIT>>>>
+
+<DEFMAC SET-FORK-STS ('FORK "TUPLE" STATS "AUX" (ON 0) (OFF 0))
+  <REPEAT (WD)
+    <COND (<EMPTY? .STATS> <RETURN>)>
+    <COND (<TYPE? <SET WD <1 .STATS>> LIST>
+          <SET OFF <ORB .OFF !.WD>>)
+         (<SET ON <ORB .ON .WD>>)>
+    <SET STATS <REST .STATS>>>
+  <SET OFF <CHTYPE .OFF FIX>>
+  <SET ON <CHTYPE .ON FIX>>
+  <COND (<NOT <0? <CHTYPE <ANDB .ON ,ST-BIT-DEAD> FIX>>>
+        <SET OFF <CHTYPE <ORB .OFF ,ST-BIT-RUNNING> FIX>>)>
+  <FORM BIND ()
+    <COND (<NOT <0? .OFF>>
+          <FORM FORK-STS .FORK <FORM ANDB <FORM FORK-STS .FORK>
+                                     <CHTYPE <XORB .OFF -1> FIX>>>)>
+    <COND (<NOT <0? .ON>>
+          <FORM FORK-STS .FORK <FORM ORB <FORM FORK-STS .FORK>
+                                     .ON>>)>>>
+
+;"<MSETG PT-READ-I 1>
+<MSETG PT-READ-D 2>
+<MSETG PT-READ-S 3>
+<MSETG PT-WRITE-I 4>
+<MSETG PT-WRITE-D 5>
+<MSETG PT-WRITE-S 6>
+<MSETG PT-CONT 7>
+<MSETG PT-TERM 8>
+"
+<MSETG SIG-INT 2>
+<MSETG SIG-QUIT 3>
+<MSETG SIG-ILL 4>
+<MSETG SIG-FPE 8>
+<MSETG SIG-KILL 9>
+<MSETG SIG-BUS 10>
+<MSETG SIG-SEGV 11>
+<MSETG SIG-SYS 12>
+<MSETG SIG-PIPE 13>
+<MSETG SIG-ALRM 14>
+<MSETG SIG-TERM 15>
+<MSETG SIG-STOP 17>
+<MSETG SIG-TSTP 18>
+<MSETG SIG-CONT 19>
+<MSETG SIG-CHLD 20>
+<MSETG SIG-TTIN 21>
+<MSETG SIG-TTOU 22>
+<MSETG SIG-XCPU 24>
+<MSETG SIG-XFSZ 24>
+<MSETG SIG-IGNORE 1>
+<MSETG SIG-DEFAULT 0>
+<MSETG FORK-INT-LEV 3>
+<SETG ALL-FORKS ()>
+
+<SETG BUF <UVECTOR 0>>
+<GDECL (BUF) UVECTOR (ALL-FORKS) <LIST [REST FIX CHANNEL]>>
+
+<DEFINE GET-INPUT (CH OPER "AUX" (FORK <CHANNEL-DATA .CH>) FROB)
+  #DECL ((CH) CHANNEL (OPER) ATOM (FORK) FORK)
+  <COND (<==? .OPER GET-INPUT>
+        <SET FROB <FORK-INPUT .FORK>>)
+       (T
+        <SET FROB <FORK-OUTPUT .FORK>>)>
+  <AND <TYPE? .FROB CHANNEL> .FROB>>
+
+<DEFINE RUN-FORK (FILE "OPTIONAL" (INPUT <>) (OUTPUT <>) "TUPLE" ARGS
+                 "AUX" VAL (OINT <INT-LEVEL>) F)
+  #DECL ((FILE) STRING (INPUT OUTPUT) <OR ATOM FALSE CHANNEL>
+        (ARGS) <TUPLE [REST STRING]> (OINT) FIX (VAL) <OR CHANNEL FALSE>
+        (F) FORK)
+  <UNWIND
+   <PROG ()
+     <INT-LEVEL <MAX .OINT ,FORK-INT-LEV>>
+     <COND (<SET VAL <CHANNEL-OPEN FORK .FILE .INPUT .OUTPUT !.ARGS>>
+           <SET F <CHANNEL-DATA .VAL>>
+           <SETG ALL-FORKS (<FORK-ID .F> .VAL !,ALL-FORKS)>)>
+     <COND (<AND .VAL
+                <OR <TYPE? .INPUT ATOM>
+                    <TYPE? .OUTPUT ATOM>>>
+           <PASS-TTY-DOWN .VAL PASS-TTY-DOWN .OINT>)>
+     <INT-LEVEL .OINT>
+     .VAL>
+   <INT-LEVEL .OINT>>>
+
+<DEFINE RUN-PIPED (FILE "TUPLE" ARGS "AUX" (ICH <>) (OCH <>) VAL)
+  #DECL ((FILE) STRING (ARGS) <TUPLE [REST STRING]>
+        (ICH OCH) <OR CHANNEL FALSE>)
+  <UNWIND
+   <COND (<SET ICH <CHANNEL-OPEN PIPE <STRING .FILE !\- "IN">>>
+         <COND (<SET OCH <CHANNEL-OPEN PIPE <STRING .FILE !\- "OUT">>>
+                <COND (<NOT <SET VAL <RUN-FORK .FILE .ICH .OCH !.ARGS>>>
+                       <CLOSE .OCH>
+                       <CLOSE .ICH>
+                       .VAL)
+                      (.VAL)>)
+               (T
+                <CLOSE .ICH>
+                .OCH)>)>
+   <PROG ()
+     <COND (.ICH <CLOSE .ICH>)>
+     <COND (.OCH <CLOSE .OCH>)>>>>
+
+<SETG UV3 <UVECTOR 0 0 0>>
+
+<DEFINE OPEN-FORK RF (STYPE OPER FILE "OPTIONAL" (INPUT <>) (OUTPUT <>)
+                    "TUPLE" ARGS "AUX" RFILE PID (ENV <CALL GETS ENVIR>)
+                    PSTR TEMP ARGP ENVP (IJFN <>) (OJFN <>) (KILLJ1 <>)
+                    (KILLJ2 <>) (WAIT? <>) CF (UV3 ,UV3)
+                    (BROKEN? <CHANNEL-OP ,OUTCHAN TTY-BROKEN?>))
+  #DECL ((RFILE FILE) STRING (ARGS) <TUPLE [REST STRING]> (PID) <OR FIX FALSE>
+        (ENV) VECTOR (INPUT OUTPUT) <OR ATOM FALSE CHANNEL>
+        (KILLJ1 KILLJ2 IJFN OJFN) <OR FIX FALSE>
+        (ARGP ENVP UV3) <UVECTOR [REST FIX]> (PSTR) <OR FALSE STRING>
+        (WAIT?) <OR ATOM FALSE> (CF) FORK)
+  <SETG MOI <CALL SYSCALL GETPID>>
+  <SETG MY-GROUP <CALL SYSCALL GETPGRP ,MOI>>
+  <SETG CURRENT-GROUP ,MY-GROUP>
+  <1 .UV3 ,SIG-IGNORE>
+  <2 .UV3 0>
+  <3 .UV3 0>
+  <CALL SYSCALL SIGVEC ,SIG-TTOU .UV3 0>
+  <COND (<NOT <MEMQ !\/ .FILE>>
+        <COND
+         (<SET PSTR <GET-ENV-STR "PATH" .ENV>>
+          <PROG ((OS .PSTR))
+            <MAPR <>
+                <FUNCTION (S "AUX" (C <1 .S>) NS)
+                  <COND (<==? .C !\:>
+                         <SET NS <SUBSTRUC .OS 0 <- <LENGTH .OS>
+                                                    <LENGTH .S>>>>
+                         <SET OS <REST .S>>
+                         <COND (<SET TEMP <FILE-EXISTS?
+                                           <SET NS <STRING .NS !\/ .FILE>>
+                                           0 0 0 0>>
+                                <COND 
+                                 (<NOT
+                                   <0?
+                                    <ANDB <STAT-FIELD 
+                                           <FILE-STAT <STANDARD-NAME .NS>>
+                                           ,MODE-OFFS ,MODE-SIZE>
+                                          ,FMT-IFDIR>>>
+                                  <SET TEMP <SYS-ERR .NS #FALSE(13) <>>>)
+                                 (T
+                                  <SET RFILE .NS>
+                                  <MAPLEAVE>)>)>)>>
+                .PSTR>
+            <COND (<NOT .TEMP> <RETURN .TEMP .RF>)>>)
+         (T
+          <ERROR SEARCH-PATH-NOT-KNOWN!-ERRORS RUN-FORK>
+          <RETURN <> .RF>)>)
+       (<NOT <SET TEMP <FILE-EXISTS? .FILE 0 0 0 0>>>
+        <RETURN .TEMP .RF>)
+       (<SET RFILE <PARSE-FILE-NAME .FILE <>>>)>
+  <SET RFILE <STANDARD-NAME .RFILE>>
+  <COND (<NOT <SET TEMP <CALL SYSCALL ACCESS .RFILE ,X-OK>>>
+        ; "Don't have execute access"
+        <RETURN <SYS-ERR .RFILE .TEMP <>> .RF>)>
+  ; "Now have file name in standard form, expanded, and it exists"
+  <SET FILE <STANDARD-NAME .FILE>>
+  <SET ARGP <IUVECTOR <+ <LENGTH .ARGS> 2> 0>>
+  <SET ENVP <IUVECTOR <+ <LENGTH .ENV> 1> 0>>
+  <1 .ARGP <CALL VALUE .FILE>>
+  <MAPR <>
+    <FUNCTION (ARGT ARGPTR)
+      <1 .ARGT <STANDARD-NAME <1 .ARGT>>>
+      <1 .ARGPTR <CALL VALUE <1 .ARGT>>>>
+    .ARGS <REST .ARGP>>
+  <MAPR <>
+    <FUNCTION (ENVVEC ENVPTR)
+      <1 .ENVPTR <CALL VALUE <1 .ENVVEC>>>>
+    .ENV .ENVP>
+  <COND (<OR <TYPE? .INPUT ATOM>
+            <TYPE? .OUTPUT ATOM>>
+        <SET WAIT? T>)>
+  <COND (<TYPE? .INPUT CHANNEL>
+        <COND (<==? <CHANNEL-TYPE .INPUT> PIPE>
+               <SET IJFN <READ-DESC <CHANNEL-OP .INPUT GET-PIPE>:UVECTOR>>
+               <SET KILLJ1 <WRITE-DESC <CHANNEL-OP .INPUT GET-PIPE>:UVECTOR>>)
+              (<SET IJFN <CHANNEL-OP .INPUT FILE-HANDLE>>)>)>
+  <COND (<TYPE? .OUTPUT CHANNEL>
+        <COND (<==? <CHANNEL-TYPE .OUTPUT> PIPE>
+               <SET OJFN <WRITE-DESC <CHANNEL-OP .OUTPUT GET-PIPE>>>
+               <SET KILLJ2 <READ-DESC <CHANNEL-OP .OUTPUT GET-PIPE>>>)
+              (<SET OJFN <CHANNEL-OP .OUTPUT FILE-HANDLE>>)>)>
+  ; "IJFN and OJFN can be closed by the superior; KILLJ1 and KILLJ2,
+     by the inferior"
+  <COND (<NOT <GASSIGNED? INF-HANDLER>>
+        <CLASS "INFERIOR" ,FORK-INT-LEV T>
+        <SETG INF-HANDLER <ON <HANDLER "INFERIOR" ,INF-INTERRUPT>>>)>
+  <UNWIND
+   <PROG ()
+     <COND (.BROKEN? <CHANNEL-OP ,OUTCHAN FIX-TTY>)>
+     ; "Don't leave tty broken"
+     <COND (<SET PID <CALL SYSCALL VFORK>>
+           <COND (<N==? <SETG NEW-FORK <CALL SYSCALL GETPID>> ,MOI>
+                  ; "We're inferior"
+                  ; "Copy i/o translations, kill excess descriptors"
+                  <COND (.IJFN
+                         <CALL SYSCALL DUP <+ *100* .IJFN> ,STDIN>
+                         <CALL SYSCALL CLOSE .IJFN>)>
+                  <COND (.OJFN
+                         <CALL SYSCALL DUP <+ *100* .OJFN> ,STDOUT>
+                         <CALL SYSCALL CLOSE .OJFN>)>
+                  <COND (.KILLJ1
+                         <CALL SYSCALL CLOSE .KILLJ1>)>
+                  <COND (.KILLJ2
+                         <CALL SYSCALL CLOSE .KILLJ2>)>
+                  ; "Set process group as appropriate"
+                  <COND (.WAIT?
+                         <CALL SYSCALL IOCTL ,STDIN ,TIOCLBIS
+                               <1 ,BIS-BUF ,LTOSTOP>>
+                         <SETG CURRENT-GROUP ,NEW-FORK>
+                         <CALL SYSCALL IOCTL ,STDIN ,TIOCSPGRP
+                               <1 ,WAIT-BUF ,NEW-FORK>>
+                         <CALL SYSCALL SETPGRP ,NEW-FORK ,NEW-FORK>)
+                        (T
+                         <CALL SYSCALL SETPGRP ,NEW-FORK ,MY-GROUP>)>
+                  ; "Now go for it"
+                  <COND (<CALL SYSCALL EXECVE .RFILE .ARGP .ENVP>
+                         ; "This never returns")
+                        (<CALL FATAL "EXEC call failed">)>)
+                 (T
+                  <COND (<TYPE? .INPUT CHANNEL>
+                         <COND (<==? <CHANNEL-TYPE .INPUT> PIPE>
+                                <CHANNEL-OP .INPUT CLOSE ,READ-DESC>)
+                               (<CLOSE .INPUT>)>)>
+                  <COND (<TYPE? .OUTPUT CHANNEL>
+                         <COND (<==? <CHANNEL-TYPE .OUTPUT> PIPE>
+                                <CHANNEL-OP .OUTPUT CLOSE ,WRITE-DESC>)
+                               (<CLOSE .OUTPUT>)>)>
+                  <SET CF
+                       <CHTYPE [.PID
+                                <COND (.WAIT? .PID)
+                                      (T
+                                       ,MY-GROUP)>
+                                <COND (.WAIT?
+                                       ,STATUS-TTY)
+                                      (,STATUS-RUNNING)>
+                                0
+                                <COND (<TYPE? .INPUT CHANNEL>
+                                       <COND (<CHANNEL-OPEN? .INPUT>
+                                              .INPUT)
+                                             (T <>)>)
+                                      (,STDIN)>
+                                <COND (<TYPE? .OUTPUT CHANNEL>
+                                       <COND (<CHANNEL-OPEN? .OUTPUT>
+                                              .OUTPUT)
+                                             (T <>)>)
+                                      (,STDOUT)>] FORK>>
+                  <COND (<AND <NOT .WAIT?>
+                              .BROKEN?>
+                         <CHANNEL-OP ,OUTCHAN BREAK-TTY>)>
+                  .CF)>)
+          (T
+           <COND (.BROKEN? <CHANNEL-OP ,OUTCHAN BREAK-TTY>)>
+           .PID)>>
+   <COND (.BROKEN? <CHANNEL-OP ,OUTCHAN BREAK-TTY>)>>>
+
+<DEFINE FORK-READ (CHANNEL OPER "TUPLE" STUFF
+                  "AUX" (FORK <CHANNEL-DATA .CHANNEL>) 
+                        (CH <FORK-OUTPUT .FORK>))
+  #DECL ((CHANNEL) CHANNEL (FORK) FORK)
+  <COND (<TYPE? .CH CHANNEL>
+        <CHANNEL-OP .CH .OPER !.STUFF>)
+       (T
+        #FALSE ("FORK IS NOT PIPELINED"))>>
+
+<DEFINE FORK-WRITE (CHANNEL OPER "TUPLE" STUFF 
+                          "AUX" (FORK <CHANNEL-DATA .CHANNEL>)
+                          (CH <FORK-INPUT .FORK>))
+  #DECL ((CHANNEL) CHANNEL (FORK) FORK)
+  <COND (<TYPE? .CH CHANNEL>
+        <CHANNEL-OP .CH .OPER !.STUFF>)
+       (T
+        #FALSE ("FORK IS NOT PIPELINED"))>>
+
+; "Returns stopping signal if process is stopped (non-fatally), otherwise <>"
+<DEFMAC STOPPED?('STS)
+  <FORM COND (<FORM ==? *177* <FORM GETBITS .STS <FORM BITS 8 0>>>
+             <FORM GETBITS .STS <FORM BITS 8 8>>)>>
+
+; "Returns exit argument if returned normally"
+<DEFMAC QUIT? ('STS)
+  <FORM COND (<FORM 0? <FORM GETBITS .STS <FORM BITS 8 0>>>
+             <FORM GETBITS .STS <FORM BITS 8 8>>)>>
+
+; "Returns fatal signal"
+<DEFMAC DIED? ('STS)
+  <FORM BIND (DAT)
+    <FORM COND
+         (<FORM AND
+           <FORM NOT
+                 <FORM 0? <FORM SET DAT <FORM GETBITS .STS <FORM BITS 8 0>>>>>
+           <FORM N==? '.DAT ,TERM-CONT>>
+          '.DAT)>>>
+
+<MSETG WNOHANG 1>
+<MSETG WUNTRACED 2>
+<SETG ST-BUF <UVECTOR 0>>
+<SETG BIS-BUF <UVECTOR 0>>
+<GDECL (BIS-BUF ST-BUF) UVECTOR>
+<DEFINE INF-INTERRUPT (ARG "AUX" CID)
+  #DECL ((CID) <OR FIX FALSE>)
+  <REPEAT ((BB ,ST-BUF))
+    <COND (<AND <SET CID <CALL SYSCALL WAIT .BB <+ ,WNOHANG ,WUNTRACED> 0>>
+               <NOT <0? .CID>>>
+          ; "Got status"
+          <COND (<NOT <PROCESS-FORK .CID <1 .BB>>>
+                 ; "Not ready to go yet, will try again later"
+                 <RETURN>)>)
+         (<RETURN>
+          ; "Nobody to handle")>>>
+
+<DEFINE PROCESS-FORK (PID STATUS "AUX" (AF ,ALL-FORKS) CC CFORK MISC)
+  #DECL ((PID STATUS) FIX (AF) <PRIMTYPE LIST> (CC) CHANNEL (CFORK) FORK)
+  <COND (<SET AF <MEMQ .PID .AF>>
+        <SET CC <2 .AF>>
+        <SET CFORK <CHANNEL-DATA .CC>>
+        <COND (<SET MISC <DIED? .STATUS>>      ; "Fatal interrupt"
+               <SET-FORK-STS .CFORK
+                             ,ST-BIT-DEAD ,ST-OTH-DIED>
+               <FORK-DATA .CFORK .MISC>
+               <STOP-FORK .CC INTERRUPT>
+               <REPORT .CC>)
+              (<SET MISC <QUIT? .STATUS>>
+               <SET-FORK-STS .CFORK
+                             ,ST-BIT-DEAD ,ST-OTH-QUIT>
+               <FORK-DATA .CFORK .MISC>
+               <STOP-FORK .CC INTERRUPT>
+               <REPORT .CC>)
+              (<SET MISC <STOPPED? .STATUS>>   ; "Non-fatal interrupt"
+               <COND (<==? .MISC ,SIG-CONT>
+                      <CALL SYSCALL KILL .PID ,SIG-CONT>)
+                     (<OR <==? .MISC ,SIG-TTOU>
+                          <==? .MISC ,SIG-TTIN>>
+                      ; "Trying to use tty when doesn't have it"
+                      <COND (<FORK-STS? .CFORK ,ST-BIT-TTY>
+                             ; "We think it has it"
+                             <SETG CURRENT-GROUP <FORK-ID .CFORK>>
+                             <CALL SYSCALL IOCTL ,STDIN
+                                   ,TIOCSPGRP
+                                   <1 ,GROUP-BUF <FORK-ID .CFORK>>>
+                             <CALL SYSCALL KILL .PID ,SIG-CONT>)
+                            (T
+                             <SET-FORK-STS .CFORK ,ST-BIT-TTY-WAIT>
+                             <STOP-FORK .CC INTERRUPT>
+                             <REPORT .CC>)>)
+                     (<FORK-STS? .CFORK ,ST-BIT-RUNNING>
+                      ; "Not already stopped"
+                      <FORK-DATA .CFORK .MISC>
+                      <STOP-FORK .CC INTERRUPT>
+                      <REPORT .CC>)>)>)>>
+
+<DEFINE STOP-FORK (CHAN OPER "AUX" (FORK <CHANNEL-DATA .CHAN>)
+                  (OINT <INT-LEVEL>))
+  #DECL ((CHAN) CHANNEL (FORK) FORK (OINT) FIX)
+  <INT-LEVEL <MAX .OINT ,FORK-INT-LEV>>
+  <COND (<AND <NOT <0? <FORK-DATA .FORK>>>
+             <FORK-STS? .FORK ,ST-BIT-RUNNING>>
+        <CALL SYSCALL KILL <FORK-ID .FORK> ,SIG-STOP>)>
+  <TAKE-TTY-BACK .CHAN .OPER <>>
+  <SET-FORK-STS .FORK (,ST-BIT-RUNNING)>
+  <INT-LEVEL .OINT>
+  .CHAN>
+
+<DEFINE TAKE-TTY-BACK (CHAN OPER "OPTIONAL" (PERM? T)
+                      "AUX" (FORK <CHANNEL-DATA .CHAN>) (OINT <INT-LEVEL>))
+  #DECL ((CHAN) CHANNEL (FORK) FORK (OINT) FIX)
+  <INT-LEVEL <MAX .OINT ,FORK-INT-LEV>>
+  <COND (<FORK-STS? .FORK ,ST-BIT-TTY>
+        <SET-FORK-STS .FORK (,ST-BIT-TTY)>
+        <COND (.PERM?
+               <SET-FORK-STS .FORK (,ST-BIT-HAD-TTY)>)
+              (T
+               <SET-FORK-STS .FORK ,ST-BIT-HAD-TTY>)>
+        <SETG CURRENT-GROUP ,MY-GROUP>
+        <CALL SYSCALL IOCTL ,STDIN ,TIOCSPGRP <1 ,GROUP-BUF ,MY-GROUP>>
+        <CHANNEL-OP ,OUTCHAN BREAK-TTY>)>
+  <INT-LEVEL .OINT>
+  .CHAN>
+
+<DEFINE PASS-TTY-DOWN (CHAN OPER "OPTIONAL" (OINT <INT-LEVEL>)
+                      "AUX" (FORK <CHANNEL-DATA .CHAN>))
+  #DECL ((CHAN) CHANNEL (FORK) FORK (OINT) FIX)
+  <INT-LEVEL <MAX .OINT ,FORK-INT-LEV>>
+  <SET-FORK-STS .FORK ,ST-BIT-HAD-TTY (,ST-BIT-TTY-WAIT)>
+  <CONTINUE-FORK .CHAN .OPER .OINT>>
+
+<DEFINE CONTINUE-FORK (CHAN OPER "OPTIONAL" (OINT? <>)
+                      "AUX" (FORK <CHANNEL-DATA .CHAN>) OINT
+                            (FIXED? <>)
+                            (BROKEN? <CHANNEL-OP ,OUTCHAN TTY-BROKEN?>))
+  #DECL ((CHAN) CHANNEL (OINT?) <OR FIX FALSE> (FORK) FORK (OINT) FIX
+        (FIXED?) <SPECIAL <OR ATOM FALSE>>)
+  <UNWIND
+   <PROG ()
+     <COND (<FORK-STS? .FORK ,ST-BIT-DEAD>
+           <RETURN #FALSE ("FORK CAN'T BE CONTINUED")>)>
+     <COND (<NOT .OINT?>
+           <SET OINT <INT-LEVEL>>
+           <INT-LEVEL <MAX .OINT ,FORK-INT-LEV>>)
+          (<SET OINT .OINT?>)>
+     <COND (<FORK-STS? .FORK ,ST-BIT-HAD-TTY>
+           <SET-FORK-STS .FORK ,ST-BIT-TTY (,ST-BIT-HAD-TTY)>
+           <SET FIXED? T>
+           <COND (.BROKEN? <CHANNEL-OP ,OUTCHAN FIX-TTY>)>
+           <COND (<==? ,CURRENT-GROUP ,MY-GROUP>
+                  <CALL SYSCALL IOCTL ,STDIN ,TIOCLBIS <1 ,BIS-BUF ,LTOSTOP>>
+                  <SETG CURRENT-GROUP <FORK-ID .FORK>>
+                  <CALL SYSCALL IOCTL ,STDIN ,TIOCSPGRP
+                        <1 ,GROUP-BUF <FORK-ID .FORK>>>)>)>
+     <SET-FORK-STS .FORK ,ST-BIT-RUNNING>
+     <CALL SYSCALL KILL <FORK-ID .FORK> ,SIG-CONT>
+     <COND (<OR .OINT? .FIXED?>
+           <WAIT-FORK .CHAN .OPER .OINT>
+           <SETG CURRENT-GROUP ,MY-GROUP>
+           <CALL SYSCALL IOCTL ,STDIN ,TIOCSPGRP <1 ,GROUP-BUF ,MY-GROUP>>
+           <CALL SYSCALL IOCTL ,STDIN ,TIOCLBIC <1 ,BIS-BUF ,LTOSTOP>>
+           <COND (.BROKEN? <CHANNEL-OP ,OUTCHAN BREAK-TTY>)>
+           <SET FIXED? <>>)>
+     <INT-LEVEL .OINT>
+     .CHAN>
+   <PROG ()
+     <COND (<AND .FIXED? .BROKEN?>
+           <CHANNEL-OP ,OUTCHAN BREAK-TTY>)>
+     <INT-LEVEL .OINT>>>>
+
+<SETG WAIT-BUF <UVECTOR 0>>
+<SETG GROUP-BUF <UVECTOR 0>>
+<GDECL (GROUP-BUF WAIT-BUF) UVECTOR>
+<DEFINE WAIT-FORK WAIT-ACT (CHAN OPER "OPTIONAL" (OINT? <>)
+                  "AUX" (FORK <CHANNEL-DATA .CHAN>)
+                        (CURRENT-FORK <FORK-ID .FORK>))
+  #DECL ((CHAN) CHANNEL (OINT?) <OR FIX FALSE> (FORK) FORK
+        (CURRENT-FORK) <SPECIAL FIX> (WAIT-ACT) <SPECIAL FRAME>)
+  <COND (.OINT?
+        <INT-LEVEL .OINT?>)>
+  <PROG (CID)
+    <COND (<NOT <FORK-STS? .FORK ,ST-BIT-RUNNING>>
+          .CHAN)
+         (<==? <SET CID <ISYSCALL WAIT ,WAIT-BUF ,WUNTRACED 0>>
+               .CURRENT-FORK>
+          <PROCESS-FORK .CID <1 ,WAIT-BUF>>
+          .CHAN)
+         (.CID
+          <INTERRUPT "INFERIOR">
+          <AGAIN>)
+         (<==? <1 .CID> ,EINTR>
+          <INTERRUPT "INFERIOR">
+          <AGAIN>)
+         (T
+          <SYS-ERR "" .CID <>>)>>>
+
+<DEFINE REPORT (CHAN "AUX" (FORK <CHANNEL-DATA .CHAN>))
+  #DECL ((CHAN) CHANNEL (FORK) FORK)
+  <COND (<OR <NOT <ASSIGNED? CURRENT-FORK>>
+            <N==? .CURRENT-FORK <FORK-ID .FORK>>>
+        <INTERRUPT "USER-INFERIOR" .CHAN>)
+       (T
+        <DISMISS .CHAN .WAIT-ACT>)>>
+
+<DEFINE KILL-FORK (CHAN OPER "AUX" (FORK <CHANNEL-DATA .CHAN>)
+                  (OINT <INT-LEVEL>) (AF ,ALL-FORKS) L)
+  #DECL ((CHAN) CHANNEL (FORK) FORK (OINT) FIX)
+  <INT-LEVEL <MAX .OINT ,FORK-INT-LEV>>
+  <COND (<NOT <FORK-STS? .FORK ,ST-BIT-DEAD>>
+        <SET-FORK-STS .FORK ,STATUS-KILLED>
+        <CALL SYSCALL KILL <FORK-ID .FORK> ,SIG-KILL>)>
+  <COND (<SET L <MEMQ <FORK-ID .FORK> .AF>>
+        <COND (<TYPE? <FORK-INPUT .FORK> CHANNEL>
+               <CLOSE <FORK-INPUT .FORK>>)>
+        <COND (<TYPE? <FORK-OUTPUT .FORK> CHANNEL>
+               <CLOSE <FORK-OUTPUT .FORK>>)>
+        <COND (<==? .L .AF>
+               <SETG ALL-FORKS <REST .AF 2>>)
+              (T
+               <PUTREST <REST .AF <- <LENGTH .AF> <LENGTH .L> 1>>
+                        <REST .L 2>>)>)>
+  <TAKE-TTY-BACK .CHAN .OPER>
+  <INT-LEVEL .OINT>
+  .CHAN>
+
+<DEFINE FORK-PRINT-DATA (CHANNEL OPER OUTCHAN 
+                        "AUX" (FORK <CHANNEL-DATA .CHANNEL>) OTH)
+  #DECL ((CHANNEL) CHANNEL (OUTCHAN) CHANNEL (FORK) FORK)
+  <PRINC "#FORK [" .OUTCHAN>
+  <PRINC "PID:" .OUTCHAN>
+  <PRIN1 <FORK-ID .FORK> .OUTCHAN>
+  <PRINC " GROUP:" .OUTCHAN>
+  <PRIN1 <FORK-GRP .FORK> .OUTCHAN>
+  <PRINC " STATUS:" .OUTCHAN>
+  <COND (<FORK-STS? .FORK ,ST-BIT-DEAD>
+        <COND (<==? <SET OTH <ANDB <FORK-STS .FORK> ,ST-BIT-OTHER>>
+                    ,ST-OTH-KILLED>
+               <PRINC "KILLED" .OUTCHAN>)
+              (<==? .OTH ,ST-OTH-QUIT>
+               <PRINC "QUIT" .OUTCHAN>
+               <COND (<NOT <0? <FORK-DATA .FORK>>>
+                      <PRINC !\: .OUTCHAN>
+                      <PRINC <FORK-DATA .FORK> .OUTCHAN>)>)
+              (<==? .OTH ,ST-OTH-DIED>
+               <PRINC "DIED:" .OUTCHAN>
+               <PRINC <FORK-DATA .FORK> .OUTCHAN>)>)
+       (T
+        <COND (<FORK-STS? .FORK ,ST-BIT-TTY-WAIT>
+               <PRINC "TTYWAIT;" .OUTCHAN>)
+              (<FORK-STS? .FORK ,ST-BIT-TTY>
+               <PRINC "TTY;" .OUTCHAN>)
+              (T
+               <PRINC "NOTTY;" .OUTCHAN>)>
+        <COND (<FORK-STS? .FORK ,ST-BIT-HAD-TTY>
+               <PRINC "HADTTY;" .OUTCHAN>)>
+        <COND (<FORK-STS? .FORK ,ST-BIT-RUNNING>
+               <PRINC "RUNNING" .OUTCHAN>)
+              (T
+               <PRINC "STOPPED" .OUTCHAN>
+               <COND (<NOT <0? <FORK-DATA .FORK>>>
+                      <PRINC !\: .OUTCHAN>
+                      <PRINC <FORK-DATA .FORK> .OUTCHAN>)>)>)>
+  <PRINC " INPUT:" .OUTCHAN>
+  <COND (<TYPE? <SET OTH <FORK-INPUT .FORK>> CHANNEL>
+        <PRINC <CHANNEL-TYPE .OTH> .OUTCHAN>)
+       (<TYPE? .OTH FIX>
+        <PRINC "GIVETTY" .OUTCHAN>)
+       (T
+        <PRINC "TTY" .OUTCHAN>)>
+  <PRINC " OUTPUT:" .OUTCHAN>
+  <COND (<TYPE? <SET OTH <FORK-OUTPUT .FORK>> CHANNEL>
+        <PRINC <CHANNEL-TYPE .OTH> .OUTCHAN>)
+       (<TYPE? .OTH FIX>
+        <PRINC "GIVETTY" .OUTCHAN>)
+       (T
+        <PRINC "TTY" .OUTCHAN>)>
+  <PRINC !\] .OUTCHAN>>
+
+<MSETG FORK-STATUS-QUIT 1>
+<MSETG FORK-STATUS-KILLED 2>
+<MSETG FORK-STATUS-DIED 3>
+<MSETG FORK-STATUS-DEAD 4>
+<MSETG FORK-STATUS-RUNNING 5>
+<MSETG FORK-STATUS-STOPPED 6>
+<MSETG FORK-STATUS-WAIT 7>
+<DEFINE TEST-FORK-STATUS (CHAN OPER WHICH "AUX" (FORK <CHANNEL-DATA .CHAN>)
+                         (OTH <ANDB <FORK-STS .FORK> ,ST-BIT-OTHER>))
+  #DECL ((CHAN) CHANNEL (WHICH) FIX (FORK) FORK)
+  <COND (<==? .WHICH ,FORK-STATUS-QUIT>
+        <COND (<AND <FORK-STS? .FORK ,ST-BIT-DEAD>
+                    <==? .OTH ,ST-OTH-QUIT>>
+               <FORK-DATA .FORK>)>)
+       (<==? .WHICH ,FORK-STATUS-KILLED>
+        <COND (<AND <FORK-STS? .FORK ,ST-BIT-DEAD>
+                    <==? .OTH ,ST-OTH-KILLED>>
+               T)>)
+       (<==? .WHICH ,FORK-STATUS-DIED>
+        <COND (<AND <FORK-STS? .FORK ,ST-BIT-DEAD>
+                    <==? .OTH ,ST-OTH-DIED>>
+               <FORK-DATA .FORK>)>)
+       (<==? .WHICH ,FORK-STATUS-DEAD>
+        <FORK-STS? .FORK ,ST-BIT-DEAD>)
+       (<==? .WHICH ,FORK-STATUS-RUNNING>
+        <FORK-STS? .FORK ,ST-BIT-RUNNING>)
+       (<==? .WHICH ,FORK-STATUS-STOPPED>
+        <COND (<NOT <FORK-STS? .FORK ,ST-BIT-RUNNING>>
+               <FORK-DATA .FORK>)>)
+       (<==? .WHICH ,FORK-STATUS-WAIT>
+        <FORK-STS? .FORK ,ST-BIT-TTY-WAIT>)>>
+
+<ENDPACKAGE>