DataMuseum.dk

Presents historical artifacts from the history of:

RC4000/8000/9000

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about RC4000/8000/9000

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦b0c429652⟧ Rc489k_TapeFile, TextFile

    Length: 143616 (0x23100)
    Types: Rc489k_TapeFile, TextFile

Derivation

└─⟦aa55fa693⟧ Bits:30007479 SW8110/1 TAS/SOS/PRIMO Rel 2.3
    └─⟦this⟧ 

TextFile

!             ***  tsos  ***
;
;
; swopping online system for execution of a number of interactive processes
; in the same piece of core
;
; release 3.0 mar. 1982 knud christensen, edith rosenberg, flemming biggas
; release 3.1 aug. 1982 flemming biggas
; release 3.2 apr. 1983 flemming biggas
; release 3.3 aug. 1984 flemming biggas
; release 4.0 aug. 1985 flemming biggas (mp release).
; release 5.0 sep. 1986 flemming biggas
; release 6.0 may. 1987 flemming biggas (tas version)
; release 6.1 jul. 1988 flemming biggas (error correction)
;           1 - linie 840 - input message - forkert bufsize
;           2 - linie 844 - input message - mode og trail
; release 7.0 oct. 1988 flemming biggas (RC9000-10)
; release 7.1 jul. 1989 flemming biggas (error correction)
; release 7.2 nov. 1989 flemming biggas (error correction)
;           1 line 1422 - tem message - forkert operations check
;           2 line 1472 - tem message - manglende check messgot
; release 7.3 jan. 1990 flemming biggas (error correction)
;           1 line 1630 - reject control message when waiting for first input message
!

onlinesystem
begin
  !fp.no;
  !branch 1,2;
  !sections 40;

procedure prepare(.w3.);
comment prepare process to be activated;

procedure waitevent(.w3.;w0;w1;w2);
comment call:   w0 irrelevant
                w1 irrelevant
                w2 irrelevant
        return: w0 event kind
                w1 abs ref userentry
                w2 abs ref eventbuffer
;

procedure unintelligible(.w3.;w1);
comment call:   w1 abs ref userentry
        return: all registers unchanged
;

procedure send_primo(.w3.;w1;w2);
comment call:    w1 abs ref userentry
                 w2 abs ref message sent to pseudo process primo
        return:  w1 abs ref userentry
                 w2 abs ref message sent to primo (real process)
                 w3 old w2 (from call)
;

procedure primess(.w3.);


procedure send(.w3.;w0;w1;w2);
comment call:   w0 kind of event to be send
                w1 abs ref userentry
                w2 first word of message or answer
        return: -- all registers unchanged
;
procedure action (.w3.;w0;w1;w2);
comment call:    w1 abs ref userentry
                 w2 abs ref event
        return:  -- all registers unchanged
;

procedure  send_control (.w3.;w1;w2);
comment call:    w1 abs ref userentry
                 w2 abs ref control message
        return:  -- all registers unchanged
;

procedure link(.w3.;w1;w2);
comment call:   w1 abs ref userentry to be linked
                w2 abs ref userentry after which to link w1
        return: w1 unchanged
                w2 unchanged
;

procedure swop(.w3.;w1);
comment call:   w1 abs ref userentry of process to be swopped in
        return: w1 unchanged
;

procedure copy(.w3.;w0;w1;w2);
comment call:   w0 no of bytes to copy
                w1 abs from
                w2 abs to
        return: -- all registers unchanged
;

procedure startstop(.w3.;w0;w1);
comment call:   w0 boolean stop or start process
                w1 abs ref userentry of process to start-stop
        return: -- all registers unchanged
;

procedure transport(.w2.;w1;w3);
comment call:   w1 abs ref message to be send
                w3 abs ref area name
        return: -- all registers unchanged
;

procedure continuemcl (.w3.;w0;w1);
comment call:   w0 exit cause
                w1 abs ref of userentry
        return: -- all registers unchanged
;

procedure empty_answer (.w3.;w0;w1;w2);
comment call: link       w3 
              result         w0
              user entry        w1
              status word          w2;


procedure parentmess(.w3.;w1;w2);
comment call:   w1 abs ref userentry of sending process
                w2 abs ref message buffer
        return: -- all registers unchanged
;

procedure syscommand(.w3.;w1);
comment call:   w1 abs ref userentry of commanding user
        return: -- all registers unchanged
;

procedure scancat(.w3.;w0;w1;w2);
comment call:      w1  abs ref process name
                   w2  abs ref terminal name or zero
        return:    w0  result  -3 = usercat reservation error
                               -2 = terminal unknown
                               -1 = process unknown
                              >=0 = ok (catalog segm.no)
                   w1  abs ref process description
                   w2  abs ref terminal description or zero
;

procedure break(.w3.;w1);
comment call:    w1  abs ref userentry to break
        return:  --  all registers unchanged
;

procedure clean(.w3.;w1);
comment call:   w1 abs ref userentry
        return: -- all registers unchanged
;

procedure compare(.w3.;w0;w1;w2);
comment call:   w0 no of bytes to compare
                w1 abs 1.string
                w2 abs 2.string
        return: w0 = 0 the bytes are equal
;

procedure nextchar(.w3.;word stp;w0;w1;w2);
comment call:   w0 irrelevant
                w1 partial word
                w2 abs ref next input word
                w3 return
                stp abs ref word next to last input word
        return: w0 next character
                w1 partial word
                w2 abs ref next input word
;

procedure init(.w3.);
comment call:   -- all registers irrelevant
        return: -- all registers destroyed
;

procedure opmess(.w3.;w1;w2);
comment call:   w1 abs ref message,
                w2 abs ref sender process description
;

procedure logout(.w3.;w1);
comment call:   w1 abs ref userentry
        return: -- jumps directly to main program
;

procedure outtext(.w3.;w0;w1;w2);
comment call:   w0 format pattern:
                   bits 21-23: type of message
                               0 = normal
                               1 = error
                               2 = warning
                               3 = pending
                               4 = normal
                   bit 20:     time (yes or no)
                   bit 19:     system name (yes or no)
                   bit 18:     job name (yes or no)
                w1 abs ref userentry
                w2 text number
        return: --  all registers unchanged
;

procedure outtime(.w3.;w2);
comment call:   w2 abs ref buffer
        return: -- all registers unchanged
;

procedure calldev(.w3.;w1);
comment call:   w1 abs ref string1
        return: w1 abs ref error message or zero
;

procedure testout(.w3.;w0;w1;w2);
comment call:   w0 length of testrecord
                w1 abs ref first word of record
                w2 kind of testrecord
        return: w0 destroyed
                w1 unchanged
                w2 unchanged
;

    label continue, interrupt, initialize, action_l, activate, regrettimer, discfault;

  record name (double name1,name2);
  record answer (word status,bytes,characters);
  record message (ref  nextmess,lastmess,receiver,sender;
                  byte operation,mode;
                  ref  mbfst,mblst;
                  word segmno;
                  ref mbilast);
  record userentry (ref  nextuser,prevuser,buffer,
                         messgot,messsend,procbuf1,peripheral,internal,primdevi;
                    word swopsegm,class,prio;
                    byte state,state2,buflength,bufchars,intervent,primio,bufrel;
                    word statusinf,currlocid,procsize;
                    text(14) pr_in,pr_out);
  record termdescr
        (text(11) extid;
         word intid;
         text(11) userkey;
         byte tbufs,ttimers;
         array(1:6) tfill of byte);
  record procdescr
        (byte procbuffers,procareas;
         word procsb1,procsb2,
              procub1,procub2,
              procmb1,procmb2;
         text(11) ppass;
         word pminsize,pmaxsize;
         array(1:10) pfill of byte;
         text(59) procfp;
         array(1:12) procdiscs of record procdisc
                                       (text(11) procdiscname;
                                        array(1:8) procdiscclaim of word
                                       )
        );
  record prindex (text(11) prname;
                    word prsegmno);
  incode
    ref  activqfst,activqlst,
         batchqfst,batchqlst,
         waitqfst,waitqlst,
         coreuser:=0,timermess:=0,
         firstuser,lastuser;
    word maxbuf,minprio,maxtestsegm,syscond,passmode,batchclass:=-8000000;
    word register0,register1,register2,register3,exception:=0,ic;
    word ownproc, sosterm;
    word basereg;
    text(14) procname,timer:="clock";
    text(2) att:="
>"; word timeunit:=0,interval;
    word micunit:=2;
    double micinterval:=600;
    byte testop:=5,testmode:=0;
    ref  testbfst,testblst,testsegm:=0;
    ref  fstcore,topcore;
    ref baseevent:=0,mainconsref,mictimer,psmess;
    double starttime,startbase;
    byte relintrpt,reldump,idsize,sysstate:=0;
    byte childpr,childpk,timerloss,cyclegain,inputgain,freebufs;
    text(11) operator:= "'255'";
    text (14) tstarea,swname,fpcode,cleartemp,usercat,t_mdul,p_mdul,p_pseudo,t_pseudo;
    byte fp_rel,cleart_rel;
    byte faultop:=2,faultmode:=1;
    text(20) faulttext:="***fault";
  begin
\f


    comment    the following piece of code is after initialization used as
               buffer for  wait answer, and as interrupt routine
               in case of internal interrupt or !test
    ;
    ownproc:= w3;    ! save own process description address !
interrupt:
    w3:=address(interrupt)+2;
    w0:=0;
    monitor(0);   comment set interrupt address;
    mainconsref:=w2;
    goto initialize;
    w1+0;
    w1+0;
    w1+0;
    testout(.w3.,w0:=16,w1:=address(interrupt)+2,w2:=7);
    !get 2;
    if w0 <> 1 then goto discfault;
    opmess(.w3.,w1:=address(faultop),w2:=ownproc);
initialize:
    !get 2;
    if w0 <> 1 then goto discfault;
    init(.w3.);
\f






comment     the central logic of the onlineadministrator is this:

a) wait for an event from a terminal, from an internal process
   or from the timer

b) take some action corresponding to the kind of the event arrived
   -  this action may include stopping the running process

c) if the running process is stopped then select new process for
   activation (if anyone is ready) and swop

d) take some action corresponding to the state of the process
   that is selected for activation (copy input from buffer into
   the process etc)

e) start the process, send a message to timer and goto a.
;

continue:
    waitevent(.w3.,w0,w1,w2);
action_l:
    userentry:=w1;
    message:=w2;
    action (.w3.,w0,w1,w2);



regrettimer:
    if w2:=timermess<>0 then 
    begin
      monitor(82);  comment regret message;
      w2:=0;
      timermess:=w2;
    end;
\f





comment     selection of the next process to be activated

the system deals with two different queues:

1) the active-queue    processes ready for running (input has arrived etc)
2) the waiting-queue   processes suspended or not used at all

at activation the first user in the activequeue (if any) is tested for
his priority - is it zero then the process is selected for activation
- otherwize the priority is increased, and the user is removed from the
activequeue and then put back on the queue again
;

activate:
    userentry:=w1:=activqfst;
    if w0:=address(activqfst) <> w1 then     ! activequeue not empty !
    begin
      if w0:=(w1).state = 0 then
      if w0:=(w1).class+timerloss < batchclass then     ! job is batch !
      begin
        link(.w3.,w1,w2:=address(batchqfst));
        goto activate;
      end;
    end else
    begin        ! activequeue empty !
      userentry:=w1:=batchqfst;
      if w0:=address(batchqfst) = w1 then goto continue;  ! batchqueue also empty !
    end;
    if w0:=(w1).state<0 then
    begin ! systemcommand !
      swop(.w3.,w1:=0);
      !get 2;
      if w0 <> 1 then goto discfault;
      syscommand(.w3.,w1:=userentry);
    end else
    if w0:=(w1).prio<0 then
    begin
      if w0+cyclegain > 0 then w0:=0;
      (w1).prio:=w0;
      link(.w3.,w1,w2:=address(activqfst));
    end else 
    begin 
      if w0:= (w1).class > b.batchclass then
      (w1).prio:= w0:= (w1).class;
      prepare(.w3.);
      w1:= address(timeunit);
      w3:= address(timer);
      monitor(16);
      timermess:= w2;
      startstop(.w3.,w0:=1,w1:=coreuser);
      goto continue;
    end;
    goto activate;

\f




comment in case of a disc fault disturbing the overlay transports, this piece
of code will be activated  -
the octal status, result of the transport and the name of the program area
will be written on the main console and the "sos process" will die;


discfault:
    register0:=w0;
    register3:=w3;
    w1:=firstuser;
    (w1).peripheral:=w2:=mainconsref;
    (w1).buflength:=w2:=44;
    (w1).buffer:=w2:=address(faulttext);
    (w2+14).word:=w0:=2111527;   !  " 8'"  !
    for w1:=-21 step 3 upto 0 do
    begin
      w2+2;
      (w2).word:=w0:=register0 lshift (w1) extract 3 + 48;
    end;
    (w2+2).word:=w0:=32;
    copy(.w3.,w0:=8,w1:=register3,w2+2);
    (w2+8).word:=w0:=10;
    send(.w3.,w0:=0,w1:=firstuser,w2:=20480);
    w3:=0;
    monitor(0);  ! set interrupt !
    !halt 1;   ! provoke running after error !

  end;

\f



  body of action
  begin
    label actioncase, emptyanswer, repeatmaybe, a_ready, stopcoreuser,
          timeout, semibusy, messwait;
    incode double savef1, savef3;
           ref mess, user;
            word mss0,mss2,mss4,mss6,mss8,mss10,mss12,mss14,help;
    begin


comment     actions corresponding to the kind of the event arrived:

1) input message from internal process -
     the process is stopped and the input message is sent to the terminal
     if it is ready, otherwize the input message is linked to the user-
     description, waiting to be sent, when the terminal becomes ready
     if the priority class is negative then it is increased

2) output message from internal process -
     if the terminal is ready (there is room in the terminal buffer),
     the output is copied from the process into the buffer, an answer
     is sent to the process, and an output message is sent to the ter-
     minal
     if the terminal is not ready, the internal process is stopped and
     it is given an answer, telling that no bytes are transferred, then
     at restart, the process will repeat the outputmessage

3) parent message from internal process -
     finis: the process is removed, and the userdescription cleared
     break: the process is stopped, and prepared for loading with new abs program
     ***    any other parent message is rejected for the moment

4) attention from known terminal -
     treated as an interrupt. the process is stopped and an inputmessage
     is send to the terminal asking for a system command

5) answer from known terminal -
     input answer:  the process is prepared for restart
     output answer: if the process is waiting then it is prepared for
                    restart otherwize nothing is to be done

6) attention from unknown terminal -
     the terminal is linked to a free userdescription and an input is send
     to the terminal asking for the users identification

7) answer from timer -
     the process running in core has used its time-slice and therefore
     it is stopped to make room for other users
     the priority class of this process is decreased

8) message from a bastard
     at s-replacement sos may take over some unknown children (bastards)
     parent messages from these children are written on the main console

9) message to a pseudo process called tem

10) message to be send later

11) message to a pseudo process called primo

12) message to be send to primo later

13) control message to terminal
;
\f


    savef1:= f1;
    savef3:= f3;
    user:= w1;
    mess:= w2;
actioncase:
    case w3:=w0 of
    begin

! action 1 !
      begin comment input message from internal process;
        if w3:=b.syscond onemask 2'010 then
        if w3:=(w1).intervent = -1 then goto timeout;
        if w3:=(w1).state<0 then
        begin
          empty_answer(.w3.,w0:=1,w1,w2:=0);
        end else
        if w3>0 then
        begin
          (w1).state:=w0:=5;
        end else
        begin
          (w1).procbuf1:= w0:= (w2).mbfst;
          (w1).state:= w0:= 1;
          if w0:=(w1).state2=-1 then
          begin ! fp command ready !
            if w1=b.coreuser then
            begin
              if w2:=b.timermess<>0 then
              begin
                monitor(82); ! regret !
                w2:= 0;
                b.timermess:= w2;
              end;
            end;
            (w1).state2:= w0:= 0;
            if w0:= (w1).intervent=0 then goto repeatmaybe else
            (w1).intervent:= w0:= 0;  ! no fp command in buffer at restart after break !
          end;
           w0:= (w2).mbfst;
          w3:= (w2).mblst;
          w3-w0+2;
          if w3>b.maxbuf then w3:= b.maxbuf;
          (w1).buflength:= w3;
           w2:= address ((w2).operation);
           send (.w3.,w0:=0,w1,w2:=(w2).word);
        end;
        link(.w3.,w1,w2:=address(b.waitqfst));
        startstop(.w3.,w0:=0,w1);
      end;
\f


! action 2 !
      begin comment output message from internal process;
        if w0:=(w1).state<0 then
        begin
          empty_answer(.w3.,w0:=1,w1,w2);
          goto b.continue;
        end else
        if w0=0 then
        begin
          if w1 = b.coreuser then
          begin
            w3:=(w1).internal+11;
            w3:=(w3).byte;
            if w3 and 2'10100000=2'10100000 then ! stopped !
            begin
              (w1).state:=w0:=6;
              startstop(.w3.,w0:=1,w1);
            end;
            b.idsize:=w0:=(w1).primio;
            w0:=(w2).mblst-(w2).mbfst+2;
            if w0>=b.maxbuf then w0:=b.maxbuf-b.idsize;
            (w1).buflength:=w0+b.idsize;
            w3:=w0-b.idsize-2;
            w1:=(w1).buffer+b.idsize;
            w3+w1;
            monitor(70); ! copy !
            if w0<>0 then ! unintelligible !
              unintelligible(.w3.,w1:=user)
            else
            begin
              w0:=w1;
              w1:=user;
              w2:=(w1).buffer;
              if w3:=b.idsize > 0 then
                (w2).word:=w3:=(w1).currlocid;
              (w1).buflength := w0 := (w1).buflength - b.idsize;
              (w1).bufchars := w0 + (w3:=w0 ashift -1);
              testout (.w3.,w0:= (w1).buflength, w1:=w2, w2:=0);
              send (.w3.,w0:=0,w1:=user,w2:=20480+mess.mode);
              send (.w3.,w0:=1,w1,w2:=0);
              if w0:=6=(w3:=(w1).state) then startstop(.w3.,w0:=0,w1);
              (w1).state:=w0:=2;
            end; ! message ok !
            if w0:=6=(w3:=(w1).state) then ! stop it again !
            begin
              (w1).state:=w0:=0;
              startstop(.w3.,w0:=0,w1)
            end
          end else
          begin
