%begin;               !batch stream initiator

   %owninteger sub1, sub2, sub3
   %conststring(17) subsys = "SUBSYS:subsys.exe"

   %recordformat parmfm(%shortinteger dsno, dact, ssno, sact, %C
                        %integer p1, p2, p3, p4, p5, p6)
   %record(parmfm) p, pp, Q
   %recordformat procfm(%integer process, file, name, OWNER)
   %record(procfm)%array procs('A':'Z')
   %record(procfm)%name proc

   %integer jobs, max jobs, job limit
   %owninteger  QUEUE ID = 0               {to ensure consistency}
   %integer process, pfile, reason, password
   %routine report(%string(23) text)
      %record(parmfm) p
      string(addr(p_p1)) = text
      p_dsno = 0
      svc(120, p)
   %end
   %routine spare process
      %integer j
      %for j = 'A', 1, 'A'-1+max jobs %cycle
         proc == procs(j)
         %if proc_process = 0 %start
            %return
         %finish
      %repeat
      report("Process overflow")
      svc(1, p);    !stop
   %end

   %routine find(%integer process)
      %integer j
      %for j = 'A', 1, 'A'-1+max jobs %cycle
         proc == procs(j)
         %return %if proc_process = process
      %repeat
      report("Process lost")
      svc(1, p);  !stop
   %end

   %routine release(%integer process)
      find(process)
      proc_process = 0
   %end

   %ROUTINE INFORM(%INTEGER OWNER, END)
      %RECORD(PARMFM) P
      P_P2 = OWNER;  SVC(5, P)
      %IF P_P1 # 0 %START
         P_DSNO = P_P1
         %IF END = 0 %THEN STRING(ADDR(P_P1)) = "Batch job started" %c
                     %ELSE STRING(ADDR(P_P1)) = "Batch job finished"
         SVC(120, P)
      %FINISH
   %END
   %routine initialise
      %record(parmfm) p
      %ownstring(7) proc name = "BG@:"
      %integer j
      %for j = 'A', 1, 'Z' %cycle
         charno(proc name, 3) = j
         string(addr(p_sact)) = proc name
         svc(17, p)
         procs(j)_process = 0
         procs(j)_file = 0
         procs(j)_name = p_p2
      %repeat
   %end

   {Store initial message into P so it can be interrogated}
   *STME_0,P
RECONFIGURE:
   queue id = p_p3;  max jobs = p_p4;  job limit = p_p5

REPRIME:
   jobs = 0
   max jobs = 1 %if max jobs <= 0 %or max jobs > 26
   job limit = max jobs %if job limit > max jobs
   string(addr(p_sact)) = subsys;  svc(17, p)
   sub1 = p_p2;  sub2 = p_p3;  sub3 = p_p4

   initialise

   p_dact = 2;                  !attach
   p_p1 = queue id
   p_p2 = 5;                    !sact for reply
   svc(22, p)
   %if p_p6 # 0 %start
      report("Attach fails")
      *=0
   %finish

MORE:

   %while jobs < job limit %cycle
      p_dact = 4;                  !claim
      svc(22, p)
      %exit %if p_p6 < 0;                  !not available
      pfile = p_p1
      pp_dact = 7;  pp_p1 = pfile;  svc(22, pp);   !locate
      password = 0
      %if pp_sact = 2 %start
         password = pp_p5
         pp_p5 = 0
      %finish
      %exit %if pp_p6 < 0
      %cycle
         spare process
         proc_file = pfile
         p_p1 = 0;                            !any unit
         p_p2 = proc_name;                !owner
         p_p3 = sub1
         p_p4 = sub2
         p_p5 = sub3
         p_p6 = 0;                            !not privileged
         svc(109, p);                         !start process
         %exit %if p_p6 = 0
         report(string(addr(p_p1)))
         proc_process = -1
      %repeat
      process = p_p3;                      !process number
      proc_process = process
      p_dact = 6;  p_p1 = pfile;  svc(22, p);    !identify
      pp_p5 = p_p3;  pp_p6 = p_p4
      pp_dsno = process+64;  pp_dact = 2
         p_dact = 27;         !become
         p_p3 = password
         proc_owner = p_p2;  inform(proc_owner, 0)
         p_p6 = process
         svc(20, p)
         report("Batch: cannot become") %if p_p6 # 0
      svc(115, pp);                        !send it its input file
      jobs = jobs+1
   %repeat

   !come here to wait

   p_sact = 0;  svc(16, p);                  !poff


   %if p_dact = 1 %start                      {reconfigure initiator}
      -> RECONFIGURE
   %finish

   %if p_dact = 3 %start;                     !update jobs
      %if 0 <= p_p1 <= 26 %start
         job limit = p_p1
         job limit = max jobs %if job limit > max jobs
         report("initiator suspended") %if job limit = 0
      %else
         report("Number of jobs?")
      %finish
      ->MORE
   %finish

   %if p_dact = 8 %start;                     !process stops
      jobs = jobs-1
      process = p_p1
      find(process)
      inform(proc_owner, 1)
      pp_dact = 9;  pp_p1 = proc_file;  svc(22, pp);   !delete
      release(process)
      ->MORE
   %finish
   %if p_dact = 5 %start;                     !something on queue
      ->MORE
   %finish
   ->REPRIME %if p_dact = 2 %and p_p2 = 7
   report("Bad message")
   ->MORE

%endofprogram
