storage.mod 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. (* Copyright (C) 1987 Jensen & Partners International *)
  2. (*$V-,S-,R-,I-*)
  3. IMPLEMENTATION MODULE Storage;
  4. FROM SYSTEM IMPORT Seg,Ofs,Registers,HeapBase,EI,DI,GetFlags,SetFlags;
  5. IMPORT Lib;
  6. CONST
  7. EndMarker = 0FFFFH;
  8. ErrorMsg1 = 'Storage, Fatal error : Heap overflow';
  9. ErrorMsg2 = 'Storage, Fatal error : Corrupt heap';
  10. ErrorMsg3 = 'Storage, Fatal error : Invalid dispose';
  11. PROCEDURE MakeHeap( Source : CARDINAL; (* base segment of heap *)
  12. Size : CARDINAL (* size in paragraphs *)
  13. ) : HeapRecPtr;
  14. VAR
  15. storage,first,last : HeapRecPtr;
  16. ie : CARDINAL;
  17. BEGIN
  18. ie := GetFlags(); DI;
  19. storage := [Source:0];
  20. first := [Source+1:0];
  21. last := [Source+Size-1:0];
  22. storage^.next := first;
  23. storage^.size := 0;
  24. first^.next := last;
  25. last^.next := storage;
  26. first^.size := Size-2;
  27. last^.size := EndMarker;
  28. SetFlags(ie);
  29. RETURN storage;
  30. END MakeHeap;
  31. PROCEDURE HeapAllocate(Source : HeapRecPtr; (* source heap *)
  32. VAR A : ADDRESS; (* result *)
  33. Size : CARDINAL); (* request size in paragraphs *)
  34. VAR
  35. res,prev,split : HeapRecPtr;
  36. ie : CARDINAL;
  37. BEGIN
  38. ie := GetFlags(); DI;
  39. IF Size=0 THEN INC(Size) END ;
  40. prev := Source;
  41. WHILE prev^.next^.size < Size DO
  42. prev := prev^.next;
  43. END;
  44. res := prev^.next;
  45. IF res^.size = EndMarker THEN (* heap run out of space *)
  46. EI ;
  47. Lib.FatalError(ErrorMsg1);
  48. END;
  49. IF res^.size = Size THEN (* block correct size *)
  50. prev^.next := res^.next;
  51. ELSE (* split block, bottom half returned, top half linked to free chain *)
  52. split := [Seg(res^)+Size:0];
  53. prev^.next := split;
  54. split^.next := res^.next;
  55. split^.size := res^.size - Size;
  56. END;
  57. SetFlags( ie );
  58. A := ADR(res^);
  59. END HeapAllocate;
  60. PROCEDURE HeapAvail(Source: HeapRecPtr) : CARDINAL;
  61. (* returns the largest block size available for allocation in paragraphs *)
  62. VAR
  63. size : CARDINAL;
  64. p : HeapRecPtr;
  65. ie : CARDINAL;
  66. BEGIN
  67. ie := GetFlags(); DI;
  68. p := Source^.next;
  69. size := 0;
  70. WHILE p^.size <> EndMarker DO
  71. IF p^.size>size THEN size := p^.size END;
  72. p := p^.next;
  73. END;
  74. SetFlags(ie);
  75. RETURN size;
  76. END HeapAvail;
  77. PROCEDURE HeapTotalAvail(Source: HeapRecPtr) : CARDINAL;
  78. (* returns the total block size available for allocation in paragraphs *)
  79. VAR
  80. size : CARDINAL;
  81. p : HeapRecPtr;
  82. ie : CARDINAL;
  83. BEGIN
  84. ie := GetFlags(); DI;
  85. p := Source^.next;
  86. size := 0;
  87. WHILE p^.size <> EndMarker DO
  88. INC(size,p^.size);
  89. p := p^.next;
  90. END;
  91. SetFlags(ie);
  92. RETURN size;
  93. END HeapTotalAvail;
  94. PROCEDURE HeapDeallocate(Source : HeapRecPtr; (* source heap *)
  95. VAR A : ADDRESS; (* block to deallocate *)
  96. Size : CARDINAL ); (* size of block
  97. in paragraphs *)
  98. VAR
  99. target,prev,split : HeapRecPtr;
  100. tseg : CARDINAL;
  101. ie : CARDINAL;
  102. BEGIN
  103. IF (Seg(A^)=0)OR(Ofs(A^)<>0) THEN Lib.FatalError(ErrorMsg3) END;
  104. ie := GetFlags(); DI;
  105. IF Size=0 THEN INC(Size) END ;
  106. target := A;
  107. prev := Source;
  108. tseg := Seg(target^);
  109. WHILE Seg(prev^.next^) < tseg DO
  110. prev := prev^.next;
  111. END;
  112. IF Seg(prev^)+prev^.size = tseg THEN (* amalgamate with prev *)
  113. prev^.size := prev^.size + Size;
  114. target := prev;
  115. ELSIF Seg(prev^)+prev^.size > tseg THEN (* Heap corrupt *)
  116. EI ;
  117. Lib.FatalError(ErrorMsg2);
  118. ELSE
  119. (* link after prev *)
  120. target^.next := prev^.next;
  121. prev^.next := target;
  122. target^.size := Size;
  123. END;
  124. IF (target^.next^.size <> EndMarker)
  125. AND (Seg(target^.next^) = Seg(target^)+target^.size) THEN
  126. (* amalgamate with next block *)
  127. target^.size := target^.size+target^.next^.size;
  128. target^.next := target^.next^.next;
  129. END;
  130. A := NIL;
  131. SetFlags(ie);
  132. END HeapDeallocate;
  133. PROCEDURE HeapChangeAlloc(Source : HeapRecPtr; (* source heap *)
  134. A : ADDRESS; (* block to change *)
  135. OldSize, (* old size of block *)
  136. NewSize : CARDINAL) (* new size of block *)
  137. (* in paragraphs *)
  138. : BOOLEAN; (* if sucessful *)
  139. (* This procedure attempts to change the size of an allocated block
  140. It returns TRUE if succeeded (only expansion can fail)
  141. *)
  142. VAR
  143. target,prev,
  144. split : HeapRecPtr;
  145. tseg : CARDINAL;
  146. result : BOOLEAN;
  147. extendsize : CARDINAL;
  148. ie : CARDINAL;
  149. BEGIN
  150. IF (Seg(A^)=0)OR(Ofs(A^)<>0) THEN Lib.FatalError(ErrorMsg3) END;
  151. IF OldSize = NewSize THEN RETURN TRUE END;
  152. IF OldSize > NewSize THEN
  153. target := [Seg(A^)+NewSize:0];
  154. HeapDeallocate(Source,target,OldSize-NewSize);
  155. RETURN TRUE;
  156. END;
  157. extendsize := NewSize-OldSize;
  158. ie := GetFlags(); DI;
  159. target := A;
  160. prev := Source;
  161. tseg := Seg(target^);
  162. WHILE Seg(prev^.next^) < tseg DO
  163. prev := prev^.next;
  164. END;
  165. IF (prev^.next^.size <> EndMarker) AND
  166. (Seg(prev^.next^) = Seg(target^)+OldSize) AND
  167. (extendsize <= prev^.next^.size) THEN
  168. IF (extendsize = prev^.next^.size) THEN
  169. prev^.next := prev^.next^.next
  170. ELSE
  171. split := [Seg(target^)+NewSize:0];
  172. split^.next := prev^.next^.next;
  173. split^.size := prev^.next^.size - extendsize;
  174. prev^.next := split;
  175. END;
  176. result := TRUE;
  177. ELSE
  178. result := FALSE;
  179. END;
  180. SetFlags(ie);
  181. RETURN result;
  182. END HeapChangeAlloc;
  183. PROCEDURE HeapChangeSize(Source : HeapRecPtr; (* source heap *)
  184. VAR A : ADDRESS; (* block to change *)
  185. OldSize, (* old size of block *)
  186. NewSize : CARDINAL ); (* new size of block
  187. in paragraphs *)
  188. (*
  189. This procedure will change the size of an allocated block
  190. avoiding any copy of data if possible
  191. calls HeapChangeAlloc
  192. *)
  193. VAR
  194. na : ADDRESS;
  195. BEGIN
  196. IF NOT HeapChangeAlloc ( Source, A, OldSize, NewSize ) THEN
  197. HeapAllocate(Source,na,NewSize);
  198. Lib.WordMove(A,na,OldSize*8);
  199. HeapDeallocate(Source,A,OldSize);
  200. A := na;
  201. END;
  202. END HeapChangeSize;
  203. PROCEDURE ALLOCATE(VAR a: ADDRESS; size: CARDINAL);
  204. VAR ps : CARDINAL;
  205. BEGIN
  206. IF size>0FFF0H THEN ps := 1000H
  207. ELSE ps := (size+15) DIV 16;
  208. END ;
  209. HeapAllocate(MainHeap,a,ps);
  210. IF ClearOnAllocate THEN Lib.WordFill( a,ps*8,0); END;
  211. END ALLOCATE;
  212. PROCEDURE DEALLOCATE(VAR a: ADDRESS; size: CARDINAL);
  213. VAR
  214. ps : CARDINAL ;
  215. BEGIN
  216. IF size>0FFF0H THEN ps := 1000H
  217. ELSE ps := (size+15) DIV 16;
  218. END ;
  219. HeapDeallocate(MainHeap,a,ps);
  220. END DEALLOCATE;
  221. PROCEDURE Available(size: CARDINAL) : BOOLEAN;
  222. VAR
  223. ps : CARDINAL ;
  224. BEGIN
  225. IF size=0 THEN ps := 1
  226. ELSIF size>0FFF0H THEN ps := 1000H
  227. ELSE ps := (size+15) DIV 16;
  228. END ;
  229. RETURN ps <= Storage.HeapAvail(Storage.MainHeap);
  230. END Available;
  231. PROCEDURE HEAPINIT();
  232. VAR
  233. sseg : CARDINAL;
  234. BEGIN
  235. ClearOnAllocate := FALSE;
  236. MainHeap := MakeHeap(HeapBase,CARDINAL([Lib.PSP:2]^)-HeapBase);
  237. END HEAPINIT;
  238. BEGIN
  239. HEAPINIT;
  240. END Storage.
  241.