emptyanswer:
            (w1).state:=w0:=0;
            empty_answer(.w3.,w0:=1,w1,w2:=0);
            goto a_ready;
          end;
          if w0:=b.timermess <> 0 then goto b.continue;
        end else goto emptyanswer;
      end;
\f


! action 3 !
      begin comment parent message from internal process;
        if w0:=(w1).state<0 then
        begin
          send(.w3.,w0:=2,w1,w2:=0);
          goto b.continue;
        end;
        if w1:=b.coreuser > 0 then startstop(.w3.,w0:=0,w1);
        swop(.w3.,w1:=0);
        !get 2;
        if w0 <> 1 then goto b.discfault;
        parentmess(.w3.,w1:=user,w2:=mess);
      end;



! action 4 !
      begin comment attention from known terminal;
        send(.w3.,w0:=1,w1,w2:=0);
        if w0:=(w1).state2>0 then goto b.continue;
        if w0:=(w1).state < 0 then goto b.continue;
        (w1).state:=w0:=-1;
        startstop(.w3.,w0:=0,w1);
        link(.w3.,w1,w2:=address(b.waitqfst));
        w2:=(w1).buffer;
        (w1).buflength:=w0:=2;
        copy(.w3.,w0,w1:=address(b.att),w2);
        testout(.w3.,w0,w1,w2:=0);
        send(.w3.,w0:=0,w1:=user,w2:=20480);
        (w1).buflength:=w0:=b.maxbuf;
        send(.w3.,w0:=0,w1,w2:=12288);
        if w1 = b.coreuser then goto b.regrettimer else goto b.continue;
      end;
\f


! action 5 !
      begin comment answer from known terminal;
        w2:=address(b.interrupt);
        case w3:=(w1).state+4 of
        begin
! -3 !    begin comment invisible password;
            w3:= (w1).messsend;  ! result !
            if w3 or (w2).status or (w2).bytes = 1 then
            begin  ! repeat invisible input, if normal answer and
                     bytes transferred = 0                        !
              (w1).buflength:= w0:= b.maxbuf - (w1).bufrel;
              w0:= (w1).bufrel;
              -(w0);
              send (.w3., w0, w1, w2:=12288+b.passmode);
              goto b.continue;
            end;
          end;
! -2 !    begin comment login information;
            goto repeatmaybe;
          end;
! -1 !    begin comment system command;
            goto repeatmaybe;
          end;
!  0 !    begin comment communication via pseudo process;
            w0:=(w1).messsend;
            w2:=(w1).messgot;
            if w2 > 10 then
            if w3:=(w2).operation extract 2 <> 3 then
            begin
              (w1).messgot:=w0;
              w1:=address(b.interrupt);
              monitor(22);  ! send answer !
              testout(.w3.,w0:=16,w1,w2:=61);
            end;
          end;
!  1 !    begin comment waiting for input answer;
            (w1).currlocid:= w0:= (w3:=(w1).buffer).word;
repeatmaybe:
            w3:=(w1).messsend;  comment w3 := result;
            if w3 or (w2).status or (w2).bytes = 1 then
            begin comment repeat input if normal answer, bytes trans-
                          ferred = 0;
              (w1).buflength:=w0:=b.maxbuf;
              send(.w3.,w0:=0,w1,w2:=12288);
              goto b.continue;
            end;
          end;
!  2 !    begin comment waiting for output answer;
            (w1).state:=w0:=0;
            goto b.continue;
          end;
!  3 !    begin comment waiting for load with new abs program  -  state not possible here;
          end;
!  4 !    begin comment suspended because of output buffer full;
            (w1).state:=w0:=0;
          end;
!  5 !    begin comment message waiting to be send;
            link(.w3.,w1,w2:=address(b.activqfst));
            mess:=w2:=(w1).messgot;
            (w1).state:=w0:=0;
            if w3:=(w2).receiver+b.ownproc = 0 then w0:=3 else
            if w3:=(w2).receiver+b.sosterm = 0 then
            begin
              if w3:=(w2).operation onemask 3 then w0:=1 else
              if w3 onemask 5 then w0:=2 else w0:= 13; 
            end else w0:= 9;
            goto actioncase;
          end;
!  6 !    begin ! waiting answer from primo !
          end;
!  7 !    begin ! message waiting to be send to primo !
            link(.w3.,w1,w2:=address(b.activqfst));
            mess:=w2:=(w1).messgot;
            (w1).state:=w0:=0;
            w0:=11;
            goto actioncase;
          end;
!  8 !    begin ! waiting for control answer !
            (w1).state:= w0:= 0;
            w0:= (w1).messsend; ! w0:= result !
            w2:= (w1).messgot;
            if w2 > 10 then
            begin
              (w1).messgot:= w0;
              w1:= address(b.interrupt);
              monitor (22); ! send answer !
              testout (.w3., w0:= 16, w1, w2:= 61);
            end;
          end;
        end;
        link(.w3.,w1:=user,w2:=address(b.activqfst));
a_ready:
        if w0:=b.timermess<>0 then 
        begin
          w1:= b.coreuser;
          if w0:= (w1).class + b.timerloss < b.minprio
          then goto stopcoreuser
          else goto b.continue;
        end;
      end;
\f


! action 6 !
      begin comment attention from unknown terminal;
        send(.w3.,w0:=1,w1,w2:=0);
        (w1).state:=w0:=-2;
        (w1).buflength:=w0:=2;
        w2:=(w1).buffer;
        copy(.w3.,w0,w1:=address(b.att),w2);
        testout(.w3.,w0,w1,w2:=0);
        send(.w3.,w0:=0,w1:=user,w2:=20480);
        (w1).buflength:=w0:=b.maxbuf;
        send(.w3.,w0:=0,w1,w2:=12288);
        goto b.continue;
      end;

! action 7 !
      begin comment answer from timer;
stopcoreuser:
        user:=w1:=b.coreuser;
        startstop(.w3.,w0:=0,w1);
        if w0:=(w1).class+b.timerloss < b.batchclass then (w1).prio:=w0:=0   ! batch !
        else
        begin   ! go/run-jobs ! 
          link(.w3.,w1,w2:=address(b.activqfst));
          (w1).class:=w0:=(w1).class-b.timerloss;
          (w1).prio:=w0;
          if w3:=b.syscond onemask 2'001 then
          if w0 < b.minprio then
          begin comment break process;
timeout:
            swop(.w3.,w1:=0);
            !get 2;
            if w0 <> 1 then goto b.discfault;
            break(.w3.,w1:=user);
            (w1).intervent:=w0:=5;
          end;
        end;
      end;

! action 8 !
      begin comment parent message from a bastard;
        swop(.w3.,w1:=0);
        !get 2;
        if w0 <> 1 then goto b.discfault;
        opmess(.w3.,w1:=address((w2).operation),w2:=(w2).sender);
      end;
\f


! action 9 !
      begin comment message to a pseudo process;
        if w1:=(w2).receiver < 0 then -(w1);
        copy(.w3.,w0:=8,w1+2,w2:=address(b.procname));
        copy(.w3.,w0:=16,w1:=mess+8,w2:=b.lastuser);
        w2:=mess;
        if w0:=(w2).operation onemask 1 then
        begin  ! io  - use sos buffer !
          w1:=user;
          if w1 <> b.coreuser then goto emptyanswer;
          w3:=b.lastuser-8;
          (w3).mode:=w0:=(w2).mode extract 6;
          (w3).mbfst:=w0:=(w1).buffer;
          w0:=(w2).mblst-(w2).mbfst+2;
          if w0 > b.maxbuf then w0:=b.maxbuf;
          (w1).buflength:=w0;
          user.bufchars:= w0 + (w1:=w0 ashift -1);
          w1:= user;
          w0 := (w1).buflength;
          (w3).mblst:=w0+(w3).mbfst-2;
          (w1).procbuf1:=w0:=(w2).mbfst;
          (w3).segmno:= w0:= (w2).segmno;
          if w0:=(w2).operation zeromask 2 then
          begin  ! some kind of output assumed !
            if w0:=(w2).mode onemask 8'100 then
            begin
              (w3).mblst:=w2:=(w3).mblst+2;
              (w2:=(w1).buffer).word:=w3:=(w1).currlocid;
              w2+2;
            end else w2:=(w1).buffer;
            copy(.w3.,w0:=(w1).buflength,w1:=(w1).procbuf1,w2);
            testout(.w3.,w0,w1,w2:=0);
            send(.w3.,w0:=1,w1:=user,w2:=0);
          end;
        end;

        begin   ! message to tem !
          copy(.w3.,w0:=6,w1:=user.internal+2,w2:=address(b.procname)+2);
          w3:=address(b.procname);
          b.mictimer:=w3;
          if w0:=mess.operation >= 90 then
          if w0 < 100 then
          begin   ! message concerning a pool !
            w0:=0;
            b.mictimer:=w0;
            b.baseevent:=w0;
            copy(.w3.,w0:=8,w1:=address(b.procname),w2:=b.lastuser+8);
            w3:=address(b.t_mdul);
          end;
        end;
        w1:=b.lastuser;
        monitor(16);   ! send message !
        user.messsend:=w2;
        b.psmess:=w2;
        if w0:=b.mictimer > 0 then
        begin
          w3:=address(b.timer);
          w1:=address(b.micunit);
          monitor(16);   ! send timer message !
          b.mictimer:=w2;
        end;
        w2:=b.baseevent;
semibusy:
        monitor(24);  ! wait next event !
        if w2 = b.psmess then
        begin
          w1:=b.lastuser;
          monitor(18);  ! wait answer !
          w3:=user;
          (w3).messsend:=w0;
          (w3).statusinf:=w0:=(w1).word;
          if w2:=(w3).messgot > 10 then
          begin
            if w0:=(w2).operation extract 2 = 3 then
            begin
              copy(.w3.,w0:=(w1).bytes,w1:=user.buffer,w2:=user.procbuf1);
              testout (.w3.,w0,w1,w2:=0);
              w3 := user;
              (w3).currlocid := w0 := (w1).word;
              w2 := (w3).messgot;
              w1 := b.lastuser;
            end;
          end;
          w0 := (w3).messsend;
          if w2 > 10 then
          begin
            if w3:=(w3).statusinf or w0 or 8'10200001 <> 8'10200001 then
            if w3:=(w2).operation onemask 1 then
            begin
              swop(.w3.,w1:=0);
              !get 2;
              if w0 <> 1 then goto b.discfault;
              logout(.w3.,w1:=user);
            end;
            user.messgot:=w0;
            monitor(22);  ! send answer !
            testout(.w3.,w0:=16,w1,w2:=61);
          end;
          if w2:=b.mictimer > 0 then monitor(82);  ! regret timer message !
          if w0:=b.timermess <> 0 then goto b.continue;
        end else
        if w2 = b.mictimer then
        begin
          startstop(.w3.,w0:=0,w1:=user);
          link(.w3.,w1,w2:=address(b.waitqfst));
        end else goto semibusy;
      end;
\f


! action 10 !
      begin comment wait for previous message to be answered;
        w2:=5;
messwait:
        if w0:=(w1).state < 0 then
        begin
          (w1).buflength:=w0:=0;
          send(.w3.,w0:=1,w1,w2:=8'200000);
        end else
        begin
          startstop(.w3.,w0:=0,w1);
          (w1).state:=w2;
          link(.w3.,w1,w2:=address(b.waitqfst));
        end;
        if w1 <> b.coreuser then goto b.continue;
      end;


! action 11 !
      primess(.w3.); ! messsage to primo !


! action 12 !
      begin ! message to be send later to primo !
         w2:=7; goto messwait;
      end;
! action 13 !
      begin ! control message to terminal !
        if w0:= (w1).state < 0 then
        begin
          empty_answer (.w3., w0:= 1, w1,w2:=0);
          goto b.continue;
        end else
        if w0 = 0 then
        begin
          if w0 := (w1).state2 = -1 then
          begin comment state waiting for first input, reject message;
            w2 := (w1).messgot;
            w0:= 2;(w1).messgot := w0;
            w1 := address(mss0);
            monitor (22); ! send answer !
            testout (.w3.,w0:=2, w1:= address((w1:=user).messgot), w2:= 61);
            goto b.continue;
          end;
          send_control (.w3.,w1, w2);
          (w1).state:= w0:= 8; ! waiting for control answer !
          goto b.continue;
        end else
        begin
          (w1).state:= w0:= 5;
        end;
      end;
    end;
    f1:= savef1;
    f3:= savef3;
  end;
end; ! action !
\f





comment       preparation of process waiting to be activated

first of all the process image in core is possibly written back into the
swoparea and the image of the new process is loaded
then one of the following actions are taken corresponding to the state of
the selected process

0) the process is ready for running -
     no actions

1) input has arrived from the terminal -
     the input is copied from the terminal buffer into the process and
     an answer is sent to the process

2) terminal has become ready after output (term buffer has been full)
     no actions

3) the process is to be started with new abs program
     the process description is modified according to the conventions for
     start of an abs program
;



body of prepare
begin
  label inputready;
  incode
    word return;
    word c_funct:=2'01101;
    ref  c_first,
         c_last;
    word c_rel:=0;
  begin
    return:=w3;
    swop(.w3.,w1);
    case w3:=(w1).state+1 of
    begin
      begin comment 0: no io or communication via pseudo process;
        if w3:=(w1).messgot > 10 then goto inputready;
      end;
      begin comment 1: input ready;
inputready:
        w0:=(w1).messsend;
        w3:=(w1).messgot;
        if w3:=(w3).operation onemask 1 then
        if w0 or (w1).statusinf or 8'10200001 <> 8'10200001 then
        begin
          swop(.w3.,w1:=0);
          !get 2;
          if w0 <> 1 then goto b.discfault;
          logout(.w3.,w1:=b.userentry);
        end;
        if w0:=(w1).procbuf1<w3:=b.fstcore then unintelligible(.w3.,w1)
        else if w0+(w1).buflength>(w3+(w1).procsize) then unintelligible(.w3.,w1)
        else
        begin
          w2:=b.coreuser;
          copy(.w3.,w0:=(w1).buflength,w1:=(w1).buffer,w2:=(w2).procbuf1);
          testout(.w3.,w0,w1,w2:=0);
          (w3:=b.userentry).currlocid:=w0:=(w1).word;
          w1:= b.userentry;
          send(.w3.,w0:=(w1).messsend,w1,w2:=(w1).statusinf);
        end;
        (w1).state:=w0:=0;
        if w0:=(w1).class+b.timerloss > b.batchclass then
        begin
          if w0:=(w1).class+b.inputgain > 0 then w0:=0;
          (w1).class:=w0;
          (w1).prio:=w0;
        end;
      end;
      begin comment 2: waiting for output answer;
      end;
      begin comment 3: waiting for loading with new abs program;
        w3:=address(b.procname);
        w0:=address((w1).pr_out);
        w0+b.basereg;
        b.register2:=w0;
        w0:=address((w1).pr_in);
        b.register0:=w0+b.basereg;
        w2:=(w1).internal;
        b.register3:=w2;
        if w0:=(w1).state2<1
        then w0:=b.fstcore+b.fp_rel
        else
        begin
          (w1).class:=w0:=0;
          w0:=b.fstcore+b.cleart_rel;
        end;
        b.ic:= w0;
        w2+2;
        (w3).name1:=f1:=(w2).name1;
        (w3).name2:=f1:=(w2).name2;
        w1:=address(b.register0);
        monitor(62);  comment modify internal process;
        w1:=b.coreuser;
        (w1).state:=w0:=0;
        (w1).prio:=w0;
      end;
      begin ! 4: suspended because of output buffer full !
      end;
      begin ! 5: message waiting to be send !
      end;
      begin ! 6: waiting for answer from primo !
        startstop(.w3.,w0:=1,w1);
        c_first:=w0:=(w1).buffer;
        w3:=(w1).buflength-2+w0;
        c_last:=w3;
        w2:=(w1).messgot;
        w1:=address(c_funct);
        if w3>=w0 then
          monitor(84) ! general copy !
        else
          w0:=0;
        w1:=b.userentry;
        if w0<>0 then (w1).messsend:=w0;
        send(.w3.,w0:=(w1).messsend,w1,w2:=(w1).statusinf);
        startstop(.w3.,w0:=0,w1);
        (w1).state:=w0:=0;
      end;
      begin ! 7: message waiting to be send to primo !
      end;
      begin ! 8: waiting for terminal control answer !
      end;
    end;
    w3:=return
  end
end;     !  prepare  !
\f







comment                waitevent

this procedure awaits the first event queued up to the onlineadministrator
according to the kind of this event it proceeds as follows:

answer: an answer is expected to come from the timer or from a terminal
logged in,  so the userentries are scanned to find the one matching this
message buffer (the buffer addresses of messages sent to terminals are 
saved in the userentries),  if no entry is found, and it is not an answer
from the timer, then the answer is neglected and the procedure awaits the
next event.

message: a message is expected to be an i-o message or a parent message 
from an internal process or an attention message from a terminal. the
userentries are scanned to find the sender of the message. if no entry
does match the sender (neither internal nor peripheral process belonging
to any user) then the message may be:
1) an attention message from an unknown terminal, the sender is then saved
   in a free userentry (if any)
