home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Applications / ircle 1.5.1 / source / ircle sources / Coroutines.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1993-01-16  |  5.3 KB  |  224 lines  |  [TEXT/PJMM]

  1. {    Coroutines for THINK Pascal    }
  2. {    File: Coroutines    , version 1.1 }
  3. {    Copyright © 1991-1992 Olaf Titz (s_titz@ira.uka.de)    }
  4.  
  5. {    This program is free software; you can redistribute it and/or modify    }
  6. {    it under the terms of the GNU General Public License as published by    }
  7. {    the Free Software Foundation; either version 2 of the License, or    }
  8. {    (at your option) any later version.    }
  9.  
  10. {    This program is distributed in the hope that it will be useful,    }
  11. {    but WITHOUT ANY WARRANTY; without even the implied warranty of    }
  12. {    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    }
  13. {    GNU General Public License for more details.    }
  14.  
  15. {    You should have received a copy of the GNU General Public License    }
  16. {    along with this program; if not, write to the Free Software    }
  17. {    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.    }
  18.  
  19. unit Coroutines;
  20.  
  21. interface
  22.  
  23. var
  24.     GlobalProc: Handle;    { default ' main' coroutine }
  25. { A coroutine may exit. Then it gets transfered to GlobalProc and the }
  26. { workspace deallocated. }
  27.  
  28. procedure InitCoroutines;
  29. { to be called at startup }
  30.  
  31. function NewProcess (proc: ProcPtr; size: integer): Handle;
  32. { generate a coroutine, allocate workspace }
  33.  
  34. procedure Transfer (source, dest: Handle);
  35. { Switch from - to }
  36.  
  37. procedure ExitCoroutines;
  38. { to be called on exit }
  39.  
  40. { To compile this unit you need to set a compiler option 'stackcheck' to either true }
  41. { or false. The former case will perform a regular stack checking like the system's, }
  42. { giving error 28 on overflow; the latter will disable stack checking as well as the }
  43. { default stack checking. Modules using Coroutines and doing Transfer must be compiled }
  44. { with debug option off. }
  45.  
  46. implementation
  47.  
  48. {$D-,V-,R-}
  49.     { Don't break me... }
  50.  
  51. const    {Globals}
  52.     StkLoPtr = $110;
  53.     ApplLimit = $130;
  54.     Lo3Bytes = $31A;
  55.     stacklimit = $A80;    { Last 4 bytes of ApplScratch }
  56.  
  57. type
  58.     WSPHndl = ^WSPPtr;
  59.     WSPPtr = ^WSPRecord;
  60.     WSPRecord = array[0..16000] of longint;
  61.  
  62. {$IFC stackcheck}
  63. var
  64.     StackVBL: VBLTask;
  65. {$ENDC}
  66.  
  67. procedure _Transfer;
  68. inline
  69. {$IFC stackcheck}
  70.     $42B8, stacklimit,    { CLR.L    stacklimit                        }
  71. {$ENDC}
  72.     $206E, $000C,        { MOVEA.L  12(A6),A0                    }
  73.     $2050,                { MOVEA.L  (A0),A0                    }
  74.     $48D0, $58F8,        { MOVEM.L  D3-D7/A3-A4/A6,(A0)    }
  75.     $206E, $0008,        { MOVEA.L  8(A6),A0                    }
  76. {$IFC stackcheck}
  77.     $2010,                { MOVE.L    (A0), D0                    }
  78.     $C0B8, Lo3Bytes,    { AND.L     Lo3Bytes, D0                }
  79.     $2240,                { MOVEA.L    D0,A1                        }
  80.     $4CD9, $58F8,        { MOVEM.L  (A1)+,D3-D7/A3-A4/A6    }
  81.     $2E4E,                { MOVEA.L    A6,A7                        }
  82.     $21C9, stacklimit;    { MOVE.L    A1,stacklimit                }
  83. {$ELSEC}
  84.     $2050,                { MOVEA.L  (A0),A0                    }
  85.     $4CD8, $58F8;        { MOVEM.L  (A0)+,D3-D7/A3-A4/A6    }
  86. {$ENDC}
  87.  
  88. procedure Transfer (source, dest: Handle);
  89.     begin                { LINK        #0,A6                        }
  90.         _Transfer;
  91.     end;                { UNLK        A6                            }
  92.                         { MOVEA.L    (A7)+,A0                    }
  93.                         { ADDQ.W    #8,A7                        }
  94.                         { JMP        (A0)                        }
  95.  
  96.  
  97. procedure _KillCoroutine;
  98. inline
  99. {$IFC stackcheck}
  100.     $42B8, stacklimit,    { CLR.L    stacklimit                        }
  101. {$ENDC}
  102.     $222E, $0004,     { MOVE.L    4(A6),D1                    }
  103.     $206E, $0008,        { MOVEA.L    8(A6),A0                    }
  104. {$IFC stackcheck}
  105.     $2010,                { MOVE.L    (A0), D0                    }
  106.     $C0B8, Lo3Bytes,    { AND.L     Lo3Bytes, D0                }
  107.     $2240,                { MOVEA.L    D0,A1                        }
  108. {$ELSEC}
  109.     $2250,                { MOVEA.L  (A0),A1                    }
  110. {$ENDC}
  111.     $4CD9, $58F8,        { MOVEM.L    (A1)+,D3-D7/A3-A4/A6    }
  112. {$IFC stackcheck}
  113.     $2E4E,                { MOVEA.L    A6,A7                        }
  114.     $21C9, stacklimit,    { MOVE.L    A1,stacklimit                }
  115. {$ENDC}
  116.     $2041,                { MOVEA.L    D1,A0                        }
  117.     $A02A,            { _HUnlock                                }
  118.     $A023;                { _DisposHandle                            }
  119.  
  120.  
  121.  
  122. procedure KillCoroutine (source, dest: Handle);
  123.     begin                { LINK        #0,A6                        }
  124.         _KillCoroutine;
  125.     end;                { UNLK        A6                            }
  126.                         { MOVEA.L    (A7)+,A0                    }
  127.                         { ADDQ.W    #8,A7                        }
  128.                         { JMP        (A0)                        }
  129.  
  130.  
  131.  
  132.  
  133. function NewProcess (proc: ProcPtr; size: integer): Handle;
  134.     var
  135.         h: WSPHndl;
  136.         nn, i: integer;
  137.     begin
  138.         nn := size div 4;    { adjust size to longwords }
  139.         if nn < 255 then    { we need at least 1024 bytes }
  140.             nn := 255;
  141.         size := (nn + 1) * 4;    { from 0 to nn }
  142.         h := WSPHndl(NewHandle(size));
  143.         if h <> nil then begin
  144.             MoveHHi(Handle(h));
  145.             HLock(Handle(h));
  146.             h^^[nn - 0] := longint(GlobalProc);    { set wsp parameters }
  147.             h^^[nn - 1] := longint(h);            { (see docu) }
  148.             h^^[nn - 2] := longint(@KillCoroutine);
  149.             h^^[nn - 5] := longint(Proc);
  150.             h^^[7] := BitAnd(Longint(h^), $00FFFFFF) + (nn - 6) * 4;
  151.         end;
  152.         NewProcess := Handle(h);
  153.     end;
  154.  
  155.  
  156. {$IFC stackcheck}
  157.  
  158. procedure _myStackCheck;
  159. inline
  160.     $BFF8, stacklimit,            { CMPA.L    stacklimit,A7                        }
  161.     $6200, $0006,                { BHI        _my0                                }
  162.     $701C,                        { MOVEQ    #28,D0                                }
  163.     $A9C9;                        { _SysError                                    }
  164.                                 {_my0:    }
  165.  
  166. {$A+}
  167. procedure myStackCheck;
  168.     begin
  169.         _myStackCheck;
  170.         StackVBL.vblCount := 1
  171.     end;
  172. {$A-}
  173.  
  174.  
  175. {$ENDC stackcheck}
  176.  
  177. procedure InitCoroutines;
  178.     type
  179.         pl = ^longint;
  180.     var
  181.         ap: pl;
  182.         h: WSPHndl;
  183.         i: longint;
  184.     begin
  185.         new(h);                        { generate a fake WSP handle }
  186.         ap := pl(ApplLimit);
  187.         i := ap^ + 8;
  188.         h^ := WSPPtr(i);            { pointer to ApplLimit+8... }
  189.         GlobalProc := Handle(h);    { ...in GlobalProc }
  190.         ap := pl(StkLoPtr);
  191.         ap^ := 0;                    { switch stack checking off }
  192. {$IFC stackcheck}
  193.         ap := pl(stacklimit);
  194.         ap^ := i + 32;
  195.         with StackVBL do begin
  196.             qType := ord(vType);
  197.             vblAddr := @myStackCheck;
  198.             vblCount := 1;
  199.             vblPhase := 0
  200.         end;
  201.         i := VInstall(QElemPtr(@StackVBL));
  202. {$ENDC stackcheck}
  203.     end;
  204.  
  205.  
  206.  {$IFC stackcheck}
  207.  
  208. procedure ExitCoroutines;
  209.     var
  210.         i: integer;
  211.     begin
  212.         i := VRemove(@myStackCheck)
  213.     end;
  214.  
  215. {$ELSEC}
  216.  
  217. procedure ExitCoroutines;
  218.     begin
  219.     end;
  220.  
  221. {$ENDC}
  222.  
  223.  
  224. end.