c [2,20]BQM.FTN R RHODERICK AUG 1982 c USEPA/HERL/NTD c MD74B c Research Triangle Park, NC 27711 c Modified - MAR 1983 c added job priority capability, job status words, c reformatted ...BAT send line c RECEIVED DATA BLOCK from ...BAT - c REC15(1-9) -> CMD(1:27) (coded in RAD50) c CMD(1:1) is the function code: c A - awaken request from ...BAT c C - disable processing (after current job finishes) c D - disable processing (abort any current job) c E - enable processing (if cmd(2:3) is 'TT', then cmd(4:5) is c the terminal# to log on as the batch log port) c F - future execution, delete c G - future execution, nodelete c H - immediate execution, delete c I - immediate execution, nodeletion c K - kill (abort) currently executing job c S - stop BATCH processor (after current job finishes) c X - stop BATCH processor (abort current job) c c R - remove job from queue file - CMD(2:4) contains c the queue entry number c CMD(2:5) - time to execute (hhmm) c CMD(6:11) - logon password c CMD(12:27) - job filespec - ddnnfffffffffxxx c REC15(10) -> logon UIC c REC15(11) -> job file UIC c REC15(12) -> job priority c RECEIVED DATA BLOCK from SPAWNR - c col 39: - A - logon of BATCH output log port failed c B - logon of BATCH output port successful c C - job completed c Batch job QUEUE file (LB:[1,7]BATCHQUE.SYS) format: c Record #1 - col 1: - next queue entry number (1 to 99 - binary) c col 2-24: BATCH processor status string (for ...BAT) c Record 2 to EOF - (for records with job entry number > 0 ) c col 1-4 - time to execute (hhmm) c col 5-16 - logon string - gggmmmpaswrd c col 17-38 - job filespec - ddnngggmmmfffffffffxxx c col 39: - delete/nodelete flag - 'Y' or 'N' c col 40: - job status flag- A : currently active job c C : entry marked Active in queue file c on processor startup - system c probably crashed during job c K : job was killed during execution, c either by BAT/KIL or BAT/STO:IM c P : pending job - waiting for current c job to complete c F : job scheduled for future execution c T : job timed out during execution c col 41: month to execute (binary) c col 42: day to execute job (binary) c col 43: job entry number in queue file (binary) c col 44: priority of job common irec byte d(9),t(8),next,r(45),s(48),day,month,code byte f(44),tmp(44),bluic(2),bfuic(2) character cmd*27,filine*44,spnlin*48,reclin*33,tim*8 logical*1 active,stop,err,enable,kill real mcr,bat,spawnr,batind integer*2 esb(8),rec15(15),devtyp,devno,luic,fuic integer*4 secs equivalence (r,reclin),(f,filine),(s,spnlin),(t,tim) equivalence (cmd(1:27),reclin(7:33)),(cmd(1:1),code) equivalence (bluic(1),luic),(bfuic(1),fuic) data mcr,bat,spawnr,batind/6rMCR...,6r...BAT,6rSPAWNR,6rBAT.../ data active,stop,enable,kill/.FALSE.,.FALSE.,.FALSE.,.FALSE./ data devtyp,devno/'TT',0/ call errset(24,.TRUE.,,,.FALSE.,) !no msg on eof on read errors call errset(25,.TRUE.,,,.FALSE.,) !no msg on rec outside range call errset(29,.TRUE.,,,.FALSE.,) !no msg on no such file errors call errset(30,.TRUE.,,,.FALSE.,) !no msg on file open errors c--startup message to CL: write(2,1) 1 format(/' BATCH scheduler started'/) open(unit=1,file='LB:[1,7]BATCHQUE.SYS',status='old', +recordtype='fixed',form='unformatted',associatevariable=irec, +access='direct',shared,err=6) c--get next unused entry number from first record of queue file, c then indicate processor is disabled (for ...BAT status msgs) irec=1 read(1'irec)filine next=f(1) filine(2:24)='Job processing disabled' irec=1 write(1'irec)filine c--initialization - scan thru file, reset any jobs with c "A"ctive status to "C"rashed status 4 read(1'irec,end=10)filine if(f(43).eq.0)goto 10 !past last rec if entry# zero if(filine(40:40).ne.'A')goto 4 ! filine(40:40)='C' irec=irec-1 write(1'irec)filine goto 4 c--no queue file found - open a new one 6 open(unit=1,file='LB:[1,7]BATCHQUE.SYS',status='new', +recordtype='fixed',form='unformatted',associatevariable=irec, +access='direct',recl=11,maxrec=58,initialsize=5,shared,err=970) c--initialize new queue file - put '1' in first rec (next entry number) c and string showing processing is disabled, then put c zero in cols 43 of rest of records (entry# field) irec=1 next=1 f(1)=1 filine(2:24)='Job processing disabled' f(43)=0 7 write(1'irec,err=10)filine goto 7 c--exit if we're waiting to stop and no job is currently executing 10 if(stop.and..not.active)goto 650 c--read next "P"ending job from queue file, or get minutes to wait c before starting next "F"uture job call getjob(mins,jrec) c--go back to sleep if job processing is disabled, or no job c needs to execute now, or if one is already active if(.not.enable.or.active.or.jrec.eq.0)goto 50 c--execute next pending job from queue file - (spawn spawnr task to execute it) irec=jrec read(1'irec)filine icur=f(43) !save this job's entry number write(spnlin(1:),20)filine(5:7),filine(8:10),filine(11:16), + filine(17:20),filine(21:23),filine(24:26), + filine(27:35),filine(36:38) 20 format('HEL ',a3,'/',a3,'/',a6,a4,':[',a3,',',a3,']',a9,'.', +a3,' ') if(filine(39:39).eq.'Y')spnlin(46:48)='/DE' c--compact out spaces in filespec so indirect's delete switch will work j=32 do 25 i=33,48 if(s(i).eq.' ')goto 25 j=j+1 s(j)=s(i) 25 continue if(j.lt.48)spnlin(j+1:48)=' ' !blank rest of line call spawn(spawnr,,,,,,,spnlin,48,devno,devtyp) c--cancel any previous command to run ...BAT to wake us up, then c schedule ...BAT to wake us up when next queued entry comes due 50 call canall(bat) !cancel time based run of ...BAT call time(t) !get current time in seconds read(tim(7:8),60)i 60 format(i2) !get seconds to next minute secs=mins !convert minutes to wait to i*4 secs=(secs)*60-i !compute time to wait in seconds i=min(secs,32767) !can't pass >32767 in run directive call run(bat,,i,2) !run ...BAT i seconds from now c--close queue file 70 close(unit=1) c--issue receive-or-stop directive call rcst(,rec15,idsw) c--continue processing here whether we first stopped or not if(idsw.eq.2)call receiv(,rec15) c--open queue file open(unit=1,file='LB:[1,7]BATCHQUE.SYS',status='old', +recordtype='fixed',form='unformatted',associatevariable=irec, +access='direct',shared,err=970) c--decode received data block call r50asc(33,rec15,reclin) if(reclin(1:6).eq.'SPAWNR')goto 500 if(code.eq.'A')goto 10 if(code.eq.'C'.or.code.eq.'D'.or.code.eq.'E')goto 400 if(code.eq.'F'.or.code.eq.'G'.or.code.eq.'H'.or.code.eq.'I')goto 100 if(code.eq.'K')goto 200 if(code.eq.'R')goto 300 if(code.eq.'S')stop=.true. if(code.eq.'X')goto 600 goto 10 !if none of the above, must just be ...BAT unstopping us c--add batch job entry to queue file c--make file line from received data block info 100 luic=rec15(12) !logon uic fuic=rec15(13) !job filespec uic write(filine,101)cmd(2:5),bluic(1),bluic(2),cmd(6:15), + bfuic(1),bfuic(2),cmd(16:27) 101 format(a4,2o3.3,a10,2o3.3,a12) filine(39:40)='NF' !tentative nodelete/future job if(code.eq.'F'.or.code.eq.'H')filine(39:39)='Y' !delete? if(code.eq.'H'.or.code.eq.'I')filine(40:40)='P' !immediate? c--put next entry number in this entry's queue line f(43)=next c--put month/day of command execution in filine(41:41) and (42:42) call idate(i,id,iy) f(41)=i f(42)=id call time(t) c--put current time in request if user wants immediate execution if(code.eq.'H'.or.code.eq.'I')write(filine(1:4),110)t(1),t(2),t(4),t(5) 110 format(4a1) c--determine which day to execute the job (today or tomorrow) read(tim(1:5),120)i,j 120 format(i2,x,i2) itime=i*60+j !current minute of the day read(filine(1:4),125)i,j 125 format(2i2) jtime=i*60+j !minute of the day to execute if(itime.gt.jtime)f(42)=f(42)+1 !mark it to execute tomorrow? c--put job priority in file line f(44)=rec15(14) c--now find first empty rec in queue file call getrec(0,tmp,err) if(err)goto 150 c--write this entry to queue file write(1'irec)filine c--increment and save the "next available entry number" next=next+1 if(next.gt.99)next=1 irec=1 read(1'irec)filine f(1)=next irec=1 write(1'irec)filine goto 10 c--came to end of queue file without finding an unused record 150 write(2,155)filine(17:20),filine(21:23),filine(24:26), + filine(27:35),filine(36:38) 155 format(/' WARNING - BATCH Queue file overflow -' +'entry discarded: ',A4,';[',A3,',',A3,']',A9,'.',A3,//) goto 10 c--kill currently active job - abort BAT... task and let receive c msg from SPAWNR task clean up the mess 200 if(.not.active)goto 10 kill=.TRUE. call abort(batind) goto 70 c--remove entry from queue file 300 read(cmd(2:4),301)i 301 format(i3) c--find record with correct entry number call getrec(i,filine,err) if(err)goto 10 c--found desired record - remove it from queue file call remove goto 10 c--enable/disable processing of queued jobs 400 enable=.FALSE. irec=1 f(1)=next filine(2:24)='Job processing disabled' if(code.ne.'E')goto 410 enable=.TRUE. c--get terminal number for SPAWNR task to log on if this enable cmd sent it if(cmd(2:3).eq.'TT')read(cmd(4:5),404)devno 404 format(o2.2) write(filine(2:24),405)devno 405 format(' Jobs logged to TT',O2.2,': ') c--rewrite enabled/disabled string in first rec for ...BAT 410 write(1'irec)filine if(code.eq.'D')goto 200 goto 10 c--received data block from SPAWNR TASK - C CMD(1:1)= A - logon failed C B - logon successful - job started C C - job completed C D - job aborted after job time limit expired 500 if(code.ne.'B')active=.FALSE. call getrec(icur,filine,err) if(err)goto 10 if(kill)goto 505 !was the job killed by this task? if(code.ne.'B')goto 510 c--job started - mark status as 'A'ctive active=.TRUE. f(40)='A' write(1'irec)filine goto 70 c--job was killed by this task - change status code in queue file to 'K' 505 f(40)='K' kill=.FALSE. goto 515 c--if job timed out - change it's status code in queue file to 'T' 510 if(code.ne.'D')goto 520 f(40)='T' 515 write(1'irec)filine goto 10 c--logon failed or job completed - remove entry from queue file 520 call remove goto 10 c--exit functions: c--immediate exit - change status of job in queue file to 'K'illed 600 call getrec(icur,filine,err) if(err)goto 10 f(40)='K' write(1'irec)filine call abort(batind) c--immediate and wait-for-end-of-job exit 650 call canall(bat) !cancel any time-based request for ...BAT task c--record disabled processing status in queue file (for ...BAT) irec=1 read(1'irec)filine filine(2:24)=' No BATCH processor' irec=1 write(1'irec)filine if(active)call abort(batind) call canall(bat) !cancel any time-based request for ...BAT task goto 999 970 write(2,975) 975 format(/' BQM - CANNOT OPEN QUEUE FILE - EXITING'//) 999 call exit end SUBROUTINE GETJOB(mins,jrec) C Searches through the BATCH queue file for a job to execute - C returns minutes to wait until the next future job scheduled, and C record number of a job to execute immediately if there is one C Preference is by job priority and scheduled execution time - if C several jobs are "P"ending (should have begun execution by now, C but are waiting for a current job to finish), this routine returns C the record number of the entry which should have executed earliest. C If more than one job is pending, then the record number of the first C one in the queue file, or the job with the highest priority is C returned. Any entries with a status of "F"uture which are scheduled C to execute at the current date/time are changed to "P"ending. common irec character filine*44,t*8 byte f(44),p(2) integer*2 curtim,fitime,pndtim,fday,day,pri,hipri equivalence (f,filine),(p,pri) hipri=0 pndtim=1 irec=2 mins=1440 jrec=0 call time(t) read(t(1:5),1)ih,im 1 format(i2,x,i2) curtim=ih*60+im call idate(i,day,iyr) if(j.eq.1.and.day.eq.1)i=13 !fudge at end of year day=(i-1)*31+day 10 read(1'irec,end=100)filine if(f(43).eq.0)goto 100 fday=f(41) fday=(fday-1)*31+f(42) !day for job's execution read(filine(1:4),11)ih,im 11 format(2i2) fitime=ih*60+im+(fday-day)*1440 i=fitime-curtim if(filine(40:40).eq.'P')goto 30 if(filine(40:40).ne.'F')goto 10 c--"F"uture job - check how long until it executes if(i.le.0.or.fday.lt.day)goto 20 if(i.lt.mins.and.i.gt.0)mins=i goto 10 c--"F"uture job's scheduled time is same as (or earlier than) current time - c change it to "P"ending status 20 filine(40:40)='P' irec=irec-1 write(1'irec)filine c--"P"ending job - 30 p(1)=f(44) if(pri.gt.hipri)goto 40 !does this job have greater priority if(pri.lt.hipri.or.i.ge.pndtim)goto 10 !if same pri, how long waiting c--save priority, record number & waiting time 40 hipri=pri pndtim=i jrec=irec-1 goto 10 100 return end SUBROUTINE REMOVE C Blanks a record in the queue file to effectively delete it C as an entry, then packs all following records toward the C beginning of the file common irec character filine*44 byte f(44),empty(44) equivalence (f,filine) data empty(43)/0/ c--write zero entry number in the record to be "removed" write(1'irec)empty c--now look for another record after this one 10 read(1'irec,end=100)filine if(f(43).eq.0)goto 100 c--good record - move this record back one record in file, c then zero this record's position in the queue file irec=irec-2 write(1'irec)filine write(1'irec)empty goto 10 100 return end SUBROUTINE GETREC(irecno,rec,err) c call with entry# in irecno: c if no such entry# in file, err returns as .TRUE. c returns with irec set to entry#'s record and record from file in rec c can also find first empty record in file if called with irecno=0 common irec character rec*44,filine*44 byte f(44) equivalence (f,filine) logical*1 err err=.TRUE. irec=2 10 read(1'irec,end=100)filine if(irecno.eq.f(43))goto 20 if(f(43).eq.0)goto 100 goto 10 20 err=.FALSE. irec=irec-1 rec=filine 100 return end