2) a message from an unknown process,  the message is rejected

thus at exit the procedure always delivers:
   an event (w2)
   a userentry (w1)
   an event kind (w0) these kinds are:  1 = input message from internal
                                        2 = output message from internal
                                        3 = parent message from internal
                                        4 = attention from known terminal
                                        5 = answer from known terminal
                                        6 = attention from unknown terminal
                                        7 = answer from timer
                                        8 = message from a bastard
                                        9 = message to a pseudo process (tem)
                                       10 = message to be send later
                                       11 = message to a pseudo process (primo)
                                       12 = message to be send later to primo
                                       13 = control message to terminal
;
\f




    body of waitevent
    begin
      label wait,exit,reject;
      incode
        word save0,savew1,zero:=0;
        ref return,currmess,entryref;
      begin
        return:=w3;
wait:
        w2:=b.baseevent;;
        monitor(24); comment wait first event;
        currmess:=w2;
        w1:=b.lastuser;
        if w0 = 1 then comment answer;
        begin
          (w1).messsend:=w2;
          w1:=address(b.interrupt);
          monitor(18);  comment wait answer;
          if w2 = b.timermess then
          begin
            w0:=0;
            b.timermess:=w0;
            w0:=7;
            goto exit;
          end;
          w1:=b.firstuser;
          while w2 <> (w1).messsend do w1+!length(userentry);
          if w1 = b.lastuser then  ! answer from unknown is neglected !
          begin
            testout(.w3.,w0:=24,w1:=currmess,w2:=6);
            goto wait;
          end;
          (w1).messsend:=w0;
          if w0=1 then
          begin
            w3:= address(b.interrupt);
            w0:= (w3).bytes;(w1).buflength:= w0;
            w0:= (w3).characters;(w1).bufchars:= w0;
          end else
          begin
            w0:= 4;
            (w1).buflength:= w0;
            w0:= 6;
            (w1).bufchars:= w0;
          end;
          (w1).statusinf:=w0:=(w3).status;
          w0:=5;
          goto exit;
        end else
        begin comment message;
          if w0:=(w2).operation<0 then
          begin ! skip if dummy message from term.module !
            w3:= address(b.t_mdul);
            monitor(4); ! process description !
            if w0=(w2).sender then
            begin
              b.baseevent:= w2;
              testout(.w3.,w0:=24,w1:=currmess,w2:=6);
              goto wait;
            end;
          end;
          monitor(26);  comment get event;
          w3:=(w2).sender;
          (w1).internal:=w3;
          (w1).peripheral:=w3;
          w1:=b.firstuser;
          while w3<>(w1).internal do w1+!length(userentry);
          if w1=b.lastuser then comment sender is not child;
          begin
            if w0:=(w2).operation<>0 then 
            begin
              w3+50;
              if w0:=(w3).word = b.ownproc then
              begin
                w0:=8;
                goto exit;
              end else goto reject;
            end;
            w1:=b.firstuser;
            while w3<>(w1).peripheral do w1+!length(userentry);
            if w1<b.lastuser then comment the terminal is known;
            begin
              if w3:=(w1).messgot>10 then
              begin
                empty_answer(.w3.,w0:=1,w1,w2:=0);
              end;
              w0:=4;
            end
            else comment attention from unknown terminal;
            begin
              w0:=0;
              (w1).peripheral:=w0;
              w1:=b.firstuser;
              while w0<>(w1).peripheral do w1+!length(userentry);
              if w3<0 then w1:=b.lastuser;
              if w1=b.lastuser then 
              begin
reject:
                (w1).messgot:=w2;
                empty_answer(.w3.,w0:=2,w1,w2:=0);
                goto wait;
              end;
              (w1).internal:=w3;
              (w1).peripheral:=w3; comment link terminal to entry;
              w0:=6;
            end;
            (w1).messgot:=w2:=currmess;
            goto exit;
          end
          else comment sender=internal;
          begin
            if w3:=(w1).messgot>10 then
            begin
              w0:=2;
              monitor(22);  ! send answer - reject !
              goto wait;
            end;
            savew1:=w1;
            w1:=(w1).internal+76;
            f1:=(w1).double;
            w3:=address(zero);
            monitor(72); ! set catalog base to that of child !
            w3:=address(b.p_mdul);
            monitor(4); ! process description of primo pseudo process !
            w1:=savew1;
            (w1).messgot:=w2;
            if w3:=(w1).messsend > 10 then
            begin
              if w3:=(w2).receiver+w0=0 then w0:=12
                                        else w0:=10
            end
            else
            if w3:=(w2).receiver+w0=0 then
            begin
               if w0:=7 <> w3:=(w2).operation then ! reject !
               begin
                  w0:=2;
                  (w1).messgot:=w0;
                  monitor(22); ! send answer !
                  goto wait;
               end else w0:=11
            end else
            if w3:= (w2).receiver+b.ownproc = 0 then w0:= 3 else
            if w3:= (w2).receiver+b.sosterm = 0 then
            begin
              if w3:= (w2).operation onemask 3 then w0:= 1 else
              if w3 onemask 5 then w0:= 2 else w0:= 13;
            end else w0:= 9;
          end;
        end;
exit:
        entryref:=w1;
        b.userentry:=w1;
        save0:=w0;
        comment *    testout (.w3., w0:=!length(userentry), w1:=entryref, w2:=68);
        comment *;   testout (.w3., w0:=12, w1:=address(save0), w2:=26);
        testout(.w3.,w0:=24,w1:=currmess,w2:=6);
        f1:=b.startbase;
        w3:=address(zero);
        monitor(72); ! reset catalog base !
        w0:=save0; w1:=entryref; w2:=currmess; w3:=return;
      end;
    end;     !  waitevent  !
 \f




comment      send_control (userentry, message)

this procedure sends a control message to the user terminal
(get specifications, set specifications) and sets localid in the
message in case the terminal is run by tem;

        body of send_control
        begin
          incode word mess0, mess2, mess4, mess6, mess8, mess10, mess12, mess14;
                 double savef1, savef3;
          begin
            savef1:= f1;
            savef3:= f3;
            copy (.w3.,w0:= 16, w1:= w2+8, w2:= address(mess0));
            f1:= savef1;
            w2:= (w1).peripheral;
            if w2 < 0 then -(w2);
            w2+2;
            w3:= address(b.procname);
            (w3).name1:= f1:= (w2).name1;
            (w3).name2:= f1:= (w2).name2;
            mess10:= w0:= 0; ! set local id (0) for tem !
            w1:= address(mess0);
            monitor (16); ! send message !
            f1:= savef1;
            (w1).messsend:= w2;
            testout (.w3., w0:= 16, w1:= address(mess0), w2:= 2);
            f1:= savef1;
            f3:= savef3;
          end;
        end; ! send control !

\f






comment               link (userentry)

this procedure links off the userentry pointed out by w1 from wherever it
it is chained up, and then links it up immediately after the userentry pointed
out by w2.  the heads of the queues (active- and waiting-queue) are of the
same format as the chainelements in the userentries so that the chainheads
may be used just like other elements in the chains.
;


    body of link
    begin
      incode
        double w01, w23;
      begin
        w01:=f1;
        w23:=f3;
        comment link off userentry;
        w3:=(w1).prevuser;
        (w3).nextuser:=w0:=(w1).nextuser;
        w3:=(w1).nextuser;
        (w3).prevuser:=w0:=(w1).prevuser;
        comment link userentry(w1) after userentry(w2);
        (w1).prevuser:=w3:=(w2).prevuser;
        (w1).nextuser:=w0:=(w3).nextuser;
        (w2).prevuser:=w1;
        (w3).nextuser:=w1;
        comment *   testout (.w3., w0:=20, w1:=address(b.activqfst), w2:=9);
        f1:=w01;
        f3:=w23;
      end;
    end;     !  link  !
\f







comment          copy 

this procedure just moves w0 bytes from the address of w1 (and onwards) to
the address of w2 (and onwards)
;


    body of copy
    begin
      incode
        double w01,w23;
      begin
        w01:=f1; w23:=f3;
        w3:=w1+w0;
        while w1<w3 do
        begin
          (w2).word:=w0:=(w1).word;
          w1+2; w2+2;
        end;
        f1:=w01; f3:=w23;
      end;
    end;
\f






comment               swop

this procedure makes sure, that the core image of the userentry pointed
out by w1 is brought into core (if it was not there already). if the state
is waiting for start with new abs program, swop loads a process image containing a
new abs program.  if the process was in core already and there is not asked for a
new abs program - then nothing is done.
;


    body of swop
    begin
      label exitswop;
      incode
        double w01,w23;
        word opmode;
        ref corefst,coretop;
        word segmsw;
      begin
        w01:=f1; w23:=f3;
        corefst:=w0:=b.fstcore;
        if w2:=b.coreuser=w1 then
        if w3:=(w1).state<>3 then goto exitswop;
        if w2>0 then comment core not free;
        begin
          startstop(.w3.,w0:=0,w1:=w2); ! stop coreuser !
          opmode:=w0:=5 ashift 12;
          coretop:=w0:=corefst+(w2).procsize;
          segmsw:=w0:=(w2).swopsegm;
          w1:=address(opmode);
          w3:=address(b.swname);
          transport(.w2.,w1,w3);
        end;
        f1:=w01;
        if w1<>0 then
        begin
            coretop:=w0:=corefst+(w1).procsize;
          opmode:=w0:=3 ashift 12;
          if w0:=(w1).state=3 then
          begin
            segmsw:=w0:=0;
            if w0:=(w1).state2<1
            then w3:=address(b.fpcode)
            else w3:=address(b.cleartemp);
          end
          else begin
            segmsw:=w0:=(w1).swopsegm;
            w3:=address(b.swname);
          end;
          w1:=address(opmode);
          transport(.w2.,w1,w3);
        end;
        f1:=w01;
        b.coreuser:=w1;
        testout(.w3.,w0:=!length(userentry),w1,w2:=3);
exitswop:
        f1:=w01;
        f3:=w23;
      end;
    end;     !  swop  !
\f







    body of unintelligible
    begin
      incode
        double w01,w23;
        word op,fst,lst;
      begin
        w01:=f1; w23:=f3;
!test 99;
        op:=w0:=0;
        fst:=w0:=2;
        lst:=w0:=3;
        w2:=(w1).messgot;
        w0:=3;
        (w1).messgot:=w0;
        w1:=address(op);
        monitor(22); ! send answer !
        testout(.w3.,w0:=6,w1:=address(op),w2:=60);
        f1:=w01; f3:=w23
      end
    end;     !  unintelligible  !
\f







comment               send message to primo

   w1 = userentry
   w2 = messbuf address of buffer sent to primo (pseudo process)
   at return w2 = messbuf address of message sent to primo (real process)
             w3 = old w2
;

    body of send_primo
    begin
      incode
        word savew2;
        double savef1;
        ref return;
        word op;
        ref  ofirst,
             olast,
             ifirst,
             ilast;
      begin
        savef1:=f1;
        return:=w3;
        savew2:=w2;
        op:=w0:=28672;    ! 7<12 !
        ofirst:=w0:=(w1).buffer;
        ifirst:=w0;
        olast:=w3:=(w2).mblst-(w2).mbfst+w0;
        ilast:=w3:=(w2).mbilast-(w2).segmno+w0;
        w1:=address(op);
        w3:=address(b.p_pseudo);
        monitor(16); ! send message to pseudo process created by primo !
        f1:=savef1;
        (w1).messsend:=w2;
        (w1).state:=w0:=6;
        testout(.w3.,w0:=10,w1:=address(op),w2:=2);
        f1:=savef1;
        w2:=(w1).messsend;
        w3:=savew2;
        call w0 return
      end
    end;     !  send_primo  !
\f







    body of primess
    begin
      label stopped;
      incode
        ref return;
        word savew0;
        word zero:=0;
        word c_funct:=2'00100;
        ref  c_first,
             c_last;
        word c_rel:=0;
      begin
        return:=w3;
        if w0:=(w1).state<0 then
        begin
          empty_answer(.w3.,w0:=1,w1,w2:=256); ! stopped !
          goto b.continue;
        end else
        begin
          if w0=0 then
          begin
          if w1=b.coreuser then
          begin
            w3:=(w1).internal+11;
            if w3:=(w3).byte and 2'10100000=2'10100000 then ! stopped !
            begin
              (w1).state:=w0:=6;
              startstop(.w3.,w0:=1,w1);
            end;
            c_first:=w0:=(w1).buffer;
            c_last:=w3:=(w2).mblst-(w2).mbfst+w0;
            w1:=address(c_funct);
            if w3>=w0 then
              monitor(84) ! general copy !
            else
              w0:=0;
            savew0:=w0;
            w1:=b.userentry;
            if w0:=6=(w3:=(w1).state) then startstop(.w3.,w0:=0,w1);
            if w0:=savew0<>0 then
              unintelligble(.w3.,w1)
            else
            begin
              w3:=(w1).buffer;
              w0:=(w3).word;
              w3+2; w3:=(w3).word;
              if w0=4'2000000 then
              begin
              if w3=4'1010010 then
              begin ! define transport !
                w1:=(w1).internal+76;
                f1:=(w1).double;
                w3:=address(zero);
                monitor(72); ! set catalog base to that of child !
                send_primo(.w3.,w1:=b.userentry,w2);
                w1:=address(b.interrupt);
                monitor(18); ! wait answer !
                w3:=w1;
                w1:=b.userentry;
                (w1).messsend:=w0; ! result !
                (w1).buflength:=w0:=(w3).bytes;
                (w1).statusinf:=w0:=(w3).status;
                f1:=b.startbase;
                w3:=address(zero);
                monitor(72); ! reset catalog base !
                w1:=b.userentry;
                w0:=5; ! answer, w1=userentry, w2=messbufaddr !
                if w2:=b.timermess<>0 then
                begin
                  monitor(82); ! regret message !
                  w2:=0;
                  b.timermess:=w2
                end;
                goto b.action_l;
              end
              else
                 unintelligible(.w3.,w1)
              end ! define transport !
              else
              begin
                send_primo(.w3.,w1,w2);
                if w2:=b.timermess<>0 then
                begin
                  monitor(82); ! regret message !
                  w2:=0; b.timermess:=w2
                end;
                link(.w3.,w1,w2:=address(b.waitqfst));
                startstop(.w3.,w0:=0,w1);
              end
            end ! message ok !
          end
          else
            goto stopped
          end ! state=0 and in core !
          else
          begin ! state>0 or not coreuser !
stopped:    (w1).buflength:=w0:=0;
            (w1).state:=w0;
            empty_answer(.w3.,w0:=1,w1,w2:=256); ! stopped !
          end; ! state>0 or not coreuser !
          if w0:=b.timermess<>0 then goto b.continue;
        end; ! state>=0 !
        w3:=return
      end
    end;     !  primess  !
\f






comment               send  (message or answer)

according to the content of w0 this procedure sends a message or an answer
to the peripheral or the internal process referenced by the userentry(w1).
w0 > 0  answer is sent to internal process (w2 = status, w0 = result)
w0 <= 0  message is sent to peripheral process (w2 = operation < 12 + mode)
at i-o messages to the terminal, the terminal buffer is used for this ope-
ration. at communication with internal processes, data is copied to-from some in-
ternal buffer from-to the terminal buffer. this copying must be done before
calling this procedure.

when w0 < 0 only a part of the terminal buffer is used for the operation, 
-w0 giving the relative start address in the buffer.
;


    body of send
    begin
      incode
        double w01,w23;
        word op,fst,lst;
      begin
        w01:=f1; w23:=f3;
        op:=w2;
        if w0>0 then comment send answer;
        begin
          w2:=(w1).buflength;    ! op=status, fst=no.of hw.s, lst=no of chars !
          fst:=w2;
            w2:= (w1).bufchars;
            lst:= w2;
          w2:=(w1).messgot;
          (w1).messgot:=w0;
          w1:=address(op);
          monitor(22);  comment send answer;
        end
        else comment send message;
        begin
          w2:=(w1).peripheral;
          if w2 < 0 then -(w2);
          w2+2;
          w3:=address(b.procname);
          (w3).name1:=f1:=(w2).name1;
          (w3).name2:=f1:=(w2).name2;
          f1:=w01;
          if w0<0 then -(w0);
          w0 + (w1).buffer;
          fst:=w0;
          lst:=w0+(w1).buflength-2;
          w1:=address(op);
          monitor(16);  comment send message;
          f1:=w01;
          (w1).messsend:=w2;
        end;
        testout(.w3.,w0:=14,w1:=address(w01),w2:=2);
        f1:=w01; f3:=w23;
      end;
    end;     !  send  !
\f







comment               startstop  (internal process)

this procedure just starts or stops the internal process referenced by the
userentry (w1). 
w0 = 0  stop process
     1  start process
;


    body of startstop
    begin
      incode
        double w01,w23;
      begin
        w01:=f1; w23:=f3;
        w3:=address(b.procname);
        w2:=(w1).internal+2;
        (w3).name1:=f1:=(w2).name1;
        (w3).name2:=f1:=(w2).name2;
        f1:=w01;
        if w0=0 then
        begin
          w1:=b.lastuser;
          monitor(60);  comment stop internal process;
          monitor(18);  comment wait answer;
          if w0<>1 then key(w01):=w0;
        end else
        begin
          monitor(58);  comment start internal process;
          if w0<>0 then key(w01):=w0;
        end;
        f1:=w01;
        w2:=w0+4;
        testout(.w3.,w0:=!length(userentry),w1,w2);
        f1:=w01;  f3:=w23;
      end;
    end;     !  startstop  !
\f

 

