1 | (*
|
---|
2 | (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
3 | See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
4 | *)
|
---|
5 |
|
---|
6 | (*$R-*)
|
---|
7 | IMPLEMENTATION MODULE Storage;
|
---|
8 | (*
|
---|
9 | Module: Dynamic Storage Allocation
|
---|
10 | Author: Ceriel J.H. Jacobs
|
---|
11 | Adapted from a version in C by Hans Tebra
|
---|
12 | Version: $Header: /cvsup/minix/src/lib/ack/libm2/Storage.mod,v 1.1 2005/10/10 15:27:46 beng Exp $
|
---|
13 | *)
|
---|
14 | (* This storage manager maintains an array of lists of objects with the
|
---|
15 | same size. Commonly used sizes have their own bucket. The larger ones
|
---|
16 | are put in a single list.
|
---|
17 | *)
|
---|
18 | FROM Unix IMPORT sbrk, ILLBREAK;
|
---|
19 | FROM SYSTEM IMPORT ADDRESS, ADR;
|
---|
20 | FROM Traps IMPORT Message;
|
---|
21 |
|
---|
22 | CONST
|
---|
23 | NLISTS = 20;
|
---|
24 | MAGICW = 0A5A5H;
|
---|
25 | MAGICC = 175C;
|
---|
26 |
|
---|
27 | TYPE
|
---|
28 | ALIGNTYPE =
|
---|
29 | RECORD
|
---|
30 | CASE : INTEGER OF
|
---|
31 | 1: l: LONGINT |
|
---|
32 | 2: p: ADDRESS |
|
---|
33 | 3: d: LONGREAL
|
---|
34 | END
|
---|
35 | END; (* A type with high alignment requirements *)
|
---|
36 | BucketPtr = POINTER TO Bucket;
|
---|
37 | Bucket =
|
---|
38 | RECORD
|
---|
39 | CASE : BOOLEAN OF
|
---|
40 | FALSE:
|
---|
41 | BNEXT: BucketPtr; (* next free Bucket *)
|
---|
42 | BSIZE: CARDINAL; | (* size of user part in UNITs *)
|
---|
43 | TRUE: BXX: ALIGNTYPE
|
---|
44 | END;
|
---|
45 | BSTORE: ALIGNTYPE;
|
---|
46 | END;
|
---|
47 |
|
---|
48 | CONST
|
---|
49 | UNIT = SIZE(ALIGNTYPE);
|
---|
50 |
|
---|
51 | VAR
|
---|
52 | FreeLists: ARRAY[0..NLISTS] OF BucketPtr; (* small blocks *)
|
---|
53 | Llist: BucketPtr; (* others *)
|
---|
54 | Compacted: BOOLEAN; (* avoid recursive reorganization *)
|
---|
55 | FirstBlock: BucketPtr;
|
---|
56 | USED: ADDRESS;
|
---|
57 |
|
---|
58 | PROCEDURE MyAllocate(size: CARDINAL) : ADDRESS;
|
---|
59 | VAR nu : CARDINAL;
|
---|
60 | b : CARDINAL;
|
---|
61 | p, q: BucketPtr;
|
---|
62 | pc: POINTER TO CHAR;
|
---|
63 | brk : ADDRESS;
|
---|
64 | BEGIN
|
---|
65 | IF size > CARDINAL(MAX(INTEGER)-2*UNIT + 1) THEN
|
---|
66 | RETURN NIL;
|
---|
67 | END;
|
---|
68 | nu := (size + (UNIT-1)) DIV UNIT;
|
---|
69 | IF nu = 0 THEN
|
---|
70 | nu := 1;
|
---|
71 | END;
|
---|
72 | IF nu <= NLISTS THEN
|
---|
73 | b := nu;
|
---|
74 | IF FreeLists[b] # NIL THEN
|
---|
75 | (* Exact fit *)
|
---|
76 | p := FreeLists[b];
|
---|
77 | FreeLists[b] := p^.BNEXT;
|
---|
78 | p^.BNEXT := USED;
|
---|
79 | IF p^.BSIZE * UNIT # size THEN
|
---|
80 | pc := ADR(p^.BSTORE) + size;
|
---|
81 | pc^ := MAGICC;
|
---|
82 | END;
|
---|
83 | p^.BSIZE := size;
|
---|
84 | RETURN ADR(p^.BSTORE);
|
---|
85 | END;
|
---|
86 |
|
---|
87 | (* Search for a block with >= 2 units more than requested.
|
---|
88 | We pay for an additional header when the block is split.
|
---|
89 | *)
|
---|
90 | FOR b := b+2 TO NLISTS DO
|
---|
91 | IF FreeLists[b] # NIL THEN
|
---|
92 | q := FreeLists[b];
|
---|
93 | FreeLists[b] := q^.BNEXT;
|
---|
94 | p := ADDRESS(q) + (nu+1)*UNIT;
|
---|
95 | (* p indicates the block that must be given
|
---|
96 | back
|
---|
97 | *)
|
---|
98 | p^.BSIZE := q^.BSIZE - nu - 1;
|
---|
99 | p^.BNEXT := FreeLists[p^.BSIZE];
|
---|
100 | FreeLists[p^.BSIZE] := p;
|
---|
101 | q^.BSIZE := nu;
|
---|
102 | q^.BNEXT := USED;
|
---|
103 | IF q^.BSIZE * UNIT # size THEN
|
---|
104 | pc := ADR(q^.BSTORE) + size;
|
---|
105 | pc^ := MAGICC;
|
---|
106 | END;
|
---|
107 | q^.BSIZE := size;
|
---|
108 | RETURN ADR(q^.BSTORE);
|
---|
109 | END;
|
---|
110 | END;
|
---|
111 | END;
|
---|
112 |
|
---|
113 | p := Llist;
|
---|
114 | IF p # NIL THEN
|
---|
115 | q := NIL;
|
---|
116 | WHILE (p # NIL) AND (p^.BSIZE < nu) DO
|
---|
117 | q := p;
|
---|
118 | p := p^.BNEXT;
|
---|
119 | END;
|
---|
120 |
|
---|
121 | IF p # NIL THEN
|
---|
122 | (* p^.BSIZE >= nu *)
|
---|
123 | IF p^.BSIZE <= nu + NLISTS + 1 THEN
|
---|
124 | (* Remove p from this list *)
|
---|
125 | IF q # NIL THEN q^.BNEXT := p^.BNEXT
|
---|
126 | ELSE Llist := p^.BNEXT;
|
---|
127 | END;
|
---|
128 | p^.BNEXT := USED;
|
---|
129 | IF p^.BSIZE > nu + 1 THEN
|
---|
130 | (* split block,
|
---|
131 | tail goes to FreeLists area
|
---|
132 | *)
|
---|
133 | q := ADDRESS(p) + (nu+1)*UNIT;
|
---|
134 | q^.BSIZE := p^.BSIZE -nu -1;
|
---|
135 | q^.BNEXT := FreeLists[q^.BSIZE];
|
---|
136 | FreeLists[q^.BSIZE] := q;
|
---|
137 | p^.BSIZE := nu;
|
---|
138 | END;
|
---|
139 | IF p^.BSIZE * UNIT # size THEN
|
---|
140 | pc := ADR(p^.BSTORE) + size;
|
---|
141 | pc^ := MAGICC;
|
---|
142 | END;
|
---|
143 | p^.BSIZE := size;
|
---|
144 | RETURN ADR(p^.BSTORE);
|
---|
145 | END;
|
---|
146 | (* Give part of tail of original block.
|
---|
147 | Block stays in this list.
|
---|
148 | *)
|
---|
149 | q := ADDRESS(p) + (p^.BSIZE-nu)*UNIT;
|
---|
150 | q^.BSIZE := nu;
|
---|
151 | p^.BSIZE := p^.BSIZE - nu - 1;
|
---|
152 | q^.BNEXT := USED;
|
---|
153 | IF q^.BSIZE * UNIT # size THEN
|
---|
154 | pc := ADR(q^.BSTORE) + size;
|
---|
155 | pc^ := MAGICC;
|
---|
156 | END;
|
---|
157 | q^.BSIZE := size;
|
---|
158 | RETURN ADR(q^.BSTORE);
|
---|
159 | END;
|
---|
160 | END;
|
---|
161 |
|
---|
162 | IF Compacted THEN
|
---|
163 | (* reorganization did not yield sufficient memory *)
|
---|
164 | RETURN NIL;
|
---|
165 | END;
|
---|
166 |
|
---|
167 | brk := sbrk(UNIT * (nu + 1));
|
---|
168 | IF brk = ILLBREAK THEN
|
---|
169 | ReOrganize();
|
---|
170 | Compacted := TRUE;
|
---|
171 | brk := MyAllocate(size);
|
---|
172 | Compacted := FALSE;
|
---|
173 | RETURN brk;
|
---|
174 | END;
|
---|
175 |
|
---|
176 | p := brk;
|
---|
177 | p^.BSIZE := nu;
|
---|
178 | p^.BNEXT := USED;
|
---|
179 | IF p^.BSIZE * UNIT # size THEN
|
---|
180 | pc := ADR(p^.BSTORE) + size;
|
---|
181 | pc^ := MAGICC;
|
---|
182 | END;
|
---|
183 | p^.BSIZE := size;
|
---|
184 | RETURN ADR(p^.BSTORE);
|
---|
185 | END MyAllocate;
|
---|
186 |
|
---|
187 | PROCEDURE ALLOCATE(VAR a: ADDRESS; size: CARDINAL);
|
---|
188 | BEGIN
|
---|
189 | Allocate(a, size);
|
---|
190 | END ALLOCATE;
|
---|
191 |
|
---|
192 | PROCEDURE Allocate(VAR a: ADDRESS; size: CARDINAL);
|
---|
193 | BEGIN
|
---|
194 | a := MyAllocate(size);
|
---|
195 | IF a = NIL THEN
|
---|
196 | Message("out of core");
|
---|
197 | HALT;
|
---|
198 | END;
|
---|
199 | END Allocate;
|
---|
200 |
|
---|
201 | PROCEDURE Available(size: CARDINAL): BOOLEAN;
|
---|
202 | VAR a: ADDRESS;
|
---|
203 | BEGIN
|
---|
204 | a:= MyAllocate(size);
|
---|
205 | IF a # NIL THEN
|
---|
206 | Deallocate(a, size);
|
---|
207 | RETURN TRUE;
|
---|
208 | END;
|
---|
209 | RETURN FALSE;
|
---|
210 | END Available;
|
---|
211 |
|
---|
212 | PROCEDURE DEALLOCATE(VAR a: ADDRESS; size: CARDINAL);
|
---|
213 | BEGIN
|
---|
214 | Deallocate(a, size);
|
---|
215 | END DEALLOCATE;
|
---|
216 |
|
---|
217 | PROCEDURE Deallocate(VAR a: ADDRESS; size: CARDINAL);
|
---|
218 | VAR p: BucketPtr;
|
---|
219 | pc: POINTER TO CHAR;
|
---|
220 | BEGIN
|
---|
221 | IF (a = NIL) THEN
|
---|
222 | Message("(Warning) Deallocate: NIL pointer deallocated");
|
---|
223 | RETURN;
|
---|
224 | END;
|
---|
225 | p := a - UNIT;
|
---|
226 | IF (p^.BNEXT # BucketPtr(USED)) THEN
|
---|
227 | Message("(Warning) Deallocate: area already deallocated or heap corrupted");
|
---|
228 | a := NIL;
|
---|
229 | RETURN;
|
---|
230 | END;
|
---|
231 | WITH p^ DO
|
---|
232 | IF BSIZE # size THEN
|
---|
233 | Message("(Warning) Deallocate: wrong size or heap corrupted");
|
---|
234 | END;
|
---|
235 | BSIZE := (size + (UNIT - 1)) DIV UNIT;
|
---|
236 | IF (BSIZE*UNIT # size) THEN
|
---|
237 | pc := a + size;
|
---|
238 | IF pc^ # MAGICC THEN
|
---|
239 | Message("(Warning) Deallocate: heap corrupted");
|
---|
240 | END;
|
---|
241 | END;
|
---|
242 | IF BSIZE <= NLISTS THEN
|
---|
243 | BNEXT := FreeLists[BSIZE];
|
---|
244 | FreeLists[BSIZE] := p;
|
---|
245 | ELSE
|
---|
246 | BNEXT := Llist;
|
---|
247 | Llist := p;
|
---|
248 | END;
|
---|
249 | END;
|
---|
250 | a := NIL
|
---|
251 | END Deallocate;
|
---|
252 |
|
---|
253 | PROCEDURE ReOrganize();
|
---|
254 | VAR lastblock: BucketPtr;
|
---|
255 | b, be: BucketPtr;
|
---|
256 | i: CARDINAL;
|
---|
257 | BEGIN
|
---|
258 | lastblock := NIL;
|
---|
259 | FOR i := 1 TO NLISTS DO
|
---|
260 | b := FreeLists[i];
|
---|
261 | WHILE b # NIL DO
|
---|
262 | IF ADDRESS(b) > ADDRESS(lastblock) THEN
|
---|
263 | lastblock := b;
|
---|
264 | END;
|
---|
265 | be := b^.BNEXT;
|
---|
266 | b^.BNEXT := NIL; (* temporary free mark *)
|
---|
267 | b := be;
|
---|
268 | END;
|
---|
269 | END;
|
---|
270 |
|
---|
271 | b := Llist;
|
---|
272 | WHILE b # NIL DO
|
---|
273 | IF ADDRESS(b) > ADDRESS(lastblock) THEN
|
---|
274 | lastblock := b;
|
---|
275 | END;
|
---|
276 | be := b^.BNEXT;
|
---|
277 | b^.BNEXT := NIL;
|
---|
278 | b := be;
|
---|
279 | END;
|
---|
280 |
|
---|
281 | (* Now, all free blocks have b^.BNEXT = NIL *)
|
---|
282 |
|
---|
283 | b := FirstBlock;
|
---|
284 | WHILE ADDRESS(b) < ADDRESS(lastblock) DO
|
---|
285 | LOOP
|
---|
286 | be := ADDRESS(b)+(b^.BSIZE+1)*UNIT;
|
---|
287 | IF b^.BNEXT # NIL THEN
|
---|
288 | (* this block is not free *)
|
---|
289 | EXIT;
|
---|
290 | END;
|
---|
291 | IF ADDRESS(be) > ADDRESS(lastblock) THEN
|
---|
292 | (* no next block *)
|
---|
293 | EXIT;
|
---|
294 | END;
|
---|
295 | IF be^.BNEXT # NIL THEN
|
---|
296 | (* next block is not free *)
|
---|
297 | EXIT;
|
---|
298 | END;
|
---|
299 | (* this block and the next one are free,
|
---|
300 | so merge them, but only if it is not too big
|
---|
301 | *)
|
---|
302 | IF MAX(CARDINAL) - b^.BSIZE > be^.BSIZE THEN
|
---|
303 | b^.BSIZE := b^.BSIZE + be^.BSIZE + 1;
|
---|
304 | ELSE
|
---|
305 | EXIT;
|
---|
306 | END;
|
---|
307 | END;
|
---|
308 | b := be;
|
---|
309 | END;
|
---|
310 |
|
---|
311 | (* clear all free lists *)
|
---|
312 | FOR i := 1 TO NLISTS DO FreeLists[i] := NIL; END;
|
---|
313 | Llist := NIL;
|
---|
314 |
|
---|
315 | (* collect free blocks in them again *)
|
---|
316 | b := FirstBlock;
|
---|
317 | WHILE ADDRESS(b) <= ADDRESS(lastblock) DO
|
---|
318 | WITH b^ DO
|
---|
319 | IF BNEXT = NIL THEN
|
---|
320 | IF BSIZE <= NLISTS THEN
|
---|
321 | BNEXT := FreeLists[BSIZE];
|
---|
322 | FreeLists[BSIZE] := b;
|
---|
323 | ELSE
|
---|
324 | BNEXT := Llist;
|
---|
325 | Llist := b;
|
---|
326 | END;
|
---|
327 | b := ADDRESS(b) + (BSIZE+1) * UNIT;
|
---|
328 | ELSE
|
---|
329 | b := ADDRESS(b) +
|
---|
330 | ((BSIZE + (UNIT - 1)) DIV UNIT + 1) * UNIT;
|
---|
331 | END;
|
---|
332 | END;
|
---|
333 | END;
|
---|
334 | END ReOrganize;
|
---|
335 |
|
---|
336 | PROCEDURE InitStorage();
|
---|
337 | VAR i: CARDINAL;
|
---|
338 | brk: ADDRESS;
|
---|
339 | BEGIN
|
---|
340 | FOR i := 1 TO NLISTS DO
|
---|
341 | FreeLists[i] := NIL;
|
---|
342 | END;
|
---|
343 | Llist := NIL;
|
---|
344 | brk := sbrk(0);
|
---|
345 | brk := sbrk(UNIT - brk MOD UNIT);
|
---|
346 | FirstBlock := sbrk(0);
|
---|
347 | Compacted := FALSE;
|
---|
348 | USED := MAGICW;
|
---|
349 | END InitStorage;
|
---|
350 |
|
---|
351 | BEGIN
|
---|
352 | InitStorage();
|
---|
353 | END Storage.
|
---|