home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / PASCAL / MULTI12 / MULTI.PAS < prev    next >
Pascal/Delphi Source File  |  1989-06-04  |  15KB  |  603 lines

  1. Unit Multi;
  2.  
  3. {
  4.        MULTI-PROGRAMMING KERNEL FOR TURBO PASCAL 5.0, VERSION 1.2
  5.        ==========================================================
  6.  
  7.       Copyright 1989 Anders Wolf Pedersen. You may use this product on a
  8.     shareware basis, i.e. if you find it usefull you should send
  9.     Dkr 150, US$ 20 or what you deem appropriate to
  10.  
  11.                      Anders Wolf Pedersen
  12.                      Vejlegade 9,5.th
  13.                      DK 2100 Koebenhavn
  14.                      Denmark
  15.  
  16.     Small contributions will be accepted with gratitude, large with greed.
  17.     If you use this product and do not make a contribution, bad luck will
  18.     haunt you: spurious bugs will appear in your programs, your disks will
  19.     crash, your computer will die in a puff of blue smoke, your dog will
  20.     bite you, and your life will in general be miserable.
  21.       You may distribute this product freely on the conditions that you
  22.     a) include this message, b) do not charge anything for it, and c) do not
  23.     modify it in any way.
  24.       I can not accept responsability for any problems you may encounter
  25.     as a result of using this product, nor can I guarantie that it will
  26.     perform as claimed. I have, however, checked it as carefully as I
  27.     possibly can and I hope that you will find it usefull. Your use of the
  28.     program constitutes an accept of all responsability of the consequenses.
  29.       This file should be accompanied by a file MULTI.DOC which contains
  30.     documentation for the product. If you have any comments to the unit
  31.     or suggestions for improvement, I will be glad to hear from you. I can
  32.     be reached on bitnet address ANDERSWP@DKNBI51 or FIDO-net address
  33.     2:231/47 Anders Pedersen.
  34.       However, I can not assist you in debugging your multiprograms or
  35.     otherwise give you any service; you are on your own. Good luck.
  36.  
  37. }
  38.  
  39.  
  40. Interface
  41.  
  42. Uses  Dos;
  43.  
  44.  
  45. Const TimerIntNo =  8;                 { Interruptno. for timer }
  46.       SavedInt   = 78;                 { Int.no. for rerouting timer }
  47.       Interleave =  1;                 { Interleave factor for timeslicing }
  48.  
  49. Type  QueueType         = ^ProcDescriptor;
  50.       Process           = QueueType;
  51.  
  52.       ProcDescriptor    = Record
  53.                                Next      : QueueType;
  54.                             Inqueue   : ^QueueType;
  55.                      Sseg,
  56.                             Sp,
  57.                             ProcStack : Word;
  58.                             Ptr       : Pointer;
  59.                           End;
  60.  
  61.  
  62.       Semaphore         = Record
  63.                             Queue   : QueueType;
  64.                             Counter : Integer;
  65.                           End;
  66.  
  67.       Msgtype           = Pointer;
  68.  
  69.       MsgSemaphore      = Record
  70.                             ProcQueue,
  71.                             MsgQueue  : QueueType;
  72.                           End;
  73.  
  74.       GetMode           = (Stay, Return);
  75.  
  76.       SwitchMode        = (Timer, NoTimer);
  77.  
  78.  
  79. Procedure Wait(Var Sem: Semaphore);
  80.  
  81. Procedure Signal(Var Sem: Semaphore);
  82.  
  83. Procedure InitSem(Var Sem : Semaphore);
  84.  
  85. Procedure GetMsg(Var MsgSem: MsgSemaphore; Var Msg : Msgtype;
  86.                   Mode: Getmode);
  87.  
  88. Procedure PutMsg(Var MsgSem : MsgSemaphore; Msg : Msgtype );
  89.  
  90. Procedure InitMsgSem(Var MsgSem : MsgSemaphore);
  91.  
  92. Procedure CreateProcess(body: Pointer; StackSize: Word;
  93.                         Var Proc: QueueType);
  94.  
  95. Procedure Kill(Proc: Process);
  96.  
  97. Procedure StopMulti;
  98.  
  99. Procedure StartMulti(Mode : SwitchMode);
  100.  
  101. Procedure Die;
  102.  
  103. Function  NoProcesses : Integer;
  104.  
  105.  
  106. { ----------------------------------------------------------------------- }
  107.  
  108.  
  109. Implementation
  110.  
  111. Var Tick,                              { Counts elapsed clock ticks }
  112.     NoProc       : Integer;            { No. of processes in multiprogram }
  113.     ReadyQueue,                        { Queue for processes ready to run }
  114.     CurrentProc,                       { Pointer to currently running Proc }
  115.     Dead,                              { Queue of Dead processes }
  116.     Main         : QueueType;          { Pointer to desc. for Main program }
  117.     Regs         : Registers;          { used for sofware interrupt }
  118.     MainProg     : Process;            { Proc.descriptor for Main program }
  119.  
  120.  
  121. { ----------------------------------------------------------------------- }
  122.  
  123.  
  124. Procedure Cli; Inline($FA);      { Disable interrupts }
  125.  
  126. Procedure Sti; Inline($FB);      { Enable interrupts }
  127.  
  128.  
  129. { ----------------------------------------------------------------------- }
  130.  
  131.  
  132. Procedure Enqueue(Var Proc,Queue: QueueType);
  133.  
  134. { Inserts ProcDescriptor pointed to by Proc in Queue }
  135.  
  136.    Begin
  137.      If Queue=Nil
  138.      Then Begin
  139.             Queue:=Proc;
  140.             Proc^.Next:=Proc;
  141.           End
  142.      Else Begin
  143.         Proc^.Next:=Queue^.Next;
  144.         Queue^.Next:=Proc;
  145.             Queue:=Proc;
  146.           End;
  147.      Proc^.inqueue:=@Queue;
  148.    End; { Enqueue }
  149.  
  150.  
  151. { ----------------------------------------------------------------------- }
  152.  
  153.  
  154. Procedure Dequeue(Var Proc,Queue : QueueType);
  155.  
  156. { Retreives a ProcDescriptor from Queue and returns Pointer to it in Proc. }
  157.  
  158.    Begin
  159.      Proc:=Queue^.Next;
  160.      If Queue=Proc
  161.      Then Queue:=Nil
  162.      Else Queue^.Next:=Proc^.Next;
  163.    End; { Dequeue }
  164.  
  165.  
  166. { ----------------------------------------------------------------------- }
  167.  
  168.  
  169. {$F+}
  170.  
  171. Procedure SwitchContext(OldProc,NewProc: QueueType);
  172.  
  173. {$F-}
  174.  
  175. { Switches context from OldProc to NewProc - must compiled as FAR call }
  176.  
  177. {$IFDEF VER40 }
  178.  
  179.    Var Ofs,Seg : Word;
  180.        Proc    : Process;
  181.  
  182. {$ELSE}
  183.  
  184.    Var Seg,Ofs : Word;
  185.        Proc    : Process;
  186.  
  187. {$ENDIF}
  188.  
  189.    Begin
  190.      { Save current bp,Sseg:Sp }
  191.      Inline($55);                           { Push bp }
  192.      OldProc^.Sp:=Sptr;
  193.      OldProc^.Sseg:=Sseg;
  194.  
  195.      { Remove Dead processes if there are any }
  196.      While Dead<>Nil Do
  197.      Begin
  198.        Dequeue(Proc,Dead);
  199.        Dispose(Proc);
  200.      End;
  201.  
  202.      { Get New values of Sseg:Sp for NewProc via local variables Seg,Ofs }
  203.      Seg:=NewProc^.Sseg;
  204.      Ofs:=NewProc^.Sp;
  205.  
  206.      Inline($8B/$46/$FE);                   { Mov  ax,ss:[bp-2] }
  207.      Inline($8B/$5E/$FC);                   { Mov  bx,ss:[bp-4] }
  208.      Inline($8E/$D0);                       { Mov  ss,ax }
  209.      Inline($8B/$E3);                       { Mov  Sp,bx }
  210.  
  211.      Inline($5D);                           { Pop  bp }
  212.  
  213.    End; { SwitchContext }
  214.  
  215.  
  216. { ----------------------------------------------------------------------- }
  217.  
  218.  
  219. Procedure Wakeup(Var Queue: QueueType);
  220.  
  221.    Var OldProc,NewProc : QueueType;
  222.  
  223.    Begin
  224.      While Queue=Nil Do           { If no Processes, Wait for something to }
  225.      Begin                        { happen }
  226.        Sti;
  227.        Cli;
  228.      End;
  229.  
  230.      Dequeue(OldProc,CurrentProc);
  231.      Enqueue(OldProc,ReadyQueue);
  232.  
  233.      Dequeue(NewProc,Queue);
  234.      Enqueue(NewProc,CurrentProc);
  235.  
  236.      SwitchContext(OldProc,CurrentProc);
  237.    End;
  238.  
  239.  
  240. { ----------------------------------------------------------------------- }
  241.  
  242.  
  243. Procedure Sleep(Var Queue: QueueType);
  244.  
  245.    Var OldProc,NewProc : QueueType;
  246.  
  247.    Begin
  248.      Dequeue(OldProc,CurrentProc);
  249.      Enqueue(OldProc,Queue);
  250.  
  251.      While ReadyQueue=Nil Do      { If no Processes, Wait for something to }
  252.      Begin                        { happen }
  253.        Sti;
  254.        Cli;
  255.      End;
  256.  
  257.      Dequeue(NewProc,ReadyQueue);
  258.      Enqueue(NewProc,CurrentProc);
  259.  
  260.      SwitchContext(OldProc,CurrentProc);
  261.    End;
  262.  
  263.  
  264. { ----------------------------------------------------------------------- }
  265.  
  266.  
  267. Procedure Wait(Var Sem: Semaphore);
  268.  
  269. { Performs WAIT-operation on Semaphore Sem }
  270.  
  271.    Begin
  272.      Cli;
  273.  
  274.      With Sem Do
  275.      Begin
  276.        If Counter=0 Then Sleep(Queue);
  277.        Counter:=Counter-1;
  278.      End;
  279.  
  280.      Sti;
  281.    End; { Wait }
  282.  
  283.  
  284. { ----------------------------------------------------------------------- }
  285.  
  286.  
  287. Procedure Signal(Var Sem: Semaphore);
  288.  
  289. { Performs SIGNAL operation on Semaphore Sem }
  290.  
  291.    Begin
  292.      Cli;
  293.  
  294.      With Sem Do
  295.      Begin
  296.        Counter:=Counter+1;
  297.        If Queue<>Nil Then Wakeup(Queue)
  298.                      Else Sleep(ReadyQueue);
  299.      End;
  300.  
  301.      Sti;
  302.    End; { signal }
  303.  
  304.  
  305. { ----------------------------------------------------------------------- }
  306.  
  307.  
  308. Procedure InitSem(Var Sem : Semaphore);
  309.  
  310. { Initializes Semaphore Sem. MUST be done BEFORE Semaphore is used }
  311.  
  312.    Begin
  313.      Sem.Queue:=Nil;
  314.      Sem.Counter:=0;
  315.    End; { InitSem }
  316.  
  317.  
  318. { ----------------------------------------------------------------------- }
  319.  
  320.  
  321. Procedure GetMsg(Var MsgSem: MsgSemaphore; Var Msg : Msgtype;
  322.                  Mode: Getmode);
  323.  
  324. { Gets a message from message Semaphore MSGSEM. A Pointer to the
  325.    message is returned in MSG. If Mode = Stay and there are no messages
  326.    available, the Process will Sleep until a message arrives. If
  327.    Mode = Return the Process will Return no matter what buf MSG will be
  328.    Nil if there were no messages. The content of the Pointer-field of
  329.    the message (the first 8 bytes) is undefined when returning.
  330. }
  331.  
  332.    Var Ptr : Process;
  333.  
  334.    Begin
  335.      Cli;
  336.  
  337.      If MsgSem.MsgQueue<>Nil
  338.      Then Begin
  339.             Dequeue(Ptr,MsgSem.MsgQueue);
  340.             Msg:=Ptr;
  341.           End
  342.      Else case Mode of
  343.  
  344.           Stay   : Begin
  345.                      Sleep(MsgSem.ProcQueue);
  346.                      Dequeue(Ptr,MsgSem.MsgQueue);
  347.                      Msg:=Ptr;
  348.                    End;
  349.  
  350.           Return : Msg:=Nil;
  351.  
  352.           End; { Case }
  353.  
  354.      Sti;
  355.    End; { GetMsg }
  356.  
  357.  
  358. { ----------------------------------------------------------------------- }
  359.  
  360.  
  361. Procedure PutMsg( Var MsgSem : MsgSemaphore; Msg : Msgtype);
  362.  
  363. { Puts a message pointed to by MSG in the message Semaphore MSGSEM. }
  364.  
  365.    Var Ptr : Process;
  366.  
  367.    Begin
  368.      Cli;
  369.  
  370.      Ptr:=Msg;
  371.      Enqueue(Ptr,MsgSem.MsgQueue);
  372.      If MsgSem.ProcQueue<>Nil
  373.      Then Wakeup(MsgSem.ProcQueue)
  374.      Else Sleep(ReadyQueue);
  375.  
  376.      Sti;
  377.    End; { PutMsg }
  378.  
  379.  
  380. { ----------------------------------------------------------------------- }
  381.  
  382.  
  383. Procedure InitMsgSem(Var MsgSem : MsgSemaphore);
  384.  
  385. { Initializes message-Semaphore MSGSEM. MUST be done BEFORE Semaphore
  386.    is used }
  387.  
  388.    Begin
  389.      MsgSem.MsgQueue:=Nil;
  390.      MsgSem.ProcQueue:=Nil;
  391.    End; { InitMsgSem }
  392.  
  393.  
  394. { ----------------------------------------------------------------------- }
  395.  
  396. {$F+}
  397.  
  398. Procedure StartProc;
  399.  
  400. { All processes start by executing this procedure which provides
  401.    a legitimate exit from the kernel by enabling interrupts. }
  402.  
  403.    Begin
  404.      Sti;
  405.    End; { StartProc }
  406.  
  407. {$F-}
  408.  
  409.  
  410. { ----------------------------------------------------------------------- }
  411.  
  412.  
  413. Procedure CreateProcess(body: Pointer; StackSize: Word;
  414.                         Var Proc: QueueType);
  415.  
  416. { Creates a Process and adds it to the system. Process id is returned in
  417.    form of a Pointer to the Process-descriptor in Proc. }
  418.  
  419.    Var Adr      : Longint;          { Adress of stack space for Process }
  420.        ParmSize : Integer;          { Size of parameters in SwitchContext }
  421.  
  422.    Begin
  423.      Cli;
  424.  
  425.      New(Proc);
  426.  
  427.      With Proc^ Do
  428.      Begin
  429.        { Get stack space from heap }
  430.        getmem(Ptr,StackSize);
  431.        Adr:=Longint(Seg(Ptr))*16+Ofs(Ptr);
  432.        Sseg:=Adr shr 4;
  433.        Sp:=(Adr and 15)+StackSize-64;
  434.        ProcStack:=StackSize;
  435.  
  436.        ParmSize:=2*SizeOf(Process);
  437.  
  438.        { Set up stack to Return to body^ when Process is activated }
  439.        MemW(.Sseg:Sp   .):=Sp+2;
  440.        MemW(.Sseg:Sp+ 2.):=Sp+8+ParmSize;
  441.        MemW(.Sseg:Sp+ 4.):=Ofs(StartProc);
  442.        MemW(.Sseg:Sp+ 6.):=Seg(StartProc);
  443.        MemW(.Sseg:Sp+ParmSize+ 8.):=Ofs(body^);
  444.        MemW(.Sseg:Sp+ParmSize+10.):=Seg(body^);
  445.  
  446.        Enqueue(Proc,ReadyQueue);
  447.  
  448.        { Increase no. of processes in system }
  449.        NoProc:=NoProc+1;
  450.  
  451.     End; { With }
  452.  
  453.     Sti;
  454.   End; { CreateProcess }
  455.  
  456.  
  457. { ----------------------------------------------------------------------- }
  458.  
  459.  
  460. Procedure TimeOut;
  461. Interrupt;
  462.  
  463. { This procedure is hooked into the timer interrupt. It switches Process
  464.    after having called the regular driver for the timer. }
  465.  
  466.    Begin
  467.      Cli;
  468.  
  469.      Intr(SavedInt,Regs);
  470.  
  471.      Inc(Tick);
  472.      If ((Tick mod Interleave)=0) and (ReadyQueue<>Nil)
  473.      Then Sleep(ReadyQueue);
  474.  
  475.      Sti;
  476.    End; { TimeOut }
  477.  
  478.  
  479. { ----------------------------------------------------------------------- }
  480.  
  481.  
  482. Procedure Kill(Proc: Process);
  483.  
  484. { Kills the Process pointed to by Proc }
  485.  
  486.    Var QueueProc : Process;
  487.  
  488.    Begin
  489.      Cli;
  490.  
  491.      FreeMem(Proc^.Ptr,Proc^.ProcStack);   { Release stack space on heap }
  492.  
  493.      NoProc:=NoProc-1;                     { If no processes left, stop }
  494.      If NoProc=0 Then StopMulti;           { multiprogram }
  495.  
  496.      If Proc^.inqueue^=CurrentProc         { If killed Process was running, }
  497.      Then Sleep(Dead)                      { start another.                 }
  498.      Else
  499.        Repeat                              { Otherwise remove Process. }
  500.          Dequeue(QueueProc,Proc^.inqueue^);
  501.          If QueueProc<>Proc Then Enqueue(QueueProc,Proc^.inqueue^);
  502.        Until
  503.          QueueProc=Proc;
  504.  
  505.      Sti;
  506.    End; { Kill }
  507.  
  508.  
  509. { ----------------------------------------------------------------------- }
  510.  
  511.  
  512. Procedure Die;
  513.  
  514. { Kills the current Process }
  515.  
  516.    Begin
  517.      Kill(CurrentProc);
  518.    End; { Die }
  519.  
  520.  
  521.  
  522. { ----------------------------------------------------------------------- }
  523.  
  524.  
  525.  
  526. Procedure StartMulti(Mode : SwitchMode);
  527.  
  528. { Starts the multiprogram }
  529.  
  530.    Var IntPtr : Pointer;
  531.  
  532.    Begin
  533.      Cli;
  534.  
  535.      { Hook TimeOut-procedure to timer interrupt }
  536.      GetIntVec(TimerIntNo,IntPtr);
  537.      SetIntVec(SavedInt,IntPtr);
  538.  
  539.      If Mode=Timer Then SetIntVec(TimerIntNo,@TimeOut);
  540.  
  541.      { Save Main program info }
  542.      CurrentProc:=MainProg;
  543.      MainProg^.Sseg:=Sseg;
  544.      MainProg^.Sp:=Sptr;
  545.      Sleep(Main);
  546.  
  547.      Sti;
  548.    End; { StartMulti }
  549.  
  550.  
  551. { ----------------------------------------------------------------------- }
  552.  
  553.  
  554. Procedure StopMulti;
  555.  
  556. { Stops the multiprogram - returns to Main program }
  557.  
  558.    Var IntPtr : Pointer;
  559.  
  560.    Begin
  561.      Cli;
  562.  
  563.      { Put timer driver back into place }
  564.      GetIntVec(SavedInt,IntPtr);
  565.      SetIntVec(TimerIntNo,IntPtr);
  566.  
  567.      { Return to Main program }
  568.      Wakeup(Main);
  569.  
  570.      Sti;
  571.    End; { StopMulti }
  572.  
  573.  
  574. { ----------------------------------------------------------------------- }
  575.  
  576.  
  577. Function NoProcesses : Integer;
  578.  
  579. { Returns the current number of processes in the system }
  580.  
  581.    Begin
  582.      NoProcesses:=NoProc;
  583.    End; { NoProcesses }
  584.  
  585.  
  586. { ----------------------------------------------------------------------- }
  587.  
  588.  
  589. Begin { Unit Main body }
  590.  
  591.   { Initialize queues }
  592.   ReadyQueue:=Nil;
  593.   CurrentProc:=Nil;
  594.   Dead:=Nil;
  595.   Main:=Nil;
  596.  
  597.   NoProc:=0;
  598.   Tick:=0;
  599.  
  600.   { Make descriptor for Main program and set it up as current Process }
  601.   New(MainProg);
  602.   Enqueue(MainProg,CurrentProc);
  603. End.