comment - send an emty answer to "messgot" and set's 
          "buflength" and "bufchars" to zero -
          call: w0 = monitor result
                w1 = user entry
                w2 = status;

                
    body of empty_answer
    begin
      incode
      double w23;
      ref user, buf;
      word result;
      word status, halves, bytes;
      begin
        result := w0;
        user := w1;
        w23 := f3;
        status := w2;
        w2:= 0;
        halves := w2;
        bytes := w2;
        user.buflength := w2;
        user.bufchars := w2;
        buf := w2 := user.messgot;
        user.messgot := w0;
        w1:= address (status);
        monitor (22); ! send answer !
        testout (.w3., w0:= 10, w1:= address (buf), w2:= 61);
        w0 := result;
        w1 := user;
        f3 := w23;
      end;
    end;

\f






    body of testout
    begin
      record testhead(byte length,kind;
                      word time,user,tailfst);
      record dump (
        word reg0,reg1,reg2,reg3,exreg,instr,cause,sbreg);
      incode
        ref return;
        word bufrel:=0;
        double w01,w23;
      begin
        w01:=f1;  w23:=f3;
        if w3:=b.testbfst<b.testblst then
        begin
          if w0+bufrel+8>510 then comment change buffer segment;
          begin
            if w0 > 1024 then w0:=-2 else w0:=-1;
            (w3:=b.testbfst+bufrel).word:=w0;
            w1:=address(b.testop);
            w3:=address(b.tstarea);
            transport(.w2.,w1,w3);
            if w1:=b.testsegm+1=b.maxtestsegm then w1:=1;
            b.testsegm:=w1;
            bufrel:=w0:=0;
            f1:= w01;
            if w0 > 500 then if w0 < 1024 then w0:= 500;
            w01:= f1;
          end;
          f1:=w01;  f3:=w23;
          w3:=b.testbfst+bufrel;
          (w3).length:=w0+6;
          bufrel:=w1:=bufrel+w0;
          w1:=108;  comment abs ref current time;
          f1:=(w1).double-b.starttime lshift -7;
          (w3).time:=w1;
          (w3).kind:=w2;
          f1:=w01;
          w1:=b.userentry;
          w2:=(w1).internal;
          (w3).user:=w2;
          f1:=w01;
          copy(.w3.,w0,w1,w2:=(w3+6));
        end;
        f3:=w23;
        if w2=7 then comment fault;
        begin
          w3:= (w1).instr-2;
          if w0:=(w3).word lshift -12=(51*64) ! key store ! then
          begin ! reestablish registers and continue !
            w3+1;
            (w1).cause:= w0:= (w3).byte;
            w0:= (w1).instr;
            return:= w0;
            w0:= (w1).reg0;
            w2:= (w1).reg2;
            w3:= (w1).reg3;
            w1:= (w1).reg1;
            call w0 return;
          end
          else
          begin
            f1:=w01;
            f3:=w23;
          end;
        end;
      end;
    end;     !  testout  !
\f






comment                  transport

;


    body of transport
    begin
      incode
        byte optr:=2,modetr:=8'1001;
        text (6) stars:="status";
        word trstatus, trbytes, chars, a4, a5, a6, a7, a8;
        word savew0, savew1;
        double savef1,savef3;
      begin
        savew0:=w0; savew1:=w1;
        savef3:=f3;
        w0:=0;
        while w0=0 do
        begin
          monitor(16);
          w1:=address(trstatus);
          monitor(18);
          w2:=1 ashift w0;
          if w0=1 then w2+trstatus;
            trbytes :=w0;
          if w2<>2 then
          begin
            trstatus:= w2;
            copy(.w3.,w0:=8,w1:=w3,w2:=address(trbytes));
            !get 2;
            if w0 <> 1 then goto b.discfault;
            opmess(.w3.,w1:=address(optr),w2:=b.ownproc);
          end;
          w0:=trbytes;
          w1:=savew1;
          f3:=savef3;
        end;
        w0:=savew0;
      end;
    end;     !  transport  !
\f





!branch 1,2;


comment                   init

this procedure initializes the userentries (being all free) reserves area
for terminal buffer, testbuffer,  computes absolute addresses (creating
the chains of the queues, references to buffers and process-area etc),
creates swop- and test-area-processes  -  and after execution it is over-
written (used as buffer area for execution of child process)
;


    body of init
    begin
      incode
        word childstart,swopno:=0;
        byte vop:=16,vmode:=8'140;
        text(14) verstxt:=
        !               *** sos ***                   ! "release: 7.3";
        word sosversion := 900111,


        comment ===trimstart;
        comment date of option version;                      optionid  :=     0,
        comment rc4000/rc8000 (rc4000=4000,rc8000=8000);     rc        :=  8000,
        comment minimum no of active childs at the same time;minusers  :=     1,
        comment terminals performing os-commands;            comndusers:=     2,
        comment min. no of bufs reserved for childs;         minbufs   :=     4,
        comment min. no of areas reserved for childs;        minareas  :=     7,
        comment min. core size for childs;                   minsize   := 12800,
        comment size of testoutput area;                     testsegmnt:=   168,
        comment size of i-o buffer for a terminal (bytes);   bufl      :=   104,
        comment length of a timeslice  (seconds);            timeslice :=     3,
        comment max no of timeslices used in cpu (no input); cpulimit  :=   100,
        comment loss of priority class when timed out;       classloss :=     1,
        comment priority class gain at input (if class<0);   classgain :=     1,
        comment priority gain when first in activequeue;     priogain  :=     1,
        comment reaction on time exceeded/break;             conditions := 2'000011,
        comment    2'000001 = abort job at time exceeded;
        comment    2'000010 = abort job after break command;

                trimtexts;  text(11)

        comment operator key;                                oprkey    := "opr",
        comment document for swoparea;                       swopdoc   :=    "",
        comment document for testarea;                       testdoc   :=    "",
        comment ===trimfinis;


        keytext :="key",
        inttext :="internal",
        buftext :="buf",
        areatext:="area",
        sizetext:="size";
        ref return,currentry,prevchain:=0;
        word zero:=0;

        array (1:10) tail of word := 0 0 0 0 0 0 0 0 0 0;
        byte op1:=16, mode1:=8'40;
        word alarm;
        text(11) resource;
        word filler:=0;
        word stdvalue;
        text(21) functext:="***function 1,2,3,4,5",
                 bufltext:="***buflength >= 94";
        word stop;
        byte op2:= 16, mode2:= 0;
        text (20) childres:="child resources";
        byte opstop:= 2, modestop:= 1;
        text (20) inittr:= "***init troubles";
        byte op3:=16, mode3:=0;
        text (20) started:="started";

        word childareas, users, swopsize;
        text(11) swoparea:="swp",termarea:="psd",testarea:="tst",
                 fparea:="fp",cleararea:="cleartemp",soscat:="soscat",
                 t_module:="tem",p_module:="primo",
                 p_msys:="primosys",console1:="console1";
      begin
        return:=w3;
        w3:=108;
        b.starttime:=f1:=(w3).double;
        if w2:=rc = 4000 then
        begin
          b.relintrpt:=w0:=36;
          b.reldump:=w0:=38;
        end else
        begin
          b.relintrpt:=w0:=36;
          b.reldump:=w0:=80;
        end;
        copy(.w3.,w0:=8,w1:=address(oprkey),w2:=address(b.operator));
        b.maxbuf:=w0:=bufl;
        bufl:=w0:=bufl+2;
        b.minprio:=-(w1:=cpulimit);
        b.interval:=w1:=timeslice;
        b.timerloss:=w1:=classloss;
        b.cyclegain:=w1:=priogain;
        b.inputgain:=w1:=classgain;
        b.syscond:=w1:=conditions;
         w3:= b.ownproc+32;
         w0:= (w3).word;
         f1 lshift -12; w1 lshift -12;
         if w2:=rc <> 4000 then
         begin
           b.childpr:= w0;
           b.childpk:= w1;
         end
         else
         begin
           -(w1);
           b.childpr:= w2:= 128 lshift w1 + w0;
           if w2 extract 8=127 then ! no key available for child !
           begin
             stdvalue:= w0:= 2;
             copy(.w3.,w0:=8,w1:=address(keytext),w2:=address(resource));
             alarm:= w0:= 2763306;
             stop:= w0;
             opmess(.w3.,w1:=address(op1),w2:=b.ownproc);
           end;
            w2:=b.childpr extract 8;
           w1:= 1;
           while w2 lshift 1 onemask 128 do w1+1;
           b.childpk:= w1;
         end;

        opmess(.w3.,w1:=address(vop),w2:=b.ownproc);
        w3:=b.ownproc+29;   ! test function mask !
        if w0:=(w3).byte onemask 8'3700 then else
        begin
          copy(.w3.,w0:=14,w1:=address(functext),w2:=address(started));
          stop:=w0:=1;
          opmess(.w3.,w1:=address(op3),w2:=b.ownproc);
        end;

        if w0:=bufl < 94 then   ! buffer size too small for sos' private use !
        begin
          copy(.w3.,w0:=14,w1:=address(bufltext),w2:=address(started));
          stop:=w0:=1;
          opmess(.w3.,w1:=address(op3),w2:=b.ownproc);
        end;
         w3:= b.ownproc+28;
         w0:= (w3).byte;
         if w0<minusers then ! too few internals available !
         begin
           stdvalue:= w0:= minusers;
           copy(.w3.,w0:=8,w1:=address(inttext),w2:=address(resource));
           alarm:= w0:= 2763306;
           stop:= w0;
           opmess(.w3.,w1:=address(op1),w2:=b.ownproc);
           w0:= minusers;
         end;
         users:= w0+comndusers;
         w0*2;  ! compute free bufs !
         w0+4;
         w3:= b.ownproc+26;
         -(w0-(w3).byte);
         b.freebufs:= w0;
         if w0<minbufs then ! too few buffers !
         begin
           -(w0-minbufs-(w3).byte);
           stdvalue:= w0;
           copy(.w3.,w0:=8,w1:=address(buftext),w2:=address(resource));
           alarm:= w0:= 2763306;
           stop:= w0;
           opmess(.w3.,w1:=address(op1),w2:=b.ownproc);
         end;
         w3:= b.ownproc+27;
         ! "fp", swoparea, "soscat", "cleartemp", pseudo process, (testarea) !
         if w0:=testsegmnts=0 then w0:=5 else w0:= 6;
         w0+users+users-comndusers; ! pseudo tem + pseudo primo !
         w2:= (w3).byte;
         childarea:= w3:= w2-w0;
         w0+minareas;
         if w2<w0 then ! too few areas !
         begin
           stdvalue:= w0+1;
           copy(.w3.,w0:=8,w1:=address(areatext),w2:=address(resource));
           alarm:= w0:= 2763306;
           stop:= w0;
           opmess(.w3.,w1:=address(op1),w2:=b.ownproc);
         end;
         w3:= b.ownproc+22;
         w0:= (w3).word;  b.fstcore:= w0;
         w3+2;
         w0:= (w3).word; b.topcore:= w0;
         w0:= bufl+!length(userentry)*users;
         w0+!length(userentry);
         if w3:=testsegmnts<>0 then w0+512;
         w3:= address(childstart) + 2047;
         w3 := w3 lshift -11 lshift 11; ! force address to 2K border !
         - (w3);
         w3+b.topcore; w3-w0;
         if w3<minsize then ! size too small !
         begin
           -(w3-minsize);
           w3+b.topcore-b.fstcore; stdvalue:= w3;
           copy(.w3.,w0:=8,w1:=address(sizetext),w2:=address(resource));
           alarm:= w0:= 2763306;
           stop:= w0;
           opmess(.w3.,w1:=address(op1),w2:=b.ownproc);
         end;
         swopsize:= w3 ashift -9;
         w3 ashift 9;
         w1:= address(childstart) + 2047;
         w1 := w1 lshift -11 lshift 11; ! force address to 2K border !
         b.fstcore := w1;
         w1+w3; b.topcore:= w1;
         b.testbfst:= w1;

         w2:= testsegmnts;
         if w2>0 then ! prepare testoutput !
         begin
           w1+510; b.testblst:= w1;
           copy(.w3.,w0:=6,w1:=b.ownproc+2,w2:=address(testarea)+2);
           tail(w2:=2);
           copy(.w3.,w0:=8,w1:=address(testdoc),w2);
           if w0:=(w2).word = 0 then (w2).word:=w0:=1;
           w3:= address(testarea);
           monitor(48); ! remove entry !
           (tail(w1:=1)).word:= w2:=testsegmnts;
           b.maxtestsegm:= w2;
           monitor(40); ! create testoutput area !
           monitor(52); ! create area process !
           monitor(8);  ! reserve area process !
           if w0<>0 then
           begin
             stdvalue:= w2;
             copy(.w3.,w0:=8,w1:=address(testarea),w2:=address(resource));
             alarm:= w0:= 2763306;
             stop:= w0;
             opmess(.w3.,w1:=address(op1),w2:=b.ownproc);
           end;
           w1:= 3;
           monitor(50); ! permanent entry !
           copy(.w3.,w0:=8,w1:=address(testarea),w2:=address(b.tstarea));
         end
         else
         b.testblst:= w1;

         ! prepare swoparea !
         copy(.w3.,w0:=6,w1:=b.ownproc+2,w2:=address(swoparea)+2);     ! name = "swp<sos>" !
         tail(w2:=2);
         copy(.w3.,w0:=8,w1:=address(swopdoc),w2);
         if w0:=(w2).word = 0 then (w2).word:=w0:=1;
         w3:= address(swoparea);
         monitor(48); ! remove entry !
         w2:= users*swopsize;
         (tail(w1:=1)).word:= w2;
         monitor(40); ! create swop area !
         monitor(52); ! create area process !
         monitor( 8); ! reserve area process !
         if w0<>0 then
         begin
           stdvalue:= w2;
           copy(.w3.,w0:=8,w1:=address(swoparea),w2:=address(resource));
           alarm:= w0:= 2763306;
           stop:= w0;
           opmess(.w3.,w1:= address(op1),w2:=b.ownproc);
         end;
         copy(.w3.,w0:=8,w1:=address(swoparea),w2:=address(b.swname));

         w3:= address(fparea);     ! "fp" !
         tail(w1:=1);
         monitor(42); ! lookup entry !
         w1+17;
         b.fp_rel:= w0:= (w1).byte;
         monitor(52); ! create area process !
         if w0<>0 then
         begin
           stdvalue:= w0;
           copy(.w3.,w0:=8,w1:=address(fparea),w2:=address(resource));
           alarm:= w0:= 2763306;
           stop:= w0;
           opmess(.w3.,w1:=address(op1),w2:=b.ownproc);
         end;
         copy(.w3.,w0:=8,w1:=address(fparea),w2:=address(b.fpcode));

         w3:= address(cleararea);     ! "cleartemp" !
         tail(w1:=1);
         monitor(42); ! lookup entry !
         w1+17;
         b.cleart_rel:= w0:= (w1).byte;
         monitor(52); ! create area process !
         if w0<>0 then
         begin
           stdvalue:= w0;
           copy(.w3.,w0:=8,w1:=address(cleararea),w2:=address(resource));
           alarm:= w0:= 2763306;
           stop:= w0;
           opmess(.w3.,w1:=address(op1),w2:=b.ownproc);
         end;
         copy(.w3.,w0:=8,w1:=address(cleararea),w2:=address(b.cleartemp));
         ! prepare pseudo process for terminal i/o : "psd<sos-name>" !
         copy(.w3.,w0:=6,w1:=b.ownproc+2,w2:=address(termarea)+2);
         w3:= address(termarea);
         monitor (80); ! create pseudo process !
         if w0 <> 0 then
         begin
           stdvalue:= w0;
           copy (.w3.,w0:=8,w1:=address(termarea),w2:=address(resource));
           alarm:= w0:= 2763306;
           stop:= w0;
           opmess(.w3.,w1:=address(op1),w2:=b.ownproc);
         end else
         begin
           monitor (4); ! process description !
           b.sosterm:= w0;
         end;
         w3:=b.ownproc+68;
         b.startbase:=f1:=(w3).double;
         w3:=address(zero);
         w0:=w1;
         monitor(72);  ! set sos own cat base !
         w3:= address(soscat);     ! "soscat"   !
         tail(w1:=1);
         monitor(52); ! create area process !
         if w0<>0 then
         begin
           stdvalue:= w0;
           copy(.w3.,w0:=8,w1:=address(soscat),w2:=address(resource));
           alarm:= w0:= 2763306;
           stop:= w0;
           opmess(.w3.,w1:=address(op1),w2:=b.ownproc);
         end;
         copy(.w3.,w0:=8,w1:=address(soscat),w2:=address(b.usercat));      ! "soscat"   !

         copy(.w3.,w0:=8,w1:=address(t_module),w2:=address(b.t_mdul));     ! "tem"      !
         copy(.w3.,w0:=8,w1:=address(p_module),w2:=address(b.p_mdul));     ! "primo"    !
         copy(.w3.,w0:=8,w1:=address(p_msys),w2:=address(b.p_pseudo));     ! "primosys" !

         if w0:=stop<>0 then
         begin ! resources not available for start up !
            opmess(.w3.,w1:= address(opstop),w2:=b.ownproc);
         end;

         opmess(.w3.,w1:=address(op2),w2:=b.ownproc);
 
         alarm:= w0:= 2105376; ! "   " !
         stdvalue:= w0:= users-comndusers;
         copy(.w3.,w0:=8,w1:=address(inttext),w2:=address(resource));
         opmess(.w3.,w1:=address(op1),w2:=b.ownproc);

         stdvalue:= w0:= b.freebufs;
         copy(.w3.,w0:=8,w1:=address(buftext),w2:=address(resource));
         opmess(.w3.,w1:=address(op1),w2:=b.ownproc);

         stdvalue:= w0:= childareas;
         copy(.w3.,w0:=8,w1:=address(areatext),w2:=address(resource));
         opmess(.w3.,w1:=address(op1),w2:=b.ownproc);

         w0:= b.topcore-b.fstcore; stdvalue:= w0;
         copy(.w3.,w0:=8,w1:=address(sizetext),w2:=address(resource));
         opmess(.w3.,w1:=address(op1),w2:=b.ownproc);
         opmess(.w3.,w1:=address(op3),w2:=b.ownproc);

        comment    reserve space for i/o-buffers for terminals;

         w1:= b.testblst+2;
        w0:=bufl*users;
        w2:=w0+w1;
        currentry:=w2;
        b.firstuser:=w2;
        swopno:=w3:=swopno-swopsize;
        w3:=0;
        while w3+1<=users do     ! initialize all user entries as empty !
        begin
          (w2).prevuser:=w0:=prevchain;
          prevchain:=w2;
          swopno:=w0:=swopno+swopsize;
          (w2).swopsegm:=w0:=swopno;
          w0:=0;
          (w2).internal:=w0;
          (w2).peripheral:=w0;
          (w2).messsend:=w0;
          (w2).messgot:=w0;
          (w2).bufrel:=w0;
          (w2).buffer:=w1;
          w1+bufl;
          w0:=w2+!length(userentry);
          (w2).nextuser:=w0;
          w2:=w0;
        end;
        b.lastuser:=w2;
        w2:=(w0-!length(userentry));
        w0-!length(userentry);
        (w2).prevuser:=w0;
        (w2).nextuser:=w0:=address(b.waitqfst);
        b.waitqlst:=w2;
        w2:=b.firstuser;
        (w2).prevuser:=w0:=address(b.waitqfst);
        b.activqfst:=w0:=address(b.activqfst);
        b.activqlst:=w0;
        b.batchqfst:=w0:=address(b.batchqfst);
        b.batchqlst:=w0;
        b.waitqfst:=w2;
        testout(.w3.,w0:=60,w1:=address(sosversion),w2:=69);
        w3:=address(zero);
        f1:=b.startbase;
        monitor(72);  ! set own cat base !
        w0:=b.fstcore;
        b.register1:=w0;
        w0:=b.fstcore+2;
        testout(.w3.,w0:=150,w1:=b.ownproc-4,w2:=8);
        comment *;  testout (.w3., w0:=20, w1:=address(b.activqfst), w2:=9);
        w3:=b.ownproc+98;
        b.basereg:=w3:=(w3).word;
        w3:=return;
      end;
    end;     !  init  !
