<< LINES .001/.009 ARE RESERVED FOR SYSTEMS INTEGRATION>>               00000001
$page                                                                   00200010
<<                                                                      00200020
Internal Design Notes                                                   00200030
---------------------                                                   00200040
                                                                        00200050
Accessing the Port Data Segment                                         00200060
                                                                        00200070
In Basic IPC, there are many independent processes accessing            00200080
the Port Data Segment.  If while accessing this data segment,           00200090
a process' quantum runs out or if a port timer expires, another         00200100
process can come in and change the data segment.  If not managed        00200110
carefully, the Port Data Segment could be easily corrupted.             00200120
There are 3 types of collisions that need close attention.              00200130
                                                                        00200140
  1.) Creating and releasing the Port Data Segment.  Two con-           00200150
  current FCPORTOPENs should not both try to create it, nor             00200160
  should two concurrent FCPORTCLOSEs both try to release it.            00200170
  Also, once an FCPORTOPEN has determined that the Port Data            00200180
  Segment exists, an FCPORTCLOSE should not release it.                 00200190
                                                                        00200200
  2.) Two normal processes accessing the same block.  While one         00200210
  process is getting a free block, another should not attempt           00200220
  to get the same block.  The same is true for linking and de-          00200230
  linking blocks from any list, or altering a port or the global        00200240
  area.                                                                 00200250
                                                                        00200260
  3.) A normal process and the timer interrupt handler both             00200270
  accessing the same message or timer block at the same time.           00200280
  If an FCPORTRECEIVE is done just as the timer for that message        00200290
  expires (causing an interrupt), only one of them should access        00200300
  the message at a time.  This is also true of very short timeouts,     00200310
  where the timer may expire before FCPORTSEND can get the message      00200320
  completely linked in.                                                 00200330
                                                                        00200340
All of these cases are handled with "pseudodisable", which stops        00200350
the Dispather from starting other processes until a "pseudoenable"      00200360
is done.                                                                00200370
                                                                        00200380
NOTE: Basic IPC calls the following special procedures:                 00200390
         WAIT         GETDATASEG       QUEUEONSEGMENT                   00200400
         IMPEDE       ALTDSEGSIZE                                       00200410
All these procedures yeild the processor.  They should NOT be called    00200420
when a "pseudodisable" is preventing other processes from running.      00200430
                                                                        00200440
>>   <<"Accessing the Port Data Segment" is part of FIX # ==>> <<02548>>00200450
  3 :IM: Subtype: Pin of the port manager              : 3              00366000
  4 :  Soft interrupt parameter one (File Number)      : 4              00370000
  6 :  Spare                                           : 6              00378000
                                                                        00416100
    IM      Interrupt Mode                                              00416200
            0 - Priv and User mode code can be soft interrupted         00416300
            1 - Only user mode code can be soft interrupted             00416400
                                                                        00416500
    Subtype File System Interrupt Subtype                               00416600
            1 - Message file soft interrupts                            00416700
  Psoft'subtype                   = port(3).(1:3)       #,     <<06737>>00442000
  Psoft'int'mode                  = port(3).(0:1)       #,     <<06110>>00442111
  Pport'pin                       = port(3).(4:12)      #,     <<06737>>00444000
  Pspare                          = port(6)             #,     <<02114>>00450000
  6 :  Value of TIMER when this timeout expires        : 6              00676000
  DSTB                            = 2;                         <<06737>>00878000
$edit void=00882000                                            <<06737>>00880000
$page                                                          <<06737>>00882000
$include inclpcb5                                              <<06737>>00883000
$page                                                          <<06737>>00884000
  PCB=SysPcbIndex;                                             <<06737>>00896000
$edit void=00916000                                            <<06737>>00898000
  pseudodisable                   = assemble(psdb)   #,        <<06737>>01000000
PCBXDBvalue                       = push(dl); tos:=tos-ps0(-1);<<06737>>01001000
                                    tos:=ps0(1); delb#;        <<06737>>01002000
double  seg'num;                                               <<06737>>01064000
procedure MMSTAT'(entrie,p0,p1,p2,p3,p4,p5);                   <<07357>>01158000
value entrie,p0,p1,p2,p3,p4,p5;                                <<07357>>01160000
integer entrie,p0,p1,p2,p3,p4,p5;                              <<07357>>01162000
                                                               <<02114>>01164100
