File: Storage.mi

package info (click to toggle)
mocka 9905-2
  • links: PTS
  • area: non-free
  • in suites: potato, sarge, woody
  • size: 5,436 kB
  • ctags: 160
  • sloc: asm: 23,203; makefile: 124; sh: 102; ansic: 23
file content (265 lines) | stat: -rw-r--r-- 6,708 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
(******************************************************************************)
(* Copyright (c) 1988 by GMD Karlruhe, Germany				      *)
(* Gesellschaft fuer Mathematik und Datenverarbeitung			      *)
(* (German National Research Center for Computer Science)		      *)
(* Forschungsstelle fuer Programmstrukturen an Universitaet Karlsruhe	      *)
(* All rights reserved.							      *)
(******************************************************************************)

IMPLEMENTATION MODULE Storage;


   FROM SYSTEM IMPORT ADR, ADDRESS;

   FROM SysLib IMPORT sbrk;


   CONST
     Alignment	       = 4;
     MinSizeSmallBlock = 4;	(* must be aligned *)

   CONST
     MaxSizeSmallBlock     = 30;
     MinSizeLargeBlockLog  = 5;    (* Log2 32    *)
     MaxSizeLargeBlockLog  = 24;   (* Log2 2**24 *)
     PoolSize              = 10240;
     cNoMoreSpace          = -1;

   TYPE
     tBlockPtr        = POINTER TO tBlock;
     tBlock           = RECORD
			  Successor : tBlockPtr;
			  Size      : CARDINAL;
			END;
     tSmallBlockRange = [MinSizeSmallBlock    .. MaxSizeSmallBlock   ];
     tLargeBlockRange = [MinSizeLargeBlockLog .. MaxSizeLargeBlockLog];

   VAR
     SmallChain    : ARRAY tSmallBlockRange OF ADDRESS;
     LargeChain    : ARRAY tLargeBlockRange OF ADDRESS;
     PoolFreePtr   : ADDRESS;
     PoolSpaceLeft : CARDINAL;
     NoMoreSpace   : LONGINT;




   PROCEDURE Log2 (x: LONGINT) : CARDINAL;
   (* Returns the logarithm to the base 2 of 'x'.        *)
     VAR y: CARDINAL;
   BEGIN
     y := 0;
     IF x >= 65536 THEN INC (y, 16); x := x DIV 65536; END;
     IF x >=   256 THEN INC (y,  8); x := x DIV   256; END;
     IF x >=    16 THEN INC (y,  4); x := x DIV    16; END;
     IF x >=     4 THEN INC (y,  2); x := x DIV     4; END;
     IF x >=     2 THEN INC (y,  1); x := x DIV     2; END;
     RETURN y;
   END Log2;


   PROCEDURE ALLOCATE (VAR a : ADDRESS; size : CARDINAL);
   (* Allocates an area of the given size 'size' and returns it's *) 
   (* address in 'a'. If no space is available, 'a' becomes 'NIL'. *)

   VAR
     BlockPtr,
     CurrentBlock,
     PreviousBlock,
     BestBlock,
     PredecessorBlock : tBlockPtr;
     ChainNumber      : CARDINAL;
     CurrentBlockSize,
     BestBlockSize    : CARDINAL;
     j                : tLargeBlockRange;

   BEGIN
       (* align size to next Alignment boundary: *)
       size := CARDINAL( BITSET(size + (Alignment-1)) - BITSET(Alignment-1) );

       IF size < MinSizeSmallBlock THEN
	 size := MinSizeSmallBlock;
       END;

       IF size <= MaxSizeSmallBlock THEN

	 (* handle small block *)

	 IF SmallChain [size] # NIL THEN

	   (* obtain block from freelist *)

	   BlockPtr := SmallChain [size];
	   SmallChain [size] := BlockPtr^.Successor;
	   a :=  BlockPtr;

	 ELSE

	   (* obtain block from storage pool *)

	   PoolAlloc (a, size);
	 END;
       ELSE

	 (* handle large block *)

	 (* 1. search in LargeChain [Log2 (size)] using BEST FIT *)

	 ChainNumber    := Log2 (size);
	 CurrentBlock   := LargeChain [ChainNumber];
	 PreviousBlock  := ADR (LargeChain [ChainNumber]);
	 BestBlock      := NIL;
	 BestBlockSize  := MAX(CARDINAL);

	 WHILE CurrentBlock # NIL DO

	   CurrentBlockSize := CurrentBlock^.Size;
	   IF CurrentBlockSize >= size THEN

	     (* exact match *)

	     IF CurrentBlockSize = size THEN
	       PreviousBlock^.Successor := CurrentBlock^.Successor;
	       a := CurrentBlock;
	       RETURN
	     END;

	     (* improve approximation *)

	     IF CurrentBlockSize < BestBlockSize THEN
	       BestBlock        := CurrentBlock;
	       BestBlockSize    := CurrentBlockSize;
	       PredecessorBlock := PreviousBlock;
	     END;
	   END;
	   PreviousBlock := CurrentBlock;
	   CurrentBlock  := CurrentBlock^.Successor;
	 END;

	 IF BestBlock # NIL THEN
	   PredecessorBlock^.Successor := BestBlock^.Successor;
	   IF   BestBlockSize - size >= MinSizeSmallBlock
	   THEN a := ADDRESS (BestBlock) + size;
		DEALLOCATE (a, BestBlockSize - size);
	   END;
	   a := BestBlock;
	   RETURN
	 END;

	 (* 2. search in LargeChain [j], j > Log2 (size), using FIRST FIT *)

	 FOR j := ChainNumber+1 TO MaxSizeLargeBlockLog DO
	   CurrentBlock := LargeChain [j];
	   IF CurrentBlock # NIL THEN
	     LargeChain [j] := CurrentBlock^.Successor;
	     IF   CurrentBlock^.Size - size >= MinSizeSmallBlock
	     THEN a := ADDRESS (CurrentBlock) + size;
		  DEALLOCATE (a, CurrentBlock^.Size - size);
	     END;

	     a := CurrentBlock;
	     RETURN
	   END;
	 END;

	 IF size < PoolSize THEN

	   (* 3. obtain block from storage pool *)

	   PoolAlloc (a, size);
	 ELSE

	   (* 4. allocate individual block *)
	   IF INTEGER(size) >= 0 THEN
	     BlockPtr := sbrk (size);
	   ELSE
	     BlockPtr := tBlockPtr(NoMoreSpace);
	   END;

	   IF LONGINT (BlockPtr) = NoMoreSpace THEN
	     a := NIL;
	   ELSE
	     a := BlockPtr;
	   END;
	 END;
       END;
   END ALLOCATE;


   PROCEDURE DEALLOCATE (VAR a : ADDRESS; size : CARDINAL);
   (* Frees the area of size 'size' starting at address 'a' *)
   VAR
     BlockPtr    : tBlockPtr;
     ChainNumber : tLargeBlockRange;

   BEGIN
       (* align size to next Alignment boundary: *)
       size := CARDINAL( BITSET(size + (Alignment-1)) - BITSET(Alignment-1) );

       IF size < MinSizeSmallBlock THEN
	 size := MinSizeSmallBlock;
       END;

       BlockPtr := a;
       IF size <= MaxSizeSmallBlock THEN
	 BlockPtr^.Successor := SmallChain [size];
	 SmallChain [size]   := BlockPtr;
       ELSE
	 ChainNumber              := Log2 (size);
	 BlockPtr^.Successor      := LargeChain [ChainNumber];
	 BlockPtr^.Size           := size;
	 LargeChain [ChainNumber] := BlockPtr;
       END;
       a := NIL;
   END DEALLOCATE;


   PROCEDURE PoolAlloc (VAR a : ADDRESS; size: CARDINAL);
   (* Allocates 'size' bytes in the internal      *)
   (* storage pool and returns the start address. *)
   BEGIN
     IF PoolSpaceLeft < size THEN

       (* release old pool *)

       IF PoolSpaceLeft >= MinSizeSmallBlock THEN
	 DEALLOCATE (PoolFreePtr, PoolSpaceLeft);
       END;

       (* allocate new pool *)

       ALLOCATE (PoolFreePtr, PoolSize);

       PoolSpaceLeft := PoolSize;
     END;

     IF PoolFreePtr # NIL THEN
       DEC (PoolSpaceLeft, size);
       INC (PoolFreePtr, size);
       a := PoolFreePtr - size;
     ELSE
       PoolSpaceLeft := 0;
       a := NIL;
     END;
   END PoolAlloc;






   VAR
     i : tSmallBlockRange;
     j : tLargeBlockRange;
BEGIN

      FOR i := MinSizeSmallBlock TO MaxSizeSmallBlock BY 2 DO
	SmallChain [i] := NIL;
      END;
      FOR j := MinSizeLargeBlockLog TO MaxSizeLargeBlockLog DO
	LargeChain [j] := NIL;
      END;
      PoolSpaceLeft := 0;
      NoMoreSpace   := cNoMoreSpace;

END Storage.