\f



    body of opmess
    begin
      procedure outinteger(.w3.;w1;w2);
      incode
        text(11) pause:=" pause ",mess:=" message ";
        text(14) maincons;
        word clock1,clock2;
        text(11) sysname;
        text(11) messtype;
        text(14) procname:="             ";
        array(1:70) linebuffer of word;
        word nl:=10;
        byte op:=5,mode:=0;
        ref first,last;
        double savef1,savef3;
      begin
        savef1:=f1;
        savef3:=f3;
        outtime(.w3.,w2:=address(clock1));
        w3:=address(sysname);
        w2:=b.ownproc+2;
        (w3).name1:=f1:=(w2).name1;
        f1:=(w2).name2;
        w1+58;
        (w3).name2:=f1;
        f3:=savef3;
        copy(.w3.,w0:=8,w1:=w2+2,w2:=address(procname));
        f1:=savef1;
        if w0:=(w1).word extract 1 = 1 then w1:=address(pause)
                                       else w1:=address(mess);
        copy(.w3.,w0:=8,w1,w2:=address(messtype));
        f1:=savef1;
        w0:=-1 lshift 12 or (w1).word lshift -5;
        w1+14;
        linebuffer(w2:=70);
        while w0 onemask 8'10000 do
        begin
          if w0 onemask 1 then
          outinteger(.w3.,w1,w2) else
          (w2).word:=w3:=(w1).word;
          w2-2;
          w1-2;
          w0 lshift -1;
        end;
        w0:=0;
        linebuffer(w1:=1);
        while w1 <= w2 do
        begin
          (w1).word:=w0;
          w1+2;
        end;
        first:=w1:=address(clock1);
        last:=w1:=address(nl);
        copy(.w3.,w0:=8,w1:=b.mainconsref+2,w2:=address(maincons));
        w1:=address(op);
        w3:=address(maincons);
        monitor(16);  ! send message !
        linebuffer(w1:=1);
        monitor(18);  ! wait answer !
        f1:=savef1;
        f3:=savef3;
        if w2 = b.ownproc then
        if w0:=(w1).word onemask 1 then
        begin ! pause message from sos itself !
          w0:=0;
          w3:=0;
          monitor(0);  ! set interrupt !
          testout(.w3.,w0:=1024,w1:=-2,w2);
        end else f1:=savef1;
      end;

      body of outinteger
      begin
        incode
          double savef1;
          word savew3;
        begin
          savef1:=f1;
          savew3:=w3;
          (w2).word:=w0:=32;
          w2-2;
          w0:=(w1).word;
          if w0 = 0 then
          begin
            (w2).word:=w3:=48;
            w2-2;
          end;
          while w0 <> 0 do
          begin
            w3:=0;
            f0 // 10;
            (w2).word:=w3+48;
            w2-2;
          end;
          (w2).word:=w0:=32;
          f1:=savef1;
          w3:=savew3;
        end;
      end;  ! outinteger !

    end;   ! opmess !
\f




    body of logout
    begin
      incode
        double savef1,savef3;
        byte op1,mode1:=0;
        ref fst,lst;
        byte op2:=102,mode2:=0;
        word locid;
        text(14) simtext:="'2''2' hard error'10'";
        text(14) poolname;
      begin
        savef1:=f1;
        savef3:=f3;
        startstop(.w3.,w0:=0,w1);
        (w1).buflength:=w0:=0;
        if w0:=(w1).messgot > 10 then empty_answer(.w3.,w0:=1,w1,w2:=0);
        locid:=w0:=(w3:=(w1).buffer).word;
        copy(.w3.,w0:=6,w1:=(w1).internal+2,w2:=address(poolname)+2);
        copy(.w3.,w0:=2,w1:=address(b.t_mdul),w2:=address(poolname));
        w3:=address(poolname);
        op1:=w0:=9;  ! simulate input !
        fst:=w0:=address(locid);
        lst:=w0:=address(simtext)+8;
        w1:=address(op1);
        monitor(16);  ! send message !
        w1:=b.lastuser;
        monitor(18);  ! wait answer !
        if w0 or (w1).word = 1 then
        begin  ! terminal on transparent pool !
          w1:=address(op2);
          monitor(16);  ! send message (remove link soft) !
          w1:=b.lastuser;
          monitor(18);  ! wait answer !
        end else
        begin  ! other kind of hard error  - kill job !
          f1:=savef1;
          clean(.w3.,w1);
          (w1).intervent:=w0:=6;
        end;
        f1:=savef1;
        w0:=1;
        (w1).messsend:=w0;
        goto b.activate;
      end;
    end;    ! logout !
\f




    body of outtext
    begin
      incode
        text(29)
          t0 :="command unknown'10'",
          t1 :="ready'10'",
          t2 :="syntax'10'",
          t3 :="identification illegal'10'",
          t4 :="no room in primary store'10'",
          t5 :="bs claims exceeded'10'",
          t6 :="process creation not ok'10'",
          t7 :="forbidden'10'",
          t8 :="terminal busy'10'",
          t9 :="terminal connection not ok'10'",
          t10:="jobfile does not exist'10'",
          t11:="terminal connected'10'",
          t12:="terminal disconnected'10'",
          t13:="bad password'10'",
          t14:="terminal not connected'10'",
          t15:="process unknown'10'",
          t16:="disconnection not ok'10'",
          t17:="call not ok'10'",
          t18:="include not ok'10'",
          t19:="enrolled'10'",
          t20:="removed after break'10'",
          t21:="removed after finis'10'",
          t22:="removed after user kill'10'",
          t23:="removed after operator kill'10'",
          t24:="removed after time exceeded'10'",
          t25:="removed after terminal error'10'",
          t26:="removed after user break'10'",
          t27:="removed after operator break'10'",
          t28:="user conflict'10'",
          t29:="forbidden  -  system locked'10'",
          t30:="user catalog reserved'10'",
          t99:="***";
        double savef3;
        word savew0,savew1;
        ref bufpointer;
      begin
        savef3:=f3;
        savew0:=w0;
        savew1:=w1;
        bufpointer:=w3:=(w1).buffer;
        (w3).word:=w2:=0;
        w3+2;
        bufpointer:=w3;
        if w0 onemask 8'10 then
        begin  ! write time !
          outtime(.w3.,w2:=bufpointer);
          bufpointer:=w2:=bufpointer+4;
        end;
        w3:=bufpointer;
        case w2:=savew0 extract 3 + 1 of
        begin
          (w3).word:=w0:=0;
          (w3).word:=w0:=2763306;   comment "***" ;
          (w3).word:=w0:=2171169;   comment "!!!" ;
          (w3).word:=w0:=2960685;   comment "---" ;
          (w3).word:=w0:=2105376;   comment "   " ;
          (w3).word:=w0:=0;
          (w3).word:=w0:=0;
          (w3).word:=w0:=0;
        end;
        bufpointer:=w0:=bufpointer+2;
        if w0:=savew0 onemask 8'20 then
        begin  ! write system name !
          w3:=bufpointer;
          w2:=b.ownproc+2;
          (w3).name1:=f1:=(w2).name1;
          f1:=(w2).name2;
          w1+14880;   ! ": " !
          (w3).name2:=f1;
          bufpointer:=w0:=bufpointer+8;
        end;
        if w0:=savew0 onemask 8'40 then
        begin  ! write process name !
          w3:=bufpointer;
          w1:=savew1;
          w1:=savew1;
          w2:=(w1).internal+2;
          (w3).name1:=f1:=(w2).name1;
          f1:=(w2).name2;
          w1+32;
          (w3).name2:=f1;
          bufpointer:=w0:=bufpointer+8;
        end;
        f3:=savef3;
        w2*20;
        copy(.w3.,w0:=20,w1:=address(t0)+w2,w2:=bufpointer);
        w1:=savew1;
        w0:=(w1).buffer;
        w2+20-w0;
        (w1).buflength:=w2;

        testout(.w3.,w0:=w2,w1:=(w1).buffer,w2:=0);
        w1:=savew1;
        send(.w3.,w0:=0,w1,w2:=20480);
          f3:= savef3;
          continuemcl (.w3.,w0:=w2,w1:=savew1);
        w0:=savew0;
        w1:=savew1;
        f3:=savef3;
      end;
    end;    ! outtext !
\f





    body of outtime
    begin
      record timetext(word hourtxt,minutetxt);
      incode
        ref systime:=108;
        word daysize:=1687500,hoursize:=70313,minutesize:=1172;
        ref return,bufref;
        double savef1;
      begin
        savef1:=f1;
        bufref:=w2;
        return:=w3;
        f3:=systime.name1 lshift -9 // daysize;  ! w3:=dayno !
        f1 lshift -100;
        f2 // hoursize;   ! w2:=hour !
        f1 // minutesize; ! w1:=minute !
        w0:=0;
        f1 // 10;
        bufref.minutetxt:=w1 + 48 lshift 8 + w0 + 48 lshift 8 + 32;
        w1:=0;
        f2 // 10;
        bufref.hourtxt:=w2 + 48 lshift 8 + w1 + 48 lshift 8 + 46;
        f1:=savef1;
        w2:=bufref;
        w3:=return;
      end;
    end;    ! outtime !
\f







comment                    syscommand

this procedure checks the user identification typed at login. if it is
ok, a process is created with standard bs claims and with catalog bases
corresponding to the user identification.
the user is answered with a message telling, wheather or not the attemp
to login was succesfull.

;


    body of syscommand
    begin
      procedure login(.w3.;w0;w1);
      comment call:    w0  kind of start command 
                       w1  abs ref string1
              return:  w1  abs ref error message or zero
      ;
      procedure out(.w3.;w1);
      comment call:    w1  abs ref string1
              return:  w1  abs ref error message or zero
      ;
      procedure control(.w3.;w0;w1);
      comment call:    w0  control operation (1,2,3,4 = kill,break,stop,start)
                       w1  abs ref string1
              return:  w1  abs ref error message or zero
      ;
      procedure empty(.w3.;w1);
      comment call:    w1  abs ref userentry
              return:  w1  abs ref error message or zero
      ;
      procedure include(.w3.;w1);

      comment call:    w1  abs ref string1
              return:  w1  abs ref error message or zero
      ;
     
      label newstring,aftername,commfound,error,accept;

      incode
        double savef1,savef3;
        word logstop,radix,offset,char,savew1,savew2,savew3,count,comm,proc_no;
        ref namepointer,next;
        text(11) emptytext:="";
        text(11) string1, string2, string3,
                 string4, string5, string6,
                 string7,string8,string9;
        text(11)oscomm1 :="in",
                oscomm2 :="out",
                oscomm3 :="kill",
                oscomm4 :="",
                oscomm5 :="run",
                oscomm6 :="go",
                oscomm7 :="batch",
                oscomm8 :="break",
                oscomm9 :="stop",
                oscomm10:="start",
                oscomm11:="call",
                oscomm12:="include",
                oscomm13:="lock",
                oscomm14:="open",
                oscomm15:="halt";
      begin
        savef1:=f1;  savef3:=f3;
        testout(.w3.,w0:=!length(userentry),w1,w2:=68);
        testout(.w3.,w0:= (w1).bufrel + (w1).buflength,w1:=(w1).buffer,w2:=0);
        ! read strings !
        w0:=0;
        w1:=address(emptytext);
        w2:=address(string1);
        w3:=0;
        while w3+1<=9 do     ! zeroset string1 - string9 !
        begin
          savew3:=w3;
          copy(.w3., w0:=8, w1, w2);
          w3:=savew3;
          w2+8;
        end;

        comment    transfer commands from terminal buffer to the text
                   variables string1 - string 8
        ;
        count:=w0:=1;
        namepointer:=w0:=address(string1);
        next:=w0:=namepointer+8;
        w3:=b.userentry;
        w2:=(w3).buffer;
        comm:= w0:= (w3).state;
        w1:=0;
        logstop:=w0:= (w3).bufrel + (w3).buflength+w2;
        (w3).bufrel:= w1;
newstring:
        w0:=32;
        while w0=32 do nextchar(.w3.,w3:=logstop,w0,w1,w2);
        if w0 = 10 then goto aftername;
        if w0 = 62 then       ! '>' is start of password line !
        begin
          comm:= w0:= 0;
          goto newstring;
        end;
        if w0 < 97 then
        begin  ! integer param !
          offset:=w3:=48;
          radix:=w3:=10;
          word(namepointer):=w3:=-1;
          namepointer:=w3:=namepointer+2;
        end else
        begin  ! name param !
          offset:=w3:=0;
          radix:=w3:=256;
        end;
        while w0<>32 do
        begin
          if w3:=next=namepointer
          then goto aftername;
          if w0=10 then goto aftername;
          char:=w0;
          if w0:=offset = 0 then
          begin
            if w0:=char >= 97 then
            if w0 < 126 then goto accept;
          end;
          if w0:=char >= 48 then
          if w0 < 58 then goto accept;
!test 1;
          outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=2);  ! syntax !
          goto error;
accept:
          w0:=word(namepointer)*radix;     ! pack text or number !
          word(namepointer):=w0+char-offset;
          if w0>65535 then namepointer:=w3:=namepointer+2;
          nextchar(.w3.,w3:=logstop,w0,w1,w2);
        end;
aftername:
        ! more than 11 chars or w0=32 or w0=10 !
        if w3:=next=namepointer then
        begin
!test 2;
          outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=2);  ! syntax !
          goto error;
        end;
        if w0=32 then
        begin
          count:=w3:=count+1;
          if w3>8 then     ! max 8 params in command line !
          begin
            while w0=32 do nextchar(.w3.,w3:=logstop,w0,w1,w2);
            if w0<>10 then
            begin
!test 3;
              outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=2);  ! syntax !
              goto error;
            end;
          end;
        end;
        if w3:=offset = 0 then   ! fill textparam with null-chars !
        if w3:=next>namepointer then
        begin
          w3:=word(namepointer);
          if w3<>0 then
          while w3<65535 do w3 lshift 8;
          word(namepointer):=w3;
        end;
        namepointer:=w3:=next;
        next:=w3:=next+8;
        if w0=32 then goto newstring;
        if w0:= comm = -3 then goto newstring;
                ! first newline blind, when reading invisible password !

       comment    now all parameters have been read;

        w1:=address(oscomm1);
        w2:=address(string1);
        comm:=w3:=1;
        while w3:=comm<16 do
        begin
          compare(.w3.,w0:=4,w1,w2);
          if w0=0 then goto commfound;
          w1+8;
          comm:=w3:=comm+1;
        end;
!test 4;
        outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=0);  ! what !
        goto error;
commfound:
        w1:=address(string1);
        case w3:=comm of
        begin
          login(.w3.,w0:=3,w1);     ! in (connection to pool) !
          out(.w3.,w1);             ! out (disconnect)        !
          control(.w3.,w0:=1,w1);   ! kill                    !
          empty(.w3.,w1:=b.userentry);
          login(.w3.,w0:=2,w1);     ! run (connection via tem)!
          login(.w3.,w0:=0,w1);     ! go                      !
          login(.w3.,w0:=1,w1);     ! batch                   !
          control(.w3.,w0:=2,w1);   ! break                   !
          control(.w3.,w0:=3,w1);   ! stop                    !
          control(.w3.,w0:=4,w1);   ! start                   !
          calldev(.w3.,w1);         ! call (name device)      !
          include(.w3.,w1);         ! include users(device)   !
          control(.w3.,w0:=-1,w1);  ! lock    (block logins)  !
          control(.w3.,w0:=-2,w1);  ! open (accept login)     !
          control(.w3.,w0:=-3,w1);  ! halt                    !
        end;
        if w1 <> 0 then
        begin