procedure STARTIMEOUT(MQE,port,timeout);                       <<02114>>01164200
value MQE,port,timeout;                                        <<02114>>01164300
integer pointer MQE,port;                                      <<02114>>01164400
integer timeout;                                               <<02114>>01164500
option privileged,internal,forward;                            <<02114>>01164600
                                                                        01170100
<<Function                                                   >><<02278>>01170200
<<Provides an STT entry for the HELP Debugging Facility.     >><<02278>>01170300
                                                                        01170400
option privileged, uncallable;                                 <<02278>>01170500
                                                                        01170600
  PCBpt:=Gimpede'head*PCBSize;                                 <<06737>>01294000
  if (Gimpede'head:=SPCBnimpPin) = 0 then                      <<06737>>01296000
  SPCBnimpPin:=0;                                              <<06737>>01300000
<<This procedure MUST NOT be called when pseudodisabled.>>     <<02548>>01329000
<<ALTDSEGSIZE must not be called when pseudodisabled.>>        <<02548>>01367000
pseudodisable;                                                 <<02548>>01377000
pseudoenable;                                                  <<02548>>01395000
  MMSTAT'(MMexpand'seg,portDST,num'new'blocks,                 <<07357>>01398000
         Gtotal'blocks,0,0,0);                                 <<07357>>01399000
<<This procedure should not be called when pseudodisabled.>>   <<02548>>01411000
  PcbPT,                                                       <<06737>>01497000
  <<This subroutine must be protected with pseudodisables.>>   <<02061>>01509000
$EDIT VOID=01528000                                            <<02061>>01528000
$EDIT VOID=01546000                                            <<02061>>01546000
    <<The "Gnum'free'blocks = -1" check prevents a second    >><<02548>>01550100
    <<GETFREEBLOCK from coming in and expanding the Port Data>><<02548>>01550200
    <<Seg while this one is pseudoenabled in EXPANDPORTSEG.  >><<02548>>01550300
    <<The second process' GETFREEBLOCK will decrement to -2, >><<02548>>01550400
    <<and IMPEDE rather than EXPANDPORTSEG.                  >><<02548>>01550500
    pseudodisable;                                             <<02061>>01557000
    PcbPt:=Gimpede'tail*PcbSize;                               <<02061>>01565000
    pin:=CurPrc/PcbSize;                                       <<06737>>01566000
      SPcbnimpPin:=Pin                                         <<06737>>01570000
    IMPEDE(0);    <<IMPEDE will enable pseudo interrupts.>>    <<02061>>01578000
    pseudodisable;                                             <<02061>>01579000
pseudoenable;                                                  <<02061>>01589000
<<This procedure should not be called when pseudodisabled.  >> <<02548>>01599000
<<It does not need to be protected because no other process >> <<02548>>01600000
<<can access the new seg until its DST number is put in     >> <<02548>>01601000
<<SYSGLOB (done elsewhere).                                 >> <<02548>>01601100
                                                               <<02548>>01601200
  PcbPt,                                                       <<06737>>01731000
PcbPt:=CurPrc;                                                 <<06737>>01739000
DST:=SPcbStkDst;                                               <<06737>>01740000
if port'manager'only and (Pport'pin<>0) and                    <<06737>>01754000
  (CurPrc/PcbSize<>Pport'pin) then                             <<06737>>01756000
                                                               <<02061>>01771000
<<Calls to QUICKPREPORT must eventually be followed be calls >><<02061>>01772000
<<to QUICKUNPREPORT.                                         >><<02061>>01773000
                                                               <<02061>>01774000
<<Input>>                                                      <<02061>>01775000
  QUEUEONSEGMENT(double(portDST));                             <<06737>>01820000
if (Pport'pin <> 0) and                                        <<06737>>01846000
    (CurPrc/PcbSize <> Pport'pin) then                         <<06737>>01847000
                                                               <<02061>>01861000
<<Calls to QUICKUNPREPORT must be preceeded with calls to >>   <<02061>>01862000
<<QUICKPREPORT.                                           >>   <<02061>>01863000
                                                               <<02061>>01864000
<<Input>>                                                      <<02061>>01865000
integer procedure QUEUETOPORT(port,mqe,flags,timeout);         <<02114>>01902000
value port,mqe,flags,timeout;                                  <<02114>>01904000
  integer                                                      <<02114>>01941000
    timeout;            <<In seconds, 0 if not used>>          <<02114>>01942000
                                                               <<02114>>01943000
integer Mode'subtype;                                          <<06110>>01983000
  Mode'subtype:=Psoft'subtype;                                 <<06110>>02014100
  Mode'subtype.(0:1):=Psoft'int'mode;                          <<06110>>02014200
  CAUSESOFTINT(Pport'pin,s4,Mode'subtype,Psoft'int'plabel,     <<06110>>02018000
               2,s3);                                          <<06110>>02018500
if timeout <> 0 then                                           <<02114>>02070000
  STARTIMEOUT(MQE,port,timeout);                               <<02114>>02072000
<<If this is the only message in the port, and the   >>        <<02114>>02076000
<<port was enabled, then wake up the manager process.>>        <<02114>>02078000
  PCBpointer:=PcbSize*Pport'pin;                               <<06737>>02084000
  Penable:=false;      <<Disabled after each waking message.>> <<02114>>02088000
  if wake'process then   <<Check message's wake parameter.>>   <<02114>>02090000
pseudoenable;                                                  <<02114>>02139000
integer Mode'subtype;                                          <<06110>>02177000
  Mode'subtype:=Psoft'subtype;                                 <<06110>>02178100
  Mode'subtype.(0:1):=Psoft'int'mode;                          <<06110>>02178200
  CAUSESOFTINT(0,int'type,Mode'subtype,Psoft'int'plabel,       <<06110>>02186000
               2,0);                                           <<06110>>02187000
procedure STARTIMEOUT(MQE,port,timeout);                       <<02114>>02194000
value MQE,port,timeout;                                        <<02114>>02196000
<<Caller needs to protect me with a pseudodisable.>>           <<02114>>02203000
    timeout;            <<Duration of the timeout, in seconds>><<02114>>02216000
                                                               <<02114>>02218000
@TLE:=MTLEaddress;                                             <<02114>>02292000
                                                               <<02114>>02302000
end;  <<STARTIMEOUT>>                                          <<02114>>02366000
                                                               <<02114>>02368000
pseudodisable;                                                 <<02114>>02451000
  MTLEaddress:=0;                                              <<02114>>02458000
  PUTFREEBLOCK(TLE);                                           <<02114>>02500000
  end                                                          <<02114>>02502000
else                                                           <<02114>>02504000
  pseudoenable;                                                <<02114>>02506000
                          8          7>>                       <<02061>>02546000
                                                               <<02061>>02593000
<<Calls to this subroutine must be protected by pseudodisables.<<02061>>02594000
                                                               <<02061>>02595000
    MMSTAT'(MMtimeout'exp,port'num,@mqe,Mreturn'port,0,0,0);   <<07357>>02610000
    while sp0 <> @MQE and s0 <> pTailmqe do s0:=sp0;           <<m7679>>02642000
    if sp0 <> @mqe then goto NOMQE; <<mqe already deleted by>> <<m7679>>02643100
                                    <<another process       >> <<m7679>>02643200
    QUEUETOPORT(return'port,MQE,queue'to'tail,0);              <<02114>>02662000
  NOMQE:                                                       <<m7679>>02671000
  port'number:=port'number+1;   <<port DST index, usually 1.>> <<02114>>02772000
    Pseudodisable;                                             <<02114>>02951000
      if access'restrict then CurPrc/PcbSize else 0;           <<06737>>02958000
    Pseudoenable;                                              <<02114>>02971000
  MMSTAT'(MMopen,port'number,portDST,flags,0,0,0);             <<07357>>02986000
@dummy := 0;                                                   <<02114>>03063000
    MMSTAT'(MMclose,port'number,portDSTnumber,                 <<07357>>03100000
           Gnum'open'ports-1,0,0,0);                           <<07357>>03101000
integer pointer                                                <<02114>>03249000
  TLE;                                                         <<02114>>03250000
data'structure;                                                <<02114>>03251000
if not timeout'spec then timeout:=0;                           <<02114>>03257000
if (@MQE:=GETFREEBLOCK(impede'me)) = 0 then <<Block for msg.>> <<02114>>03259000
  condition'code:=ccl                       <<No space left.>> <<02114>>03260000
else                                                           <<02114>>03261000
  if timeout = 0 then                     <<No timer needed.>> <<02114>>03262000
    condition'code:=cce                                        <<02114>>03263000
  else                          <<Get a block for the timer.>> <<02114>>03264000
    if (@TLE:=GETFREEBLOCK(impede'me)) = 0 then                <<02114>>03265000
      begin                                                    <<02114>>03266000
      PUTFREEBLOCK(MQE);         <<Failed, return msg block.>> <<02114>>03267000
      condition'code:=ccl;                                     <<02114>>03268000
      end                                                      <<02114>>03269000
    else                                                       <<02114>>03270000
      condition'code:=cce;                                     <<02114>>03271000
if condition'code = cce then  <<Succeeded in getting blocks.>> <<02114>>03272000
  begin                                                        <<02114>>03273000
  <<Initialize the message>>                                   <<02114>>03274000
  Mreturn'port:=if return'port'spec then return'port else 0;   <<02114>>03275000
                                                               <<02114>>03291000
  if timeout <> 0 then                                         <<02114>>03292000
    MtLEaddress:=@TLE                                          <<02114>>03294000
  FCPORTSEND:=QUEUETOPORT(port,MQE,flags,timeout);             <<02114>>03300000
                                                               <<02114>>03301000
    MMSTAT'(MMsend,port'number,@MQE+queue'type,                <<07357>>03304000
           return'port,0,0,0);                                 <<07357>>03305000
QUICKPREPPORT(port'number,port);     <<Does a pseudodisable.>> <<02061>>03350000
  MMSTAT'(MMchange'state,port'number,MMdisable'port,           <<07357>>03358000
         PheadMQE,0,0,0);                                      <<07357>>03359000
QUICKUNPREPPORT(port'number,port);   <<Does a pseudoenable.>>  <<02061>>03360000
QUICKPREPPORT(port'number,port);     <<Does a pseudodisable.>> <<02061>>03410000
  MMSTAT'(MMchange'state,port'number,MMenable'port,            <<07357>>03440000
         PheadMQE,0,0,0);                                      <<07357>>03441000
QUICKUNPREPPORT(port'number,port);   <<Does a pseudoenable.>>  <<02061>>03442000
  <<This subroutine must be called when pseudodisabled.>>      <<02548>>03571000
  end;  <<EMPTYPORT>>                                          <<02548>>03581000
                                                               <<02548>>03582000
pseudodisable;                                                 <<02548>>03594100
                                                               <<T9343>>03594200
    pseudoenable;                                              <<02548>>03611000
    pseudodisable;                                             <<02548>>03613000
$EDIT VOID=03620500                                                     03620000
$EDIT VOID=03665000                                                     03665000
    MMSTAT'(MMreceive'completion,port'number,@MQE+iflags,      <<07357>>03670000
           return'port,0,0,0);                                 <<07357>>03671000
$EDIT VOID=03671100                                            <<07357>>03671100
$EDIT VOID=03681000                                                     03681000
  end;                                                         <<02548>>03689000
pseudoenable;                                                  <<02548>>03690000
  no'interrupt      = 0,                                       <<02062>>03858000
  pseudodisable;                                               <<02548>>03895000
  Pwake'type:=interrupt'type;                                  <<02062>>03896000
$EDIT VOID=03902000                                                     03898000
  if interrupt'type <> no'interrupt then                       <<02062>>03902000
    begin                                                      <<02062>>03904000
    Psoft'subtype:=soft'subtype.(1:15);                        <<06110>>03908000
    Psoft'int'mode:=soft'subtype.(0:1);                        <<06110>>03909000
  pseudoenable;                                                <<02548>>03913000
  MMSTAT'(MMabort,port'number,parameter'value,                 <<07357>>04046000
         return'port,0,0,0);                                   <<07357>>04047000
                                                                        04076100
option privileged, uncallable;                                 <<02278>>04076200