error:
          if w1 = -1 then
          begin
!test 5;
            if w0:= (w1:=b.userentry).messsend < 10 then
            outtext(.w3.,w0:=8'30,w1,w2:=1);  ! ready !
            if w0:=(w1).state = -1 then (w1).state:=w0:=0;
          end;
          w1:=b.userentry;
          (w1).bufrel:= w0:= 0;
          if w0:=(w1).state = -1 then
          begin
            link(.w3.,w1,w2:=address(b.waitqfst));
            (w1).state:=w0:=0;
          end else
          if w0 < -1 then
          begin
            w0:=0;
            (w1).messsend:=w0;
            (w1).peripheral:=w0;
            (w1).internal:=w0;
            link(.w3.,w1,w2:=address(b.waitqfst));
          end else ;
        end;
        w0:=1;
        w1:=b.userentry;
        (w1).messsend:=w0;
        w3:=address(emptytext);
        f1:=b.startbase;
        monitor(72);  ! set sos own catalog base !
        f1:=savef1;
        f3:=savef3;
      end;     !  syscommand  !
\f







      body of login
        begin
          procedure checkprot(.w3.;w1;w2);
          comment call:      w1  abs ref "pass"-parameter
                             w2  abs ref password from catalog
                  return:    w1  abs ref error message or zero
                             w2  boolean rewrite catalog segment
          ;
          procedure checkdevice(.w3.;w0;w1);
          comment call:      w1  abs ref userentry
                  return:    w0  mode for reading of password:
                                   0: console (deviceno=2)
                                   2: other terminal (dev<>2)
                             other registers unchanged
          ;
          label error,error1,error2,error2_1,error3,error4,freefound,
                release;

          incode
            ! process description for create internal process !
            double corelimits;
            byte buffers,areas,
                 internals:=0,fncmask:=1792,   ! .111........ !
                 protreg,protkey;
            double maxbase,stdbase;
            double claim0,claim1,claim2,claim3;

            byte  logop:=5,logmode:=0;
            ref first,last;
            word segm,zero:=0,rewrite;
            word savew0,savew1,savew2,savew3;
            ref jobfile:=0,procentry;
            double savef3;
            text(11) emptytext:="",jobf:="jobfile";
            ref string1,string2,string3,string4,string5,string6,
                string7,string8;
            array(1:10) tail of word;
            array(1:8)answ of word;
            byte simop,simmode:=0;
            ref simfirst,simlast;
            word simlocid;
            text(9) simtext:="'1''1' att   ";
            text(11)trmname;
            word nl:=10;
            byte temop,temmode:=0;
            word localid;
            ref termpda;
            byte bufs,timers;
            text(14) poolname;
            word help;

 comment    format of login command is:

     s1        s2            s3       s4
  ( go    )
  ( run   ) <procname>  ( jobfile <filename> )(.)
  ( batch )
              s3/5    s4/6            s5/7     s6/8
            ( pass <passname>      (newpass <passname>)(.) )(.)
            ( >password <passname>                         )

 or:
    s1    s2         s3          s4      s5          s6       s7
    in <procname> <termname>  ( pass <passname>  (newpass <passname>)(.) )(.)
                              ( >password <passname>                     )
 ;

          begin
            savew0:=w0;  ! login-kind: 0=go, 1=batch, 2=run, 3=in !
            savef3:=f3;
            w3:=b.userentry;
            if w0:=b.sysstate <> 0 then if w0:=b.mainconsref<>(w3).peripheral then
            begin
!test 6;
              outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=29);  ! forbidden - system locked !
              goto error;
            end;
            string1:=w1; w1+8;
            string2:=w1; w1+8;
            string3:=w1; w1+8;
            string4:=w1; w1+8;
            string5:=w1; w1+8;
            string6:=w1; w1+8;
            string7:=w1; w1+8;
            string8:=w1;
            compare(.w3.,w0:=8,w1:=string3,w2:=address(jobf));
            if w0 = 0 then jobfile:=w3:=string4;

            w1:=b.userentry;
            if w3:=(w1).state = -1 then       ! known terminal creating new job !
            begin
              if w0:=jobfile = 0 then         ! at most one job without jobfile !
              begin
!test 7;
                outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=7);  ! forbidden !
                link (.w3., w1:= b.userentry, w2:= address(b.activqfst));
                w1:= -1;
                goto error;
              end;
              w1:=b.lastuser;
              while w1-!length(userentry) >= b.firstuser do
              begin
                if w0:=(w1).internal = 0 then goto freefound;
              end;
!test 8;
              outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=6);  ! process creation !
              link (.w3., w1:= b.userentry, w2:= address(b.activqfst));
              w1:= -1;
              goto error;
freefound:
              procentry:=w2:=b.userentry;  ! old entry !
              b.userentry:=w1;             ! new entry !
              (w2).state:=w0:=0;
              (w1).peripheral:=w0:=(w2).peripheral;
              (w1).internal:=w0;
              (w1).state:=w0:=-2;
              (w1).buflength:=w0:=(w2).buflength;
              copy (.w3., w0, w1:=(w2).buffer, w2:=(w2:=b.userentry).buffer);
              link(.w3.,w1:=procentry,w2:=address(b.activqfst));
            end;
            procentry:=w1:=b.userentry;    ! new entry !
            (w1).primdevi:=w0:=(w1).peripheral;
            w0:=savew0;
            if w0 = 3 then w2:=string3 else w2:=0;
            scancat(.w3.,w0,w1:=string2,w2);
            if w0 < 0 then
            begin
              if w0 = -3 then w2:=30  ! user catalog reserved !
                         else w2:=3;  ! identification illegal !
!test 9;
              outtext(.w3.,w0:=8'31,w1:=procentry,w2);  
              goto error1;
            end else segm:=w0;
            b.procdescr:=w1;
            b.termdescr:=w2;
            if w0:=savew0 < 3 then   ! go, run or batch !
            begin
              if w1:=jobfile = 0 then w1:=string3
                                     else w1:=string5;
              checkprot(.w3.,w1,w2:=b.procdescr+!position(ppass));
              if w1 <> 0 then goto error1;
              rewrite:=w2;
              if w1:=jobfile > 0 then
              begin
                w1:=procentry;
                w2:=(w1).peripheral;
                -(w2);
                (w1).peripheral:=w2;  ! jobfile is marked by negative peripheral !
              w2:=address((w1).pr_in);
                (w2).word:=w0:=4;
                copy(.w3.,w0:=8,w1:=jobfile,w2+2);  ! insert jobfile name in i/o-buffer !
              end else
              begin
                w1:=procentry;
              w2:=address((w1).pr_in);
                (w2).word:=w0:=8;
                copy(.w3.,w0:=8,w1:=b.sosterm+2,w2+2);  ! pseudo-sos-name in i/o-buffer !
              end;
            w2:=address((w1:=procentry).pr_out);
            (w2).word:=w0:=8;
            copy(.w3.,w0:=8,w1:=b.sosterm+2,w2+2);
              w3:=b.procdescr;
              buffers:=w0:=(w3).procbuffers;
              areas:=w0:=(w3).procareas;
              w0:=(w3).procsb1;
              w1:=(w3).procsb2;
              stdbase:=f1;
              w0:=(w3).procmb1;
              w1:=(w3).procmb2;
              maxbase:=f1;
              w0:=b.fstcore;
              if w1:=b.topcore-b.fstcore > (w3).pmaxsize
                then w1:=(w3).pmaxsize+511 lshift -9 lshift 9;
              if w1 < (w3).pminsize then
              begin
!test 10;
                outtext(.w3.,w0:=8'31,w1:=procentry,w2:=4);  ! no room in primary store !
                goto error1;
              end;
          w1 lshift -11 lshift 11; ! make size a 2K multiplum !
              procentry.procsize:=w1;
              w1+w0;
              corelimits:=f1;
              protreg:=w1:=b.childpr;
              protkey:=w1:=b.childpk;
              w3:=address(zero);
              f1:=stdbase;
              monitor(72);! set sos own cat base !
!test 445;
              if w3:=jobfile > 0 then
              begin
                tail(w1:=1);
                w3:=jobfile;
                monitor(42);  ! lookup jobfile !
                if w0 <> 0 then
                begin
!test 11;
                  outtext(.w3.,w0:=8'31,w1:=procentry,w2:=10);  ! no jobfile !
                  goto error1;
                end;
              end;
              w3:=address(b.t_mdul);
              monitor(80);  ! create pseudo process "tem" !
              if w0 <> 0 then
              begin
!test 12;
                if w0 = 3 then outtext(.w3.,w0:=8'31,w1:=procentry,w2:=28)  ! user conflict !
                else outtext(.w3.,w0:=8'31,w1:=procentry,w2:=6);  ! process creation !
                goto error1;
              end;
              w3:=address(b.p_mdul);
              monitor(80);  ! create pseudo process "primo" !
              if w0<>0 then
              begin
!test 14;
                if w0 = 3 then outtext(.w3.,w0:=8'31,w1:=procentry,w2:=28)
                else outtext(.w3.,w0:=8'31,w1:=procentry,w2:=6);
                goto error2_1;
              end;
              f1:=b.startbase;
              w3:=address(zero);
              monitor(72);  ! reset sos own cat base !
!test 447;
              if w0:=b.freebufs-buffers<0 then
              begin
!test 16;
                outtext(.w3.,w0:=8'31,w1:=procentry,w2:=6);  ! process creation !
                goto error2;
              end
              else b.freebufs:=w0;
              w1:=address(corelimits);
              w3:=string2;
              monitor(56);  ! create internal process !
              if w0<>0 then
              begin
!test 17;
                          outtext(.w3.,w0:=8'31,w1:=procentry,w2:=6);  ! process creation !
                goto error3;
              end;
              w3:=b.procdescr;
              w0:=(w3).procub1;
              w1:=(w3).procub2;
              w3:= string2;
              monitor(72);  ! set catalog base  = user base !
              if w0<>0 then
              begin
!test 18;
                outtext(.w3.,w0:=8'31,w1:=procentry,w2:=6);  ! process creation !
                goto error4;
              end;
              monitor(4);  ! get process description address in w0 !
              w1:=procentry;
              (w1).internal:=w0;
              w3:=b.procdescr;
              w2:=w3+!position(procdiscs);
              w1:=0;
              while w1+1<13 do
              begin
                w2+!length(procdisc);
                savew1:=w1;
                testout(.w3.,w0:=!length(procdisc),w1:=w2,w2:=68);
                w2:=w1;  w1:=savew1;
                if w3:=(w2).word=0 then w1:=13
                else
                begin
                  savew1:=w1;
                  savew2:=w2;
                  w1:=w2+8;
                  w2:=address(claim0);
                  copy(.w3.,w0:=16,w1,w2);
                  w1:=w2;
                  w2:=savew2;
                  w3:=string2;
                  monitor(78);  ! set bs claims !
                  if w0<>0 then
                  begin
!test 19;
                    outtext(.w3.,w0:=8'31,w1:=procentry,w2:=5);  ! claims exceeded !
                    goto error4;
                  end;
                  w1:=savew1;
                  w2:=savew2;
                end;
              end;
              if w0:=savew0 = 2 then  ! run  -  connect terminal via tem !
              begin
                ! generate poolname: char 1-3 of sos-name, char 4-11 of procname !
                copy(.w3.,w0:=2,w1:=b.ownproc+2,w2:=address(poolname));
                copy(.w3.,w0:=6,w1:=procentry.internal+2,w2+2);
                temop:=w0:=90;  ! create pool !
                w1:=address(temop);
                w3:=address(b.t_mdul);
                monitor(16);  ! send message !
                answ(w1:=1);
                monitor(18);  ! wait answer !
                if w0 or (w1).word <> 1 then
                begin
!test 20;
                  outtext(.w3.,w0:=8'31,w1:=procentry,w2:=9);  ! terminal connection error !
                  goto error4;
                end;
                w3:=address(poolname);
                monitor(4);   ! get process description !
                if w2:=jobfile > 0 then -(w0);
                procentry.peripheral:=w0;
                termpda:=w0:=procentry.primdevi;
                localid:=w0:=0;
                bufs:=w0:=1;
                timers:=w0:=5;
                temop:=w0:=100;  ! create link !
                temmode:=w0:=2;  ! transparent link !
                w3:=address(poolname);
                w1:=address(temop);
                monitor(16);  ! send message !
                answ(w1:=1);
                monitor(18);  ! wait answer !
                if w0 or (w1).word <> 1 then
                begin
                  temmode:=w0:=0;
                  temop:=w0:=92;
                  w1:=address(temop);
                  w3:=address(b.t_mdul);
                  monitor(16);  ! send message !
                  answ(w1:=1);
                  monitor(18);  ! wait answer !
                  procentry.peripheral:=w0:=procentry.primdevi;
!test 21;
                  outtext(.w3.,w0:=8'31,w1:=procentry,w2:=9);  ! terminal connection error !
                  goto error4;
                end;
                procentry.primio:=w0:=0;
                procentry.currlocid:=w0:=0;
              end
              else procentry.primio:=w0:=0;     ! go/batch login !
              w1:=procentry;
              link(.w3.,w1,w2:=address(b.activqfst));
                comment  the new job is linked into the activequeue independent
                         of the job type. a batchjob is later on moved to the
                         batchqueue (at "activate:" in the main program) because
                         of the priority class
                ;
              w0:=1;
              (w1).messsend:=w0;
              (w1).statusinf:=w0:=0;
              w2:=(w1).buffer;
              w1:=b.procdescr+!position(procfp);
              copy(.w3.,w0:=40,w1,w2);
              w1:=procentry;
              if w0:=savew0 = 1
              then  ! batch !  (w1).class:=w0:=b.batchclass-b.timerloss-1
              else             (w1).class:=w0:=0;
              (w1).state:=w0:=3;
              (w1).state2:=w0:=-1;
              (w1).prio:=w0:=0;
              (w1).intervent:=w0;
              w1:=procentry;
              (w1).buffer:=w0:=(w1).buffer+50;
!test 22;
              outtext(.w3.,w0:=8'70,w1,w2:=19);  ! enrolled !
              (w1).buffer:=w0:=(w1).buffer-50;
              (w1).buflength:=w0:=40;
              w0:=1;
              (w1).messsend:=w0;
              w1:=0;
            end      ! go/run/batch !
          else
            if w0 = 3 then   !  in - connect terminal to pool !
            begin
              checkprot(.w3.,w1:=string4,w2:=b.termdescr+!position(userkey));
              if w1 <> 0 then goto error1;
              rewrite:=w2;
              ! generate poolname: "tem<termname>" !
              copy(.w3.,w0:=2,w1:=address(b.t_mdul),w2:=address(poolname));
              copy(.w3.,w0:=6,w1:=string2,w2+2);
              termpda:=w0:=(w1:=b.userentry).peripheral;
              localid:=w0:=(w3:=b.termdescr).intid;
              simlocid:=w0;
              bufs:=w0:=(w3).tbufs;
              timers:=w0:=(w3).ttimers;
              temop:=w0:=100;  ! create link !
              w1:=address(temop);
              w3:=address(poolname);
              monitor(16);  ! send message !
              answ(w1:=1);
              monitor(18);  ! wait answer !
              if w0 or (w1).word <> 1 then
              begin
                if w1:=w0 and 8'1020 <> 0 then w2:=8  ! busy !
                                          else w2:=9;  ! terminal connection error !
!test 23;
                outtext(.w3.,w0:=8'31,w1:=procentry,w2);
                goto error1;
              end;
              copy(.w3.,w0:=8,w1:=termpda+2,w2:=address(trmname));
              simfirst:=w1:=address(simlocid);
              simlast:=w1:=address(nl);
              simop:= w0:= 9;
              w1:=address(simop);
              w3:=address(poolname);
              monitor(16);  ! send message (simulate  input) !
              answ(w1:=1);
              monitor(18);  ! wait answer !
!test 24;
              outtext(.w3.,w0:=8'30,w1:=procentry,w2:=11);  ! terminal connected !
            end else;
            if w2:=rewrite <> 0 then
            begin
              help:=w1;
              first:=w0:=b.topcore-512;
              last:=w0:=b.topcore-2;
              transport(.w2.,w1:=address(logop),w3:=address(b.usercat));
              w1:=help;
            end;
            goto release;
error4:
            w3:=string2;
            monitor(64);  ! remove child process !
error3:
            b.freebufs:=w0:=b.freebufs+buffers;
error2:
            help:=w1;
            f1:=stdbase;
            w3:=address(zero);
            monitor(72); ! set own catalog base !
            w3:=address(b.p_mdul);
            monitor(64); ! remove process !
            w1:=help;
error2_1:
            help:=w1;
            f1:=stdbase;
            w3:=address(zero);
            monitor(72);  ! set sos catalog base !
            w3:=address(b.t_mdul);
            monitor(64);  ! remove pseudo process !
            w1:=help;
release:
error1:
            w3:=address(b.usercat);
            monitor(10);  ! release usercat !
error:
            w0:=savew0;
            f3:=savef3;
          end;     !  login  !
\f






        body of scancat
        begin
          label procfound,newsegm,termfound,exit;
          incode
            ref procname,termname,return;
            array(1:!length(procdescr)) process of byte;
            byte logop,logmode:=0;
            ref first,last;
            word segm,proc_no,savew1,logstop,zero:=0;
          begin
            procname:=w1;
            termname:=w2;
            return:=w3;
            w3:=address(zero);
            f1:=b.startbase;
            w0:=w1;
            monitor(72);  ! set own cat base !
            w3:=address(b.usercat);
            monitor(8);   ! reserve process, i.e. open(z,4,<:soscat:>,0) !
            if w0 <> 0 then
            begin
              w0:=-3;
              goto exit;
            end;
            first:=w0:=b.topcore-512;
            last:=w0:=b.topcore-2;
            logop:=w0:=3;
            segm:=w0:=0;
            w1:=address(logop);
            transport(.w2.,w1,w3);
            w3:=b.topcore-2;
            proc_no:=w3:=(w3-4).word;
            w1:=0;
            w2:=b.topcore-512-!length(prindex);
            while w1+1<=proc_no do
            begin
              w3:=0;
              w0:=w1;
              if f0 mod 50=1 then
                if w1<>1 then
                begin
                  segm:=w0;
                  savew1:=w1;
                  w1:=address(logop);
                  w3:=address(b.usercat);
                  transport(.w2.,w1,w3);
                  w1:=savew1;
                  w2:=b.topcore-512-!length(prindex);
                end;
              w2+!length(prindex);
              savew1:=w1;
              compare(.w3.,w0:=8,w1:=procname,w2);
              if w0 = 0 then goto procfound;
              w1:=savew1;
            end;
            w0:=-1;
            goto exit;
procfound:
            segm:=w1:=(w2).prsegmno;
            w1:=address(logop);
            w3:=address(b.usercat);
            transport(.w2.,w1,w3);
            w1:=b.topcore-512;
            process(w2:=1);
            copy(.w3.,w0:=!length(procdescr),w1,w2);
            testout(.w3.,w0,w1,w2:=68);
            ! find terminal in soscat !
            if w2:=termname = 0 then
            begin
              w0:=segm;
              goto exit;
            end;
            w2:=b.topcore-512;
            w2+!length(procdescr);
            w2-!length(termdescr);
            w3:=b.topcore-!length(termdescr);
            logstop:=w3;
newsegm:
!test 540;
            while w2+!length(termdescr)<logstop do
            begin
              if w1:=(w2).word=-1 then w2:=logstop
              else begin
                compare(.w3.,w0:=8,w1:=termname,w2);
                if w0=0 then goto termfound;
              end;
            end;
            w2:=b.topcore-2;
            if w0:=(w2).word<>-1 then
            begin
              segm:=w0;
              w1:=address(logop);
              w3:=address(b.usercat);
              transport(.w2.,w1,w3);
              w2:=b.topcore-512;
              w2-!length(termdescr);
              goto newsegm;
            end;
            w0:=-2;
            goto exit;
termfound:
            b.termdescr:=w2;
            testout(.w3.,w0:=!length(termdescr),w1:=w2,w2:=68);
            process(w1:=1);
            w2:=b.termdescr;
            w0:=segm;
exit:
            w3:=return;
          end;
        end;    !  scancat !
\f





        body of checkprot
        begin
          label bad_passw, exit, found;
          incode
            text(11) pass:="pass",newpass:="newpass",emptytext:="",
                     pass2:="password", passtxt:=">password ";
            ref password,return;
          begin
            return:=w3;
            password:=w2;     ! addr of correct password !
            compare(.w3.,w0:=8,w1,w2:=address(pass));
            if w0 <> 0 then
            begin
              compare (.w3., w0:=8, w1, w2:=address(pass2));
              if w0=0 then goto found;
              compare(.w3.,w0:=8,w1,w2:=address(emptytext));
              if w0 <> 0 then
              begin
!test 25;
                outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=2);  ! syntax !
                goto exit;
              end;
              w2:=w1;     ! addr of read passw:= addr of empty param !
            end else
            begin
found:
              w2:= w1+8;     ! addr of password param !
            end;
            w1:=password;
            compare(.w3.,w0:=8,w1,w2);
            if w0 <> 0 then
            begin
              compare (.w3., w0:=8, w1:=address(emptytext), w2);
              w1:= b.userentry;
              if w0<>0 then      ! password param <> empty !
              begin
bad_passw:
!test 26;
                outtext(.w3.,w0:=8'31,w1,w2:=13);  ! bad password !
                goto exit;
              end else
              if w0:=(w1).state = -3 then goto bad_passw
              else
              begin              ! password must be typed invisible !
                (w1).state:= w0:= -3;   ! awaiting password !
                (w1).bufrel:= w0:= (w1).buflength;
                w2:= (w1).buffer + w0;  ! start addr !
                (w1).buflength:= w0:= 8;
                copy (.w3., w0, w1:=address(passtxt), w2);
                testout (.w3., w0, w1, w2:=0);
                checkdevice (.w3., w0, w1:=b.userentry);
                b.passmode:= w0;   ! 0 = console (deviceno=2)
                                     2 = other terminal       !
                w0:= (w1).bufrel;
                -(w0);
                send (.w3., w0, w1, w2:=20480);
                (w1).bufrel:= w0:= (w1).bufrel + 8;
                -(w0);
                (w1).buflength:= w3:= b.maxbuf - (w1).bufrel;
                send (.w3., w0, w1, w2:=12288+b.passmode);
                         ! read password without echo, mode=2 !
                link(.w3.,w1,w2:=address(b.waitqfst));
                w3:= address(b.usercat);
                monitor(10); ! release usercat !
                goto b.continue;
              end;
            end;
            compare(.w3.,w0:=8,w1:=address(newpass),w2+8);
            if w0 <> 0 then
            begin
              compare(.w3.,w0:=8,w1:=address(emptytext),w2);
              if w0 <> 0 then
              begin
!test 27;
                outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=2);  ! syntax !
                goto exit;
              end;
              w2:=0;               ! rewrite:= false !
            end else
            begin
              w1:=w2+8;
              if w0:=(w1).word < 0 then
              begin
!test 28;
                outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=2);   ! syntax !
                goto exit;
              end;
              copy(.w3.,w0:=8,w1:=w2+8,w2:=password);
              w2:=1;               ! rewrite:= true !
            end;
            w1:=0;
exit:
            w3:=return;
          end;
        end;    !  checkprot  !
\f





        body of checkdevice
        begin
          incode
            double w12;
            word return;
          begin
            w12:= f2;
            return:= w3;
            w3:=74;                ! ref to name table !
            w3:=(w3).word+4;       ! ref to proc.descr. of device 2 !
            w2:=(w3).word+2;       !  -  -    -  name   -     -     !
            w1:=(w1).peripheral;
            if w1<0 then -(w1);    ! ref to proc.descr. of terminal !
            w1+2;                  !  -  -    -  name   -     -     !
            compare(.w3., w0:=8, w1, w2);
            if w0<>0 then w0:=8;
            f2:=w12;
            w3:=return;
          end;
        end;     ! checkdevice !


      end;    !  login  !
\f







        body of out
        begin
          label return;
          record cont_ans ( word stat,l_id,perif,buftimer,pool);
          incode
            word savew0;
            double savef3;
            byte temop,temmode:=0;
            ref first,last;
            word simlocid;
            text(28) simtxt:="'2''2' out   '10'";
            array(1:8) answ of word;
            text(14) emptytext:="",namebuf:="";
            byte op1:=106,mode1:=0;  ! lookup term !
            word locid,peri;
          begin
            savew0:= w0;
            savef3:= f3;
            compare(.w3.,w0:=8,w1+8,w2:=address(emptytext));
            if w0<>0 then
            begin
!test 29;
              outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=2);  ! syntax !
              goto return;
            end;

            w0:= (w1:=b.userentry).peripheral;
            peri:=w0;
            w1:= address(op1);
            w3:= address(b.t_mdul);
            monitor(16);  ! send message !
            w1:= b.lastuser;
            monitor(18);  ! wait answer !
            if w0 or (w1).stat<>1 then
            begin ! terminal not known !
!test 30;
              outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=14);  ! not connected !
              goto return;
            end;
            locid:= w0:= (w1).l_id;
            simlocid:=w0;
            copy(.w3.,w0:=8,w1:=(w1).pool+2,w2:=address(namebuf));
            temop:=w0:=9;    ! simulate input !
            first:=w0:=address(simlocid);
            w0+8;
            last:=w0;
            w1:=address(temop);
            w3:=address(namebuf);
            monitor(16);  ! send message !
            answ(w1:=1);
            monitor(18);  ! wait answer !
!test 901;
            op1:=w0:=102;  ! remove link (soft) !
            w1:=address(op1);
            monitor(16);  ! send message !
            answ(w1:=1);
            monitor(18);  ! wait answer !
!test 31;
            if w0 or (w1).word = 1
            then outtext(.w3.,w0:=8'30,w1:=b.userentry,w2:=12)  ! terminal disconnected !
            else outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=16); ! disconnection not ok !
return:
            w0:= savew0;
            f3:= savef3;
          end;
        end; ! out !
\f




        body of control
        begin
          label error,found;
          incode
            ref string1,string2,string3,string4;
            word savew0,savew1;
            double savef3;
            text(11) emptytext:="",all:="all";
            byte temop,temmode;
            word localid;
            ref termpda;
            byte bufs,timers;
            ref poolpda;
            word recfull,bytesfree,dummy,allcommand:=0;
            byte stopop:=16,stopmode:=1;
            text(20) stoptxt:="system closed";
            byte empop:=16,empmode:=0;
            text(20) emptxt:="system empty";
          begin
            savew0:=w0;  ! control operation:  1=kill     -1=lock
                                               2=break    -2=open
                                               3=stop     -3=halt
                                               4=start              !
            savef3:=f3;
            string1:=w1; w1+8;
            string2:=w1; w1+8;
            string3:=w1; w1+8;
            string4:=w1;
!test 700;
            w1:=address(b.operator);
            w2:=string2;
            compare(.w3.,w0:=8,w1,w2);
            if w0<>0 then
            begin
              w1:=address(emptytext);
              compare(.w3.,w0:=8,w1,w2);
              if w0<>0 then
              begin
                compare(.w3.,w0:=8,w1,w2:=string3);
                if w0 <> 0 then
                begin
!test 33;
                  outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=2);  ! syntax !
                  goto error;
                end;
                w3:=string2;
                monitor(4);  ! get process description !
!test 995;
                if w0 = 0 then
                begin
!test 34;
                  outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=15);  ! process unknown !
                  goto error;
                end;
                w1:=b.lastuser;
                w3:=b.userentry;
                while w1-!length(userentry) >= b.firstuser do
                begin
                  if w0 = (w1).internal then
                  if w2:=(w1).primdevi = (w3).peripheral then goto found;
                end;
!test 35;
                outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=15);  ! process unknown !
                goto error;
              end;
              ! controlled by own terminal !
              w1:=b.userentry;
              if w0:=(w1).state = -1 then
              begin
found:
                if w3:=savew0 <= 0 then
                begin
!test 36;
                  outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=7);  ! forbidden !
                  link(.w3.,w1,w2:=address(b.activqfst));
                  w1:= -1;
                  goto error;
                end;
                case w3:=savew0 of
                begin
                  begin  ! user kill !
                    (w1).intervent:=w0:=3;
                    clean(.w3.,w1);
                  end;
                  begin  ! user break !
                    break(.w3.,w1);
                    if w3:= b.syscond zeromask 2'010 then
                    begin
                      if w3:= (w1).peripheral>0 then w0:= -1
                      else w0:= 7;
                    end else w0:= 7;
                    (w1).intervent:=w0;
                  end;
                  begin  ! stop !
                    link(.w3.,w1,w2:=address(b.waitqfst));
                    if w0:=(w1).messgot > 10 then
                    begin
                      empty_answer(.w3.,w0:=1,w1,w2:=0);
                    end;
                    (w1).messsend:=w0;
                    (w1).state:=w0:=0;
                  end;
                  begin  ! start !
                    link(.w3.,w1,w2:=address(b.activqfst));
                    if w0:=(w1).messgot > 10 then
                    begin
                      empty_answer(.w3.,w0:=1,w1,w2:=0);
                    end;
                    (w1).messsend:=w0;
                    (w1).state:=w0:=0;
                  end;
                end;
                w1:=-1;
                goto error;
              end;
              temop:=w0:=106;   ! lookup terminal !
              temmode:=w0:=0;
              termpda:=w0:=(w1:=b.userentry).peripheral;
              w1:=address(temop);
              w3:=address(b.t_mdul);
              monitor(16);  ! send message !
              monitor(18);  ! wait answer !
              if w0 or (w1).word <> 1 then
              begin
!test 37;
                outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=14);  ! not connected !
                goto error;
              end;
              w0:=poolpda;
              w1:=b.firstuser-!length(userentry);
              while w1+!length(userentry) < b.lastuser do
              begin
                if w0 = (w1).peripheral then goto found;
              end;
!test 38;
              outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=15);  ! process unknown !
              goto error;
            end
            else begin
              ! controlled by operator !
              if w0:=(w1:=b.userentry).peripheral <> b.mainconsref then
              begin
!test 39;
                outtext(.w3.,w0:=8'31,w1,w2:=7);  ! forbidden !
                goto error;
              end;
              w1:=address(emptytext);
              compare(.w3.,w0:=8,w1,w2:=string4);
              if w0 <> 0 then
              begin
!test 40;
                outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=2);  ! syntax !
                goto error;
              end;
              if w0:=savew0 <= 0 then
              begin
                compare(.w3.,w0:=8,w1:=address(emptytext),w2:=string3);
                if w0 <> 0 then
                begin
!test 41;
                  outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=2);  ! syntax !
                  goto error;
                end;
                if w0:=savew0 = -1 then  ! lock !
                begin
                  b.sysstate:=w0:=1;
                  w1:=b.lastuser;
                  w0:=0;
                  while w1-!length(userentry) >= b.firstuser do
                  begin
                    if w3:=(w1).internal > 0 then
                    if w3:=(w3).word = 0 then w0+1;
                  end;
                  if w0 = 0 then opmess(.w3.,w1:=address(empop),w2:=b.ownproc);
                end else
                if w0 = -2 then  ! open !
                begin
                  b.sysstate:=w0:=0;
                end else
                if w0 = -3 then  ! halt !
                begin
                  opmess(.w3.,w1:=address(stopop),w2:=b.ownproc);
                end else
                ;
                w1:=-1;
                goto error;
              end;
              compare(.w3.,w0:=8,w1,w2:=string3);
              if w0 = 0 then
              begin
!test 42;
                outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=2);  ! syntax !
                goto error;
              end;
              w1:=b.firstuser-!length(userentry);
              while w1+!length(userentry)<b.lastuser do
              begin
!test 710;
                savew1 :=w1;
                w1:=(w1).internal+2;
                compare(.w3.,w0:=8,w1,w2:=string3);
                if w0 <> 0 then
                begin
                  compare(.w3.,w0:=8,w1:=address(all),w2);
                  if w0 = 0 then allcommand:=w3:=1;
                end;
                w1:=savew1;
                if w0=0 then
                begin
                  if w3:=(w1).internal > 0 then
                  if w0:=(w3).word = 0 then
                  case w3:=savew0 of
                  begin
                    begin  ! operator kill !
                      (w1).intervent:=w0:=4;
                      clean(.w3.,w1);
                    end;
                    begin  ! operator break !
                      break(.w3.,w1);
                      if w3:= b.syscond zeromask 2'010 then
                      begin
                        if w3:= (w1).peripheral>0 then w0:= -1
                        else w0:= 8;
                      end else w0:= 8;
                      (w1).intervent:=w0;
                    end;
                    begin  ! stop !
                      link(.w3.,w1,w2:=address(b.waitqfst));
                      if w0:=(w1).messgot > 10 then
                      begin
                        empty_answer(.w3.,w0:=1,w1,w2:=0);
                      end;
                      (w1).messsend:=w0;
                      (w1).state:=w0:=0;
                    end;
                    begin  ! start !
                      if w0:=(w1).class+b.timerloss < b.batchclass then
                      begin  ! link to front of batch queue !
                        if w1 <> b.batchqfst then link(.w3.,w1,w2:=address(b.batchqfst));
                      end else link(.w3.,w1,w2:=address(b.activqfst));
                      if w0:=(w1).messgot > 10 then
                      begin
                        empty_answer(.w3.,w0:=1,w1,w2:=0);
                      end;
                      (w1).messsend:=w0;
                      (w1).state:=w0:=0;
                    end;
                  end;
                  w1:=-1;
                  if w0:=allcommand <> 1 then goto error;
                  w1:=savew1;
                end;
              end;
!test 43;
              if w0:=allcommand <> 1
              then outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=15)  ! process unknown !
              else w1:=-1;
              goto error;
            end;
            w1:=-1;
error:
            w0:=savew0;
            f3:=savef3;
          end;
        end;  ! control !
\f





        body of empty
        begin
          incode
            word savew0;
            double savef3;
          begin
            savew0:=w0;
            savef3:=f3;
            w1:=-1;
            w0:=savew0;
            f3:=savef3;
          end;
        end;  ! empty !
\f




        body of calldev
        begin
          label syntaxerror,exit;
          record callparam (word pkind,pvalue);
          incode
            word savew0,work;
            double savef3;
            ref string1,string2,string3,string4,string5,string6;
            text(11) emptytext:="",start:="start",proc;
          begin
            savew0:=w0;
            savef3:=f3;
            string1:=w1; w1+8;
            string2:=w1; w1+8;
            string3:=w1; w1+8;
            string4:=w1; w1+8;
            string5:=w1; w1+8;
            string6:=w1;
            if w0:=string2.pkind <> -1 then goto syntaxerror;
            compare(.w3.,w0:=8,w1:=string3,w2:=address(emptytext));
            if w0 = 0 then goto syntaxerror;
            w1:=string2.pvalue;
            w3:=string3;
            monitor(54);  ! create peripheral process !
!test 111;
            if w0 <> 0 then
            if w0 <> 3 then
            begin
!test 44;
              outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=17);  ! call not accepted !
              goto exit;
            end;
            copy(.w3.,w0:=8,w1:=address(emptytext),w2:=string3);
            include(.w3.,w1:=string1);
            if w1 <> -1 then goto exit;
            compare(.w3.,w0:=8,w1:=string4,w2:=address(emptytext));
            if w0 = 0 then
            begin
              w1:=-1;
              goto exit;
            end;
            compare(.w3.,w0:=8,w1,w2:=address(start));
            if w0 = 0 then
            begin
              copy(.w3.,w0:=8,w1:=string4,w2:=string1);
              copy(.w3.,w0,w1:=string5,w2:=string2);
              copy(.w3.,w0,w1:=string6,w2:=string3);
              copy(.w3.,w0,w1:=address(emptytext),w2:=string4);
              control(.w3.,w0:=4,w1:=string1);
              goto exit;
            end;
syntaxerror:
!test 45;
            outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=2);  ! syntax !
exit:
            w0:=savew0;
            f3:=savef3;
          end;
        end;    ! calldev !
\f




        body of include
        begin
          label exit;
          record param(word pkind,pvalue);
          incode
            text(11) proc,emptytext:="";
            double savef3;
            ref string1,string2,string3;
            word work,savew0;
          begin
            savew0:=w0;
            savef3:=f3;
            string1:=w1; w1+8;
            string2:=w1; w1+8;
            string3:=w1;
            compare(.w3.,w0:=8,w1,w2:=address(emptytext));
            if w0 <> 0 then
            begin
!test 46;
              outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=2);  ! syntax !
              goto exit;
            end;
            w1:=string2;
            if w0:=(w1).pkind <> -1 then
            begin
!test 47;
              outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=2);  ! syntax !
              goto exit;
            end;
            w3:=b.lastuser;
            w2:=address(proc);
            while w3-!length(userentry) >= b.firstuser do
            begin
              if w1:=(w3).internal > 0 then
              begin
                work:=w3;
                if w0:=(w1).word = 0 then
                begin
                  copy(.w3.,w0:=8,w1+2,w2);
                  w3:=w2;
                  w1:=string2.pvalue;
                  monitor(12);  ! include user !
                  if w0 <> 0 then
                  begin
!test 48;
                    outtext(.w3.,w0:=8'31,w1:=b.userentry,w2:=18);  ! include not accepted !
                    goto exit;
                  end;
                end;
                w3:=work;
              end;
            end;
            w1:=-1;
exit:
            w0:=savew0;
            f3:=savef3;
          end;
        end;  ! include !

    end;  ! syscommand !
\f





comment                    break

when a process is too cpu bound or when the terminal operator asks for
it, the system will provoke a break of the process (break 8 = parent break)
this is done by modifying the process using the dumped registers in the
process description and then restart the process in its break routine
;

    body of break
    begin
      label exit;
      record dumparea(word r0,r1,r2,r3,exep,instr,cause);
      incode
        double savef1,savef3;
        word bufferrel,savedic;
        text(14) childname,terminal;
        byte ioop,iomode:=0;
        word first,last,segmnt;
      begin
        savef1:=f1;
        savef3:=f3;
        if w0:=(w1).intervent = 0 then
        begin 
          if w0:=(w1).messgot > 10 then
          begin
            empty_answer(.w3.,w0:=1,w1,w2:=0);
          end;
          if w0:=b.syscond zeromask 2'010 then
          if w0:=(w1).peripheral > 0 then
          begin
            (w1).state:= w0:= 3;
            (w1).state2:= w0:= -1;
            startstop (.w3., w0:=0, w1);    ! stop !
            w1:= (w1).internal+2;           ! ref process name !
            scancat (.w3., w0, w1, w2:=0);
            if w0 < 0 then
            begin
              if w0 = -3 then w2:=30        ! usercat reserv !
                         else w2:=3;        ! ident illegal  !
!test 50;
              outtext (.w3., w0:=8'31, w1:=b.userentry, w2);
              (w1).state2:= w0:= 1;         ! waiting for remove process !
              goto exit;
            end;
            b.procdescr:= w1;
            w3:= address(childname);
            f1:= savef1;
            w2:= (w1).internal + 2;          ! ref process name !
            (w3).name1:= f1:= (w2).name1;
            (w3).name2:= f1:= (w2).name2;
            w2:= b.procdescr;
            w0:= (w2).procub1;               ! user base from soscat !
            w1:= (w2).procub2;
            monitor(72);   ! reset catalog base = user base !
            link (.w3., w1:=b.userentry, w2:=address(b.activqfst));
            goto exit;
          end;

          (w1).intervent:=w0:=-1;
          w2:=(w1).internal+b.relintrpt;
          if w0:=(w2).word >= b.fstcore then
          begin comment interrupt address is set;
            savedic:=w0+16;
            w0:=(w2).word;
            w0-b.fstcore;
            bufferrel:=w3:=w0 extract 9;
            segmnt:=w0 lshift -9 + (w1).swopsegm;
            ioop:=w0:=3;
            w1:=address(ioop);
            w3:=address(b.swname);
            w0:=b.topcore;
            last:=w0;
            w0-1022;
            first:=w0;
            monitor(16);  comment send message;
            w1:=b.lastuser;
            monitor(18);  comment wait answer;
key (0):= w0; ! test 0 !
            f1:=savef1;
            w3:=address(childname);
            w2:=(w1).internal+2;
            (w3).name1:=f1:=(w2).name1;
            (w3).name2:=f1:=(w2).name2;
            f1:=savef1;
            w1:=(w1).internal+b.reldump;
            w2:=first+bufferrel;
            copy(.w3.,w0:=16,w1,w2);
            (w2).cause:=w0:=8;
            (w2).exep:=w0:=0;
            w0:=savedic;
            savedic:=w1:=(w2).instr;
            (w2).instr:=w0;
            testout(.w3.,w0:=16,w1:=w2,w2:=1);
            w3:=address(childname);
            monitor(62);  comment modify process;
            (w1).instr:=w0:=savedic;
            ioop:=w0:=5;
            w1:=address(ioop);
            w3:=address(b.swname);
            monitor(16);  comment send message;
            w1:=b.lastuser;
            monitor(18);  comment wait answer;
            f1:=savef1;
            (w1).state:=w0:=0;
            link(.w3.,w1,w2:=address(b.activqfst));
            goto exit;
          end;
        end;
        comment kill because of no reaction after break;
        startstop(.w3.,w0:=0,w1);
        clean(.w3.,w1);
exit:
        w3:= address(b.usercat);
        monitor(10); ! release usercat !
        f1:=savef1;
        f3:=savef3;
      end;
    end;     !  break  !
\f


comment                continue mcl

An appropiate text is send mcl indicating the reason of exit from the 
sos operating system;


    body of continuemcl
    begin
      incode
        double savef1, savef3;

        text (14) cmt00 := "command unkn. ",
                  cmt01 := "ready         ",
                  cmt02 := "syntax        ",
                  cmt03 := "ident illegal ",
                  cmt04 := "no room       ",
                  cmt05 := "claims exeeded",
                  cmt06 := "creation error",
                  cmt07 := "forbidden     ",
                  cmt08 := "terminal busy ",
                  cmt09 := "terminal conn.",
                  cmt10 := "no jobfile    ",
                  cmt11 := "connected     ",
                  cmt12 := "terminal disc.",
                  cmt13 := "bad password  ",
                  cmt14 := "not connected ",
                  cmt15 := "process unkn. ",
                  cmt16 := "no disconnect ",
                  cmt17 := "call not ok   ",
                  cmt18 := "include not ok",
                  cmt19 := "              ", ! enrolled !
                  cmt20 := "break         ",
                  cmt21 := "finis         ",
                  cmt22 := "user kill     ",
                  cmt23 := "operator kill ",
                  cmt24 := "time exeeded  ",
                  cmt25 := "terminal error",
                  cmt26 := "user break    ",
                  cmt27 := "operator break",
                  cmt28 := "user conflict ",
                  cmt29 := "system locked ",
                  cmt30 := "usercat resrvd";

        word mcl_mess0  :=  524288 , ! continue mcl !
             mcl_mess2,                  ! local id     !
             mcl_mess4  :=  49167,! length of op, text !
             mcl_mess6,                  ! reason text  !
             m8,m10,m12,m14;             ! reason text continued !

      begin
        savef1:= f1;
        savef3:= f3;
        w0*10; ! offset to text depending on reson (w0) !
        w1:= address (cmt00); w1+w0;
        copy (.w3., w0:= 10, w1, w2:= address (mcl_mess6));
        if w0:= mcl_mess6 <> 2105376 then
        begin
          f1:= savef1;
          w2:= (w1).peripheral;
          if w2 < 0 then -(w2); w2 + 2;
          w3:= address (b.procname);
          (w3).name1:= f1:= (w2).name1;
          (w3).name2:= f1:= (w2).name2;
          w1:= address (mcl_mess0);
          monitor (16);
          f1:= savef1;
          (w1).messsend:= w2;
          testout (.w3., w0:= 6, w1:= address (mcl_mess0), w2:= 2);
          testout (.w3., w0:=10, w1+6, w2:= 0);
        end;
        f1:= savef1;
        f3:= savef3;
      end;
    end; ! continue mcl !


\f





comment                    parentmess

the use of devices (not accessible directly from the user-processes)
and the control of the processes themselves is partially based on parent
messages. this procedure takes the actions corresponding to the possible kinds
of parent messages  -  these possible kinds are:

          break
          finis    terminates the current processing and removes the process
          mount

;

    body of parentmessage
    begin
      label unknown,mounted,mountmess;
        record cont_ans ( word stat,l_id,perif);
      incode
        double w01,w23;
        text(11) string1;
        ref firstdev:=74,lastdev:=76;
        byte temop,temmode;
        word locid,dum1,dum2;
        text(14) poolname;
        array (1:8) answ of word;
        word zero:=0;
        byte emptyop:=16,emptymode:=0;
        text(20) emptytxt:="system empty";
      begin
        w01:=f1; w23:=f3;
        w0:=0;
        b.timermess:=w0;
        startstop(.w3.,w0:=0,w1);
        if w0:=(w2).operation=2 then comment finismessage;
        begin
          send(.w3.,w0:=1,w1,w2:=0);
          if w0:=(w1).state2<=0 then
          begin
            (w1).intervent:=w0:=2;
            clean(.w3.,w1);
          end
          else begin
!test 49;
            outtext(.w3.,w0:=8'70,w1,w2:=(w1).intervent+19);
                ! removed after  break / finis / user kill / opt.kill /
                                 time exc. / term.error / user break / opt.break !
            copy(.w3.,w0:=8,w1:=(w1).internal+2,w2:=address(b.procname));
            w1:=(w1:=b.userentry).internal+76;
            f1:=(w1).double;
            w3:=address(zero);
            monitor(72);  ! set sos catalog base to stdbase of child !
!test 440;
            w3:=address(b.t_mdul);
            monitor(64);  ! remove pseudo process !
            w3:=address(b.p_mdul);
            monitor(64);  ! remove pseudo process !
!test 441;
            w3:=address(zero);
            f1:=b.startbase;
            monitor(72);  ! reset sos own cat base !
            w1:=b.ownproc+26;
            b.freebufs:=w0:=b.freebufs-(w1).byte;
            w3:=address(b.procname);
            monitor(64);  comment remove internal process;
!test 110;
            b.freebufs:=w0:=b.freebufs+(w1).byte;
            copy(.w3.,w0:=6,w1:=address(b.procname),w2:=address(poolname)+2);
            w0:= 0;
            b.baseevent:= w0;
            copy(.w3.,w0:=2,w1:=b.ownproc+2,w2:=address(poolname));

            temop:=w0:=102;  ! remove link (soft) !
            locid:=w1:=0;
            w3:=address(poolname);
            w1:=address(temop);
            monitor(16);  ! send message !
            answ(w1:=1);
            monitor(18);  ! wait answer !
            
            temop:=w0:=92;  ! remove pool !
            w3:=address(b.t_mdul);
            w1:=address(temop);
            monitor(16);  ! send message !
            answ(w1:=1);
            monitor(18);  ! wait answer !

            copy(.w3.,w0:=2,w1:=address(b.t_mdul),w2:=address(poolname));
            w1:=address(temop);
            w3:=address(b.t_mdul);
            monitor(16);  ! send message !
            answ(w1:=1);
            monitor(18);  ! wait answer !
            w1:=b.userentry;
            link(.w3.,w1,w2:=address(b.waitqfst));
            w0:=0;
            (w1).peripheral:=w0;
            (w1).internal:=w0;
            (w1).messsend:=w0;
            (w1).messgot:=w0;
            (w1).intervent:=w0;
            if w0:=b.sysstate = 1 then
            begin
              w1:=b.lastuser;
              w0:=0;
              while w1-!length(userentry) >= b.firstuser do
              begin
                if w3:=(w1).internal > 0 then 
                if w3:=(w3).word = 0 then w0+1;
              end;
              if w0 = 0 then opmess(.w3.,w1:=address(emptyop),w2:=b.ownproc);
            end;
          end;
        end else
        if w0=4 then comment break message;
        begin
          send(.w3.,w0:=1,w1,w2:=0);
          if w0:=(w1).intervent = -1 then (w1).intervent:=w0:=1;
          if w0 = 0 then (w1).intervent:=w0:=1;
          clean(.w3.,w1);
        end else
        if w0 = 14 then comment mount message;
        begin
mountmess:
          copy(.w3.,w0:=8,w1:=w2+16,w2:=address(string1));
          w3:=address(string1);
          monitor(4);  ! get process description !
          if w0 <> 0 then
          begin
            w1:=word(firstdev);
            while w1+2 <= word(lastdev) do
            begin
              if w0 = (w1).word then
              begin
                w3:=address(b.procname);
                w1-word(firstdev) lshift -1;
                monitor(12);  ! include user !
                if w0 = 0 then
                begin
                  f1:=w01;
                  (w1).state:=w0:=0;
                  link(.w3.,w1,w2:=address(b.activqfst));
                  send(.w3.,w0:=1,w1,w2:=0);
                  goto mounted;
                end;
              end;
            end;
          end;
          f1:=w01;
          f3:=w23;
          goto unknown;
mounted:
        end else
        if w0 = 32 then goto mountmess
        else
        begin comment parent message unknown;
unknown:
          (w1).state:=w0:=0;
          w2:=(w1).internal;
          opmess(.w3.,w1:=b.message+8,w2);
          if w0:=(w1).word onemask 1 then w2:=address(b.waitqfst)
                                     else w2:=address(b.activqfst);
          f1:=w01;
          link(.w3.,w1,w2);
          send(.w3.,w0:=1,w1,w2:=0);
        end;
        w3:=address(zero);
        f1:=b.startbase;
        monitor(72);  ! rset sos own catalog base !
        f1:=w01; f3:=w23;
      end;
    end;     !  parentmessage  !
\f





comment                   clean

;


    body of clean
    begin
      incode
        double savef1, savef3;
        double corelimits;
        byte buffers, areas;
        byte internals:=0, fncmask:=1792;
        byte protreg, protkey;
        double maxbase, stdbase;
      begin
        savef1:=f1; savef3:=f3;
        if w0:=(w1).messgot > 10 then
        begin
          empty_answer(.w3.,w0:=1,w1,w2:=0);
        end;
        copy(.w3.,w0:=8,w1:=(w1).internal+2,w2:=address(b.procname));
        w2 := b.fstcore;
        w3 := b.topcore - b.fstcore;
        w3 lshift -11 lshift 11; ! make size a 2K multiplum !
        w3 + b.fstcore;
        corelimits:=f3;
        protreg:=w3:=b.childpr;
        protkey:=w3:=b.childpk;
        w2:= b.ownproc;
        buffers:= -(w3:=(w1:=w2+26).byte);
        areas:= -(w3:=(w1:=w2+27).byte);
        f1:= savef1;
        w0:= (w1).internal;
        maxbase:=f3:=(w1:=w0+72).double;
        stdbase:=f3:=(w1:=w0+76).double;
        w3:=address(b.procname);
        monitor(64); comment remove internal;
!test 100;
        w2:= b.ownproc;
        buffers:= w0:= buffers+(w1:=w2+26).byte;
        areas:= w0:= areas+(w1:=w2+27).byte;
        w1:=address(corelimits);
        monitor(56); comment create internal;
!test 102;
        f1:=savef1;
        monitor(4); comment lookup process;
        (w1).internal:=w0;
        (w1).state:=w0:=3;
        (w1).state2:=w0:=1;
        (w1).prio:=w0:=0;
        (w1).class:=w0;
        (w1).messsend:=w0;
        (w1).messgot:=w0;
        link(.w3.,w1,w2:=address(b.activqfst));
        f1:=savef1;
        f3:=savef3;
      end;
    end;     !  clean  !
\f





comment               compare

;


    body of compare
    begin
      incode
        word savew1;
        double savef3;
      begin
        savew1:=w1; savef3:=f3;
        w3:=w1+w0;
        w0:=0;
        while w1<w3 do
        begin
          w0:=(w1).word;
          w0-(w2).word;
          w1+2;
          w2+2;
          if w0<>0 then w1:=w3;
        end;
        w1:=savew1;
        f3:=savef3;
      end;
    end;     !  compare  !
\f





comment                 nextchar

;


    body of nextchar
    begin
      label dummy1;
      begin
        if w1=0 then
          if w2=(w3).stp then w1:=10 ashift 16     ! simulate 'nl' at end of buffer !
          else begin
            w1:=(w2).word;
            w2+2;
          end;
        w0:=0;
        f1 lshift 8;
        if w0=13 then w0:= 10; ! convert <cr> to <nl> to avoid  !
                               ! syntax error reading in mode 2 !
      end;
    end;

end.
▶EOF◀