1 |
|
---|
2 | /**********************************************************/
|
---|
3 | /*
|
---|
4 | /* This was file READ_ME
|
---|
5 | /*
|
---|
6 | /**********************************************************/
|
---|
7 |
|
---|
8 | /*
|
---|
9 | PROGRAM
|
---|
10 | malloc(), free(), realloc()
|
---|
11 | AUTHOR
|
---|
12 | Dick Grune, Free University, Amsterdam
|
---|
13 | Modified by Ceriel Jacobs, Free University, Amsterdam,
|
---|
14 | to make it faster
|
---|
15 | VERSION
|
---|
16 | $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $
|
---|
17 | DESCRIPTION
|
---|
18 | This is an independent rewrite of the malloc/free package; it is
|
---|
19 | fast and efficient. Free blocks are kept in doubly linked lists,
|
---|
20 | list N holding blocks with sizes between 2**N and 2**(N+1)-1.
|
---|
21 | Consequently neither malloc nor free have to do any searching:
|
---|
22 | the cost of a call of malloc() (or free()) is constant, however
|
---|
23 | many blocks you have got.
|
---|
24 |
|
---|
25 | If you switch on the NON_STANDARD macro (see param.h) every block
|
---|
26 | costs 2 pointers overhead (otherwise it's 4).
|
---|
27 | */
|
---|
28 | /*
|
---|
29 | There is an organisational problem here: during devellopment
|
---|
30 | I want the package divided into modules, which implies external
|
---|
31 | names for the communication. The only external names I want in
|
---|
32 | the finished product are malloc, realloc and free. This requires
|
---|
33 | some hanky-panky.
|
---|
34 | */
|
---|
35 |
|
---|
36 |
|
---|
37 | /**********************************************************/
|
---|
38 | /*
|
---|
39 | /* This was file size_type.h
|
---|
40 | /*
|
---|
41 | /**********************************************************/
|
---|
42 |
|
---|
43 | #if _EM_WSIZE == _EM_PSIZE
|
---|
44 | typedef unsigned int size_type;
|
---|
45 | #elif _EM_LSIZE == _EM_PSIZE
|
---|
46 | typedef unsigned long size_type;
|
---|
47 | #else
|
---|
48 | #error funny pointer size
|
---|
49 | #endif
|
---|
50 | #include <stdlib.h>
|
---|
51 | #include <stdio.h>
|
---|
52 |
|
---|
53 |
|
---|
54 | /**********************************************************/
|
---|
55 | /*
|
---|
56 | /* This was file param.h
|
---|
57 | /*
|
---|
58 | /**********************************************************/
|
---|
59 |
|
---|
60 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
61 | /*
|
---|
62 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
63 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
64 | */
|
---|
65 |
|
---|
66 | # undef NON_STANDARD /* If defined, the contents of a block
|
---|
67 | will NOT be left undisturbed after it
|
---|
68 | is freed, as opposed to what it says
|
---|
69 | in the manual (malloc(2)).
|
---|
70 | Setting this option reduces the memory
|
---|
71 | overhead considerably. I personally
|
---|
72 | consider the specified behaviour an
|
---|
73 | artefact of the original
|
---|
74 | implementation.
|
---|
75 | */
|
---|
76 |
|
---|
77 | # define ASSERT /* If defined, some inexpensive tests
|
---|
78 | will be made to ensure the
|
---|
79 | correctness of some sensitive data.
|
---|
80 | It often turns an uncontrolled crash
|
---|
81 | into a controlled one.
|
---|
82 | */
|
---|
83 |
|
---|
84 | # define CHECK /* If defined, extensive and expensive
|
---|
85 | tests will be done, inculding a
|
---|
86 | checksum on the mallinks (chunk
|
---|
87 | information blocks). The resulting
|
---|
88 | information will be printed on a file
|
---|
89 | called mal.out .
|
---|
90 | Additionally a function
|
---|
91 | maldump(n) int n;
|
---|
92 | will be defined, which will dump
|
---|
93 | pertinent info in pseudo-readable
|
---|
94 | form; it aborts afterwards if n != 0.
|
---|
95 | */
|
---|
96 |
|
---|
97 | # undef EXTERN /* If defined, all static names will
|
---|
98 | become extern, which is a help in
|
---|
99 | using adb(1) or prof(1)
|
---|
100 | */
|
---|
101 |
|
---|
102 | # define STORE /* If defined, separate free lists will
|
---|
103 | be kept of chunks with small sizes,
|
---|
104 | to speed things up a little.
|
---|
105 | */
|
---|
106 |
|
---|
107 | # undef SYSTEM /* If defined, the system module is used.
|
---|
108 | Otherwise, "sbrk" is called directly.
|
---|
109 | */
|
---|
110 |
|
---|
111 | #define ALIGNMENT 8
|
---|
112 | /* alignment common to all types */
|
---|
113 | #define LOG_MIN_SIZE 3
|
---|
114 | #define LOG_MAX_SIZE 24
|
---|
115 |
|
---|
116 |
|
---|
117 | /**********************************************************/
|
---|
118 | /*
|
---|
119 | /* This was file impl.h
|
---|
120 | /*
|
---|
121 | /**********************************************************/
|
---|
122 |
|
---|
123 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
124 | /*
|
---|
125 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
126 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
127 | */
|
---|
128 | /* This file essentially describes how the mallink info block
|
---|
129 | is implemented.
|
---|
130 | */
|
---|
131 |
|
---|
132 | #define MIN_SIZE (1<<LOG_MIN_SIZE)
|
---|
133 | #define MAX_FLIST (LOG_MAX_SIZE - LOG_MIN_SIZE)
|
---|
134 | #if ALIGNMENT != 4 && ALIGNMENT != 8 && ALIGNMENT != 16
|
---|
135 | #error ALIGNMENT must be 4, 8 or 16
|
---|
136 | #elif ALIGNMENT % _EM_LSIZE
|
---|
137 | /* since calloc() does it's initialization in longs */
|
---|
138 | #error ALIGNMENT must be a multiple of the long size
|
---|
139 | #endif
|
---|
140 | #define align(n) (((n) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))
|
---|
141 |
|
---|
142 | union _inf {
|
---|
143 | union _inf *ptr;
|
---|
144 | size_type ui;
|
---|
145 | };
|
---|
146 |
|
---|
147 | typedef union _inf mallink;
|
---|
148 | #define MAL_NULL ((mallink *)0)
|
---|
149 |
|
---|
150 | /* Access macros; only these macros know where to find values.
|
---|
151 | They are also lvalues.
|
---|
152 | */
|
---|
153 | #ifndef NON_STANDARD
|
---|
154 | #define OFF_SET 0
|
---|
155 | #else /* def NON_STANDARD */
|
---|
156 | #define OFF_SET 2
|
---|
157 | #endif /* NON_STANDARD */
|
---|
158 |
|
---|
159 | #define _log_prev_of(ml) ((ml)[-1+OFF_SET]).ptr
|
---|
160 | #define _log_next_of(ml) ((ml)[-2+OFF_SET]).ptr
|
---|
161 | #define _phys_prev_of(ml) ((ml)[-3+OFF_SET]).ptr
|
---|
162 | #define _this_size_of(ml) ((ml)[-4+OFF_SET]).ui
|
---|
163 | #ifndef CHECK
|
---|
164 | #define N_WORDS 4
|
---|
165 | #else /* ifdef CHECK */
|
---|
166 | #define _checksum_of(ml) ((ml)[-5+OFF_SET]).ui
|
---|
167 | #define _print_of(ml) ((ml)[-6+OFF_SET]).ui
|
---|
168 | #define _mark_of(ml) ((ml)[-7+OFF_SET]).ui
|
---|
169 | #define N_WORDS 7
|
---|
170 | #endif /* CHECK */
|
---|
171 |
|
---|
172 | #define mallink_size() (size_t) \
|
---|
173 | align((N_WORDS - OFF_SET) * sizeof (mallink))
|
---|
174 |
|
---|
175 | #ifdef CHECK
|
---|
176 | #define set_mark(ml,e) (_mark_of(ml) = (e))
|
---|
177 | #define mark_of(ml) (_mark_of(ml))
|
---|
178 |
|
---|
179 | #define set_checksum(ml,e) (_checksum_of(ml) = (e))
|
---|
180 | #define checksum_of(ml) (_checksum_of(ml))
|
---|
181 | #endif /* CHECK */
|
---|
182 |
|
---|
183 | #define new_mallink(ml) ( _log_prev_of(ml) = 0, \
|
---|
184 | _log_next_of(ml) = 0, \
|
---|
185 | _phys_prev_of(ml) = 0, \
|
---|
186 | _this_size_of(ml) = 0 )
|
---|
187 |
|
---|
188 | #define block_of_mallink(ml) ((void *)ml)
|
---|
189 | #define mallink_of_block(addr) ((mallink *)addr)
|
---|
190 |
|
---|
191 | #define public extern
|
---|
192 | #define publicdata extern
|
---|
193 | #ifndef EXTERN
|
---|
194 | #define private static
|
---|
195 | #define privatedata static
|
---|
196 | #else /* def EXTERN */
|
---|
197 | #define private extern
|
---|
198 | #define privatedata
|
---|
199 | #endif /* EXTERN */
|
---|
200 |
|
---|
201 | #ifdef ASSERT
|
---|
202 | private m_assert(const char *fn, int ln);
|
---|
203 | #define assert(b) (!(b) ? m_assert(__FILE__, __LINE__) : 0)
|
---|
204 | #else /* ndef ASSERT */
|
---|
205 | #define assert(b) 0
|
---|
206 | #endif /* ASSERT */
|
---|
207 |
|
---|
208 |
|
---|
209 | /**********************************************************/
|
---|
210 | /*
|
---|
211 | /* This was file check.h
|
---|
212 | /*
|
---|
213 | /**********************************************************/
|
---|
214 |
|
---|
215 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
216 | /*
|
---|
217 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
218 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
219 | */
|
---|
220 | #ifdef CHECK
|
---|
221 |
|
---|
222 | private check_mallinks(const char *s), calc_checksum(mallink *ml);
|
---|
223 | private check_work_empty(const char *s);
|
---|
224 | private started_working_on(mallink *ml), stopped_working_on(mallink *ml);
|
---|
225 |
|
---|
226 | #else /* ifndef CHECK */
|
---|
227 |
|
---|
228 | #define maldump(n) abort()
|
---|
229 | #define check_mallinks(s) 0
|
---|
230 | #define calc_checksum(ml) 0
|
---|
231 | #define started_working_on(ml) 0
|
---|
232 | #define stopped_working_on(ml) 0
|
---|
233 | #define check_work_empty(s) 0
|
---|
234 |
|
---|
235 | #endif /* CHECK */
|
---|
236 |
|
---|
237 |
|
---|
238 | /**********************************************************/
|
---|
239 | /*
|
---|
240 | /* This was file log.h
|
---|
241 | /*
|
---|
242 | /**********************************************************/
|
---|
243 |
|
---|
244 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
245 | /*
|
---|
246 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
247 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
248 | */
|
---|
249 | /* Algorithms to manipulate the doubly-linked lists of free
|
---|
250 | chunks.
|
---|
251 | */
|
---|
252 |
|
---|
253 | private link_free_chunk(mallink *ml), unlink_free_chunk(mallink *ml);
|
---|
254 | private mallink *first_present(int class);
|
---|
255 | private mallink *search_free_list(int class, size_t n);
|
---|
256 |
|
---|
257 | #ifdef STORE
|
---|
258 | #define in_store(ml) ((size_type)_phys_prev_of(ml) & STORE_BIT)
|
---|
259 | #define set_store(ml, e) \
|
---|
260 | (_phys_prev_of(ml) = (mallink *) \
|
---|
261 | ((e) ? (size_type) _phys_prev_of(ml) | STORE_BIT : \
|
---|
262 | (size_type) _phys_prev_of(ml) & ~STORE_BIT))
|
---|
263 | #endif
|
---|
264 | #define set_log_prev(ml,e) (_log_prev_of(ml) = (e))
|
---|
265 | #define log_prev_of(ml) (mallink *) (_log_prev_of(ml))
|
---|
266 |
|
---|
267 | #define set_log_next(ml,e) (_log_next_of(ml) = (e))
|
---|
268 | #define log_next_of(ml) (mallink *) (_log_next_of(ml))
|
---|
269 |
|
---|
270 |
|
---|
271 |
|
---|
272 | /**********************************************************/
|
---|
273 | /*
|
---|
274 | /* This was file phys.h
|
---|
275 | /*
|
---|
276 | /**********************************************************/
|
---|
277 |
|
---|
278 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
279 | /*
|
---|
280 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
281 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
282 | */
|
---|
283 | /* Algorithms to manipulate the doubly-linked list of physical
|
---|
284 | chunks.
|
---|
285 | */
|
---|
286 | privatedata mallink *ml_last;
|
---|
287 |
|
---|
288 | #define FREE_BIT 01
|
---|
289 | #ifdef STORE
|
---|
290 | #define STORE_BIT 02
|
---|
291 | #define BITS (FREE_BIT|STORE_BIT)
|
---|
292 | #else
|
---|
293 | #define BITS (FREE_BIT)
|
---|
294 | #endif
|
---|
295 |
|
---|
296 | #define __bits(ml) ((int)((size_type)_phys_prev_of(ml) & BITS))
|
---|
297 | #define __free_of(ml) ((int)((size_type)_phys_prev_of(ml) & FREE_BIT))
|
---|
298 | #define __phys_prev_of(ml) ((mallink *)((size_type)_phys_prev_of(ml) & ~BITS))
|
---|
299 | #define prev_size_of(ml) ((char *)(ml) - \
|
---|
300 | (char *)__phys_prev_of(ml) - \
|
---|
301 | mallink_size() \
|
---|
302 | )
|
---|
303 | #define set_phys_prev(ml,e) \
|
---|
304 | (_phys_prev_of(ml) = (mallink *) ((char *)e + __bits(ml)))
|
---|
305 |
|
---|
306 | #ifdef CHECK
|
---|
307 | private Error(const char *fmt, const char *s, mallink *ml);
|
---|
308 | #define phys_prev_of(ml) (mallink *) \
|
---|
309 | (first_mallink(ml) ? \
|
---|
310 | (char *)Error("phys_prev_of first_mallink %p", "somewhere", ml) : \
|
---|
311 | (char *)__phys_prev_of(ml) \
|
---|
312 | )
|
---|
313 | #else /* ndef CHECK */
|
---|
314 | #define phys_prev_of(ml) __phys_prev_of(ml)
|
---|
315 | #endif /* CHECK */
|
---|
316 |
|
---|
317 | #define first_mallink(ml) (int) (__phys_prev_of(ml) == 0)
|
---|
318 | #define last_mallink(ml) (int) ((ml) == ml_last)
|
---|
319 |
|
---|
320 | /* There is an ambiguity in the semantics of phys_next_of: sometimes
|
---|
321 | one wants it to return MAL_NULL if there is no next chunk, at
|
---|
322 | other times one wants the address of the virtual chunk at the
|
---|
323 | end of memory. The present version returns the address of the
|
---|
324 | (virtual) chunk and relies on the user to test last_mallink(ml)
|
---|
325 | first.
|
---|
326 | */
|
---|
327 | #define size_of(ml) (_this_size_of(ml) - mallink_size())
|
---|
328 | #define set_phys_next(ml,e) \
|
---|
329 | (_this_size_of(ml) = (size_type)((char *)(e) - (char *)(ml)))
|
---|
330 | #define phys_next_of(ml) (mallink *) ((char *)(ml) + _this_size_of(ml))
|
---|
331 |
|
---|
332 | #define set_free(ml,e) \
|
---|
333 | (_phys_prev_of(ml) = (mallink *) \
|
---|
334 | ((e) ? (size_type) _phys_prev_of(ml) | FREE_BIT : \
|
---|
335 | (size_type) _phys_prev_of(ml) & ~FREE_BIT))
|
---|
336 | #define free_of(ml) (__free_of(ml))
|
---|
337 |
|
---|
338 | #define coalesce_forw(ml,nxt) ( unlink_free_chunk(nxt), \
|
---|
339 | combine_chunks((ml), (nxt)))
|
---|
340 |
|
---|
341 | #define coalesce_backw(ml,prv) ( unlink_free_chunk(prv), \
|
---|
342 | stopped_working_on(ml), \
|
---|
343 | combine_chunks((prv), (ml)), \
|
---|
344 | started_working_on(prv))
|
---|
345 |
|
---|
346 | #ifdef CHECK
|
---|
347 | #define set_print(ml,e) (_print_of(ml) = (e))
|
---|
348 | #define print_of(ml) (_print_of(ml))
|
---|
349 | #endif /* CHECK */
|
---|
350 |
|
---|
351 | private truncate(mallink *ml, size_t size);
|
---|
352 | private combine_chunks(register mallink *ml1, register mallink *ml2);
|
---|
353 | private mallink *create_chunk(void *p, size_t n);
|
---|
354 |
|
---|
355 |
|
---|
356 | /**********************************************************/
|
---|
357 | /*
|
---|
358 | /* This was file mal.c
|
---|
359 | /*
|
---|
360 | /**********************************************************/
|
---|
361 |
|
---|
362 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
363 | /*
|
---|
364 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
365 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
366 | */
|
---|
367 | #include <limits.h>
|
---|
368 | #include <stdlib.h>
|
---|
369 |
|
---|
370 | /* Malloc space is traversed by N doubly-linked lists of chunks, each
|
---|
371 | containing a couple of house-keeping data addressed as a
|
---|
372 | 'mallink' and a piece of useful space, called the block.
|
---|
373 | The N lists are accessed through their starting pointers in
|
---|
374 | free_list[]. Free_list[n] points to a list of chunks between
|
---|
375 | 2**(n+LOG_MIN_SIZE) and 2**(n+LOG_MIN_SIZE+1)-1, which means
|
---|
376 | that the smallest chunk is 2**LOG_MIN_SIZE (== MIN_SIZE).
|
---|
377 | */
|
---|
378 |
|
---|
379 | #ifdef SYSTEM
|
---|
380 | #include <system.h>
|
---|
381 | #define SBRK sys_break
|
---|
382 | #else
|
---|
383 | #define SBRK _sbrk
|
---|
384 | #define ILL_BREAK (void *)(-1) /* funny failure value */
|
---|
385 | #endif
|
---|
386 | extern void *SBRK(int incr);
|
---|
387 | #ifdef STORE
|
---|
388 | #define MAX_STORE 32
|
---|
389 | private do_free(mallink *ml), sell_out(void);
|
---|
390 | privatedata mallink *store[MAX_STORE];
|
---|
391 | #endif /* STORE */
|
---|
392 |
|
---|
393 | void *privious_free= (void *)-1;
|
---|
394 | void *
|
---|
395 | malloc(register size_t n)
|
---|
396 | {check_mallinks("malloc entry");{
|
---|
397 | register mallink *ml;
|
---|
398 | register int min_class;
|
---|
399 | void *tmp;
|
---|
400 |
|
---|
401 | { static int reent= 0; if (!reent) { reent++; printf("malloc\n"); reent--; } }
|
---|
402 | privious_free= (void *)-1;
|
---|
403 | if (n == 0) {
|
---|
404 | return NULL;
|
---|
405 | }
|
---|
406 | if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
|
---|
407 | #ifdef STORE
|
---|
408 | if (n <= MAX_STORE*MIN_SIZE) {
|
---|
409 | /* look in the store first */
|
---|
410 | register mallink **stp = &store[(n >> LOG_MIN_SIZE) - 1];
|
---|
411 |
|
---|
412 | if (ml = *stp) {
|
---|
413 | *stp = log_next_of(ml);
|
---|
414 | set_store(ml, 0);
|
---|
415 | check_mallinks("malloc fast exit");
|
---|
416 | assert(! in_store(ml));
|
---|
417 | tmp= block_of_mallink(ml);
|
---|
418 | { static int reent= 0; if (!reent) { reent++; printf("= 0x%x\n", tmp);reent--; } }
|
---|
419 | return tmp;
|
---|
420 | }
|
---|
421 | }
|
---|
422 | #endif /* STORE */
|
---|
423 |
|
---|
424 | check_work_empty("malloc, entry");
|
---|
425 |
|
---|
426 | /* Acquire a chunk of at least size n if at all possible;
|
---|
427 | Try everything.
|
---|
428 | */
|
---|
429 | {
|
---|
430 | /* Inline substitution of "smallest".
|
---|
431 | */
|
---|
432 | register size_t n1 = n;
|
---|
433 |
|
---|
434 | assert(n1 < (1L << LOG_MAX_SIZE));
|
---|
435 | min_class = 0;
|
---|
436 |
|
---|
437 | do {
|
---|
438 | n1 >>= 1;
|
---|
439 | min_class++;
|
---|
440 | } while (n1 >= MIN_SIZE);
|
---|
441 | }
|
---|
442 |
|
---|
443 | if (min_class >= MAX_FLIST)
|
---|
444 | return NULL; /* we don't deal in blocks that big */
|
---|
445 | ml = first_present(min_class);
|
---|
446 | if (ml == MAL_NULL) {
|
---|
447 | /* Try and extend */
|
---|
448 | register void *p;
|
---|
449 | #define GRABSIZE 4096 /* Power of 2 */
|
---|
450 | register size_t req =
|
---|
451 | ((MIN_SIZE<<min_class)+ mallink_size() + GRABSIZE - 1) &
|
---|
452 | ~(GRABSIZE-1);
|
---|
453 |
|
---|
454 | if (!ml_last) {
|
---|
455 | /* first align SBRK() */
|
---|
456 |
|
---|
457 | p = SBRK(0);
|
---|
458 | SBRK((int) (align((size_type) p) - (size_type) p));
|
---|
459 | }
|
---|
460 |
|
---|
461 | /* SBRK takes an int; sorry ... */
|
---|
462 | if ((int) req < 0) {
|
---|
463 | p = ILL_BREAK;
|
---|
464 | } else {
|
---|
465 | p = SBRK((int)req);
|
---|
466 | }
|
---|
467 | if (p == ILL_BREAK) {
|
---|
468 | req = n + mallink_size();
|
---|
469 | if ((int) req >= 0) p = SBRK((int)req);
|
---|
470 | }
|
---|
471 | if (p == ILL_BREAK) {
|
---|
472 | /* Now this is bad. The system will not give us
|
---|
473 | more memory. We can only liquidate our store
|
---|
474 | and hope it helps.
|
---|
475 | */
|
---|
476 | #ifdef STORE
|
---|
477 | sell_out();
|
---|
478 | ml = first_present(min_class);
|
---|
479 | if (ml == MAL_NULL) {
|
---|
480 | #endif /* STORE */
|
---|
481 | /* In this emergency we try to locate a suitable
|
---|
482 | chunk in the free_list just below the safe
|
---|
483 | one; some of these chunks may fit the job.
|
---|
484 | */
|
---|
485 | ml = search_free_list(min_class - 1, n);
|
---|
486 | if (!ml) /* really out of space */
|
---|
487 | return NULL;
|
---|
488 | started_working_on(ml);
|
---|
489 | unlink_free_chunk(ml);
|
---|
490 | check_mallinks("suitable_chunk, forced");
|
---|
491 | #ifdef STORE
|
---|
492 | }
|
---|
493 | else started_working_on(ml);
|
---|
494 | #endif /* STORE */
|
---|
495 | }
|
---|
496 | else {
|
---|
497 | assert((size_type)p == align((size_type)p));
|
---|
498 | ml = create_chunk(p, req);
|
---|
499 | }
|
---|
500 | check_mallinks("suitable_chunk, extended");
|
---|
501 | }
|
---|
502 | else started_working_on(ml);
|
---|
503 |
|
---|
504 | /* we have a chunk */
|
---|
505 | set_free(ml, 0);
|
---|
506 | calc_checksum(ml);
|
---|
507 | check_mallinks("suitable_chunk, removed");
|
---|
508 | n += mallink_size();
|
---|
509 | if (n + MIN_SIZE <= size_of(ml)) {
|
---|
510 | truncate(ml, n);
|
---|
511 | }
|
---|
512 | stopped_working_on(ml);
|
---|
513 | check_mallinks("malloc exit");
|
---|
514 | check_work_empty("malloc exit");
|
---|
515 | #ifdef STORE
|
---|
516 | assert(! in_store(ml));
|
---|
517 | #endif
|
---|
518 | tmp= block_of_mallink(ml);
|
---|
519 | { static int reent= 0; if (!reent) { reent++; printf("= 0x%x\n", tmp);reent--; } }
|
---|
520 | return tmp;
|
---|
521 | }}
|
---|
522 |
|
---|
523 | void
|
---|
524 | free(void *addr)
|
---|
525 | {check_mallinks("free entry");{
|
---|
526 | register mallink *ml;
|
---|
527 |
|
---|
528 | printf("free 0x%x\n", addr);
|
---|
529 | if (privious_free == addr) { fflush(stdout); fflush(stderr); abort(); }
|
---|
530 | privious_free= addr;
|
---|
531 | if (addr == NULL) {
|
---|
532 | check_mallinks("free(0) very fast exit");
|
---|
533 | return;
|
---|
534 | }
|
---|
535 |
|
---|
536 | ml = mallink_of_block(addr);
|
---|
537 | #ifdef STORE
|
---|
538 |
|
---|
539 | if (free_of(ml) || in_store(ml))
|
---|
540 | return; /* user frees free block */
|
---|
541 | if (size_of(ml) <= MAX_STORE*MIN_SIZE) {
|
---|
542 | /* return to store */
|
---|
543 | mallink **stp = &store[(size_of(ml) >> LOG_MIN_SIZE) - 1];
|
---|
544 |
|
---|
545 | set_log_next(ml, *stp);
|
---|
546 | *stp = ml;
|
---|
547 | set_store(ml, 1);
|
---|
548 | calc_checksum(ml);
|
---|
549 | check_mallinks("free fast exit");
|
---|
550 | }
|
---|
551 | else {
|
---|
552 | do_free(ml);
|
---|
553 | check_mallinks("free exit");
|
---|
554 | }
|
---|
555 | }}
|
---|
556 |
|
---|
557 | private
|
---|
558 | do_free(register mallink *ml)
|
---|
559 | {{
|
---|
560 | #endif
|
---|
561 |
|
---|
562 | #ifndef STORE
|
---|
563 | if (free_of(ml)) return;
|
---|
564 | #endif /* STORE */
|
---|
565 | started_working_on(ml);
|
---|
566 | set_free(ml, 1);
|
---|
567 | calc_checksum(ml);
|
---|
568 | if (! last_mallink(ml)) {
|
---|
569 | register mallink *next = phys_next_of(ml);
|
---|
570 |
|
---|
571 | if (free_of(next)) coalesce_forw(ml, next);
|
---|
572 | }
|
---|
573 |
|
---|
574 | if (! first_mallink(ml)) {
|
---|
575 | register mallink *prev = phys_prev_of(ml);
|
---|
576 |
|
---|
577 | if (free_of(prev)) {
|
---|
578 | coalesce_backw(ml, prev);
|
---|
579 | ml = prev;
|
---|
580 | }
|
---|
581 | }
|
---|
582 | link_free_chunk(ml);
|
---|
583 | stopped_working_on(ml);
|
---|
584 | check_work_empty("free");
|
---|
585 |
|
---|
586 | /* Compile-time checks on param.h */
|
---|
587 | switch (0) {
|
---|
588 | case MIN_SIZE < OFF_SET * sizeof(mallink): break;
|
---|
589 | case 1: break;
|
---|
590 | /* If this statement does not compile due to duplicate case
|
---|
591 | entry, the minimum size block cannot hold the links for
|
---|
592 | the free blocks. Either raise LOG_MIN_SIZE or switch
|
---|
593 | off NON_STANDARD.
|
---|
594 | */
|
---|
595 | }
|
---|
596 | switch(0) {
|
---|
597 | case sizeof(void *) != sizeof(size_type): break;
|
---|
598 | case 1: break;
|
---|
599 | /* If this statement does not compile due to duplicate
|
---|
600 | case entry, size_type is not defined correctly.
|
---|
601 | Redefine and compile again.
|
---|
602 | */
|
---|
603 | }
|
---|
604 | }}
|
---|
605 |
|
---|
606 | void *
|
---|
607 | realloc(void *addr, register size_t n)
|
---|
608 | {check_mallinks("realloc entry");{
|
---|
609 | register mallink *ml, *ph_next;
|
---|
610 | register size_type size;
|
---|
611 |
|
---|
612 | printf("realloc 0x%x, %d\n", addr, n);
|
---|
613 | if (addr == NULL) {
|
---|
614 | /* Behave like most Unix realloc's when handed a
|
---|
615 | null-pointer
|
---|
616 | */
|
---|
617 | return malloc(n);
|
---|
618 | }
|
---|
619 | if (n == 0) {
|
---|
620 | free(addr);
|
---|
621 | return NULL;
|
---|
622 | }
|
---|
623 | ml = mallink_of_block(addr);
|
---|
624 | if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
|
---|
625 | #ifdef STORE
|
---|
626 | if (in_store(ml)) {
|
---|
627 | register mallink *stp = store[(size_of(ml) >> LOG_MIN_SIZE) - 1];
|
---|
628 | mallink *stp1 = NULL;
|
---|
629 | while (ml != stp) {
|
---|
630 | stp1 = stp;
|
---|
631 | stp = log_next_of(stp);
|
---|
632 | }
|
---|
633 | stp = log_next_of(stp);
|
---|
634 | if (! stp1) store[(size_of(ml) >> LOG_MIN_SIZE) - 1] = stp;
|
---|
635 | else set_log_next(stp1, stp);
|
---|
636 | set_store(ml, 0);
|
---|
637 | calc_checksum(ml);
|
---|
638 | }
|
---|
639 | #endif
|
---|
640 | if (free_of(ml)) {
|
---|
641 | unlink_free_chunk(ml);
|
---|
642 | set_free(ml, 0); /* user reallocs free block */
|
---|
643 | }
|
---|
644 | started_working_on(ml);
|
---|
645 | size = size_of(ml);
|
---|
646 | if ( /* we can simplify the problem by adding the next chunk: */
|
---|
647 | n > size &&
|
---|
648 | !last_mallink(ml) &&
|
---|
649 | (ph_next = phys_next_of(ml), free_of(ph_next)) &&
|
---|
650 | n <= size + mallink_size() + size_of(ph_next)
|
---|
651 | ) {
|
---|
652 | /* add in the physically next chunk */
|
---|
653 | unlink_free_chunk(ph_next);
|
---|
654 | combine_chunks(ml, ph_next);
|
---|
655 | size = size_of(ml);
|
---|
656 | check_mallinks("realloc, combining");
|
---|
657 | }
|
---|
658 | if (n > size) { /* this didn't help */
|
---|
659 | void *new;
|
---|
660 | register char *l1, *l2 = addr;
|
---|
661 |
|
---|
662 | stopped_working_on(ml);
|
---|
663 | if (!(new = l1 = malloc(n))) return NULL; /* no way */
|
---|
664 | while (size--) *l1++ = *l2++;
|
---|
665 | free(addr);
|
---|
666 | check_work_empty("mv_realloc");
|
---|
667 | #ifdef STORE
|
---|
668 | assert(! in_store(mallink_of_block(new)));
|
---|
669 | #endif
|
---|
670 | return new;
|
---|
671 | }
|
---|
672 | /* it helped, but maybe too well */
|
---|
673 | n += mallink_size();
|
---|
674 | if (n + MIN_SIZE <= size_of(ml)) {
|
---|
675 | truncate(ml, n);
|
---|
676 | }
|
---|
677 | stopped_working_on(ml);
|
---|
678 | check_mallinks("realloc exit");
|
---|
679 | check_work_empty("realloc");
|
---|
680 | #ifdef STORE
|
---|
681 | assert(! in_store(ml));
|
---|
682 | #endif
|
---|
683 | return addr;
|
---|
684 | }}
|
---|
685 |
|
---|
686 | void *
|
---|
687 | calloc(size_t nmemb, size_t size)
|
---|
688 | {check_mallinks("calloc entry");{
|
---|
689 | long *l1, *l2;
|
---|
690 | size_t n;
|
---|
691 |
|
---|
692 | printf("calloc\n");
|
---|
693 | if (size == 0) return NULL;
|
---|
694 | if (nmemb == 0) return NULL;
|
---|
695 |
|
---|
696 | /* Check for overflow on the multiplication. The peephole-optimizer
|
---|
697 | * will eliminate all but one of the possibilities.
|
---|
698 | */
|
---|
699 | if (sizeof(size_t) == sizeof(int)) {
|
---|
700 | if (UINT_MAX / size < nmemb) return NULL;
|
---|
701 | } else if (sizeof(size_t) == sizeof(long)) {
|
---|
702 | if (ULONG_MAX / size < nmemb) return NULL;
|
---|
703 | } else return NULL; /* can't happen, can it ? */
|
---|
704 |
|
---|
705 | n = size * nmemb;
|
---|
706 | if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
|
---|
707 | if (n >= (1L << LOG_MAX_SIZE)) return NULL;
|
---|
708 | l1 = (long *) malloc(n);
|
---|
709 | l2 = l1 + (n / sizeof(long)); /* n is at least long aligned */
|
---|
710 | while ( l2 != l1 ) *--l2 = 0;
|
---|
711 | check_mallinks("calloc exit");
|
---|
712 | check_work_empty("calloc exit");
|
---|
713 | return (void *)l1;
|
---|
714 | }}
|
---|
715 | /* Auxiliary routines */
|
---|
716 |
|
---|
717 | #ifdef STORE
|
---|
718 | private
|
---|
719 | sell_out(void) {
|
---|
720 | /* Frees all block in store.
|
---|
721 | */
|
---|
722 | register mallink **stp;
|
---|
723 |
|
---|
724 | for (stp = &store[0]; stp < &store[MAX_STORE]; stp++) {
|
---|
725 | register mallink *ml = *stp;
|
---|
726 |
|
---|
727 | while (ml) {
|
---|
728 | *stp = log_next_of(ml);
|
---|
729 | set_store(ml, 0);
|
---|
730 | do_free(ml);
|
---|
731 | ml = *stp;
|
---|
732 | }
|
---|
733 | }
|
---|
734 |
|
---|
735 | }
|
---|
736 | #endif /* STORE */
|
---|
737 |
|
---|
738 | #ifdef ASSERT
|
---|
739 | private
|
---|
740 | m_assert(const char *fn, int ln)
|
---|
741 | {
|
---|
742 | char ch;
|
---|
743 |
|
---|
744 | while (*fn)
|
---|
745 | write(2, fn++, 1);
|
---|
746 | write(2, ": malloc assert failed in line ", 31);
|
---|
747 | ch = (ln / 100) + '0'; write(2, &ch, 1); ln %= 100;
|
---|
748 | ch = (ln / 10) + '0'; write(2, &ch, 1); ln %= 10;
|
---|
749 | ch = (ln / 1) + '0'; write(2, &ch, 1);
|
---|
750 | write(2, "\n", 1);
|
---|
751 | maldump(1);
|
---|
752 | }
|
---|
753 | #endif /* ASSERT */
|
---|
754 |
|
---|
755 |
|
---|
756 | /**********************************************************/
|
---|
757 | /*
|
---|
758 | /* This was file log.c
|
---|
759 | /*
|
---|
760 | /**********************************************************/
|
---|
761 |
|
---|
762 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
763 | /*
|
---|
764 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
765 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
766 | */
|
---|
767 |
|
---|
768 | /* Logical manipulations.
|
---|
769 | The chunks are properly chained in the physical chain.
|
---|
770 | */
|
---|
771 |
|
---|
772 | privatedata mallink *free_list[MAX_FLIST];
|
---|
773 |
|
---|
774 | private
|
---|
775 | link_free_chunk(register mallink *ml)
|
---|
776 | {
|
---|
777 | /* The free chunk ml is inserted in its proper logical
|
---|
778 | chain.
|
---|
779 | */
|
---|
780 | register mallink **mlp = &free_list[-1];
|
---|
781 | register size_type n = size_of(ml);
|
---|
782 | register mallink *ml1;
|
---|
783 |
|
---|
784 | assert(n < (1L << LOG_MAX_SIZE));
|
---|
785 |
|
---|
786 | do {
|
---|
787 | n >>= 1;
|
---|
788 | mlp++;
|
---|
789 | }
|
---|
790 | while (n >= MIN_SIZE);
|
---|
791 |
|
---|
792 | ml1 = *mlp;
|
---|
793 | set_log_prev(ml, MAL_NULL);
|
---|
794 | set_log_next(ml, ml1);
|
---|
795 | calc_checksum(ml);
|
---|
796 | if (ml1) {
|
---|
797 | /* link backwards
|
---|
798 | */
|
---|
799 | set_log_prev(ml1, ml);
|
---|
800 | calc_checksum(ml1);
|
---|
801 | }
|
---|
802 | *mlp = ml;
|
---|
803 | }
|
---|
804 |
|
---|
805 | private
|
---|
806 | unlink_free_chunk(register mallink *ml)
|
---|
807 | {
|
---|
808 | /* Unlinks a free chunk from (the middle of) the
|
---|
809 | logical chain.
|
---|
810 | */
|
---|
811 | register mallink *next = log_next_of(ml);
|
---|
812 | register mallink *prev = log_prev_of(ml);
|
---|
813 |
|
---|
814 | if (!prev) {
|
---|
815 | /* it is the first in the chain */
|
---|
816 | register mallink **mlp = &free_list[-1];
|
---|
817 | register size_type n = size_of(ml);
|
---|
818 |
|
---|
819 | assert(n < (1L << LOG_MAX_SIZE));
|
---|
820 | do {
|
---|
821 | n >>= 1;
|
---|
822 | mlp++;
|
---|
823 | }
|
---|
824 | while (n >= MIN_SIZE);
|
---|
825 | *mlp = next;
|
---|
826 | }
|
---|
827 | else {
|
---|
828 | set_log_next(prev, next);
|
---|
829 | calc_checksum(prev);
|
---|
830 | }
|
---|
831 | if (next) {
|
---|
832 | set_log_prev(next, prev);
|
---|
833 | calc_checksum(next);
|
---|
834 | }
|
---|
835 | }
|
---|
836 |
|
---|
837 | private mallink *
|
---|
838 | search_free_list(int class, size_t n)
|
---|
839 | {
|
---|
840 | /* Searches the free_list[class] for a chunk of at least size n;
|
---|
841 | since it is searching a slightly undersized list,
|
---|
842 | such a block may not be there.
|
---|
843 | */
|
---|
844 | register mallink *ml;
|
---|
845 |
|
---|
846 | for (ml = free_list[class]; ml; ml = log_next_of(ml))
|
---|
847 | if (size_of(ml) >= n)
|
---|
848 | return ml;
|
---|
849 | return MAL_NULL; /* nothing found */
|
---|
850 | }
|
---|
851 |
|
---|
852 | private mallink *
|
---|
853 | first_present(int class)
|
---|
854 | {
|
---|
855 | /* Find the index i in free_list[] such that:
|
---|
856 | i >= class && free_list[i] != MAL_NULL.
|
---|
857 | Return MAL_NULL if no such i exists;
|
---|
858 | Otherwise, return the first block of this list, after
|
---|
859 | unlinking it.
|
---|
860 | */
|
---|
861 | register mallink **mlp, *ml;
|
---|
862 |
|
---|
863 | for (mlp = &free_list[class]; mlp < &free_list[MAX_FLIST]; mlp++) {
|
---|
864 | if ((ml = *mlp) != MAL_NULL) {
|
---|
865 |
|
---|
866 | *mlp = log_next_of(ml); /* may be MAL_NULL */
|
---|
867 | if (*mlp) {
|
---|
868 | /* unhook backward link
|
---|
869 | */
|
---|
870 | set_log_prev(*mlp, MAL_NULL);
|
---|
871 | calc_checksum(*mlp);
|
---|
872 | }
|
---|
873 | return ml;
|
---|
874 | }
|
---|
875 | }
|
---|
876 | return MAL_NULL;
|
---|
877 | }
|
---|
878 |
|
---|
879 | #ifdef CHECK
|
---|
880 | private mallink *
|
---|
881 | free_list_entry(int i) {
|
---|
882 | /* To allow maldump.c access to log.c's private data.
|
---|
883 | */
|
---|
884 | return free_list[i];
|
---|
885 | }
|
---|
886 | #endif /* CHECK */
|
---|
887 |
|
---|
888 |
|
---|
889 | /**********************************************************/
|
---|
890 | /*
|
---|
891 | /* This was file phys.c
|
---|
892 | /*
|
---|
893 | /**********************************************************/
|
---|
894 |
|
---|
895 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
896 | /*
|
---|
897 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
898 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
899 | */
|
---|
900 | #include <stdlib.h>
|
---|
901 |
|
---|
902 | /* Physical manipulations.
|
---|
903 | The blocks concerned are not in any logical chain.
|
---|
904 | */
|
---|
905 |
|
---|
906 | private mallink *
|
---|
907 | create_chunk(void *p, size_t n)
|
---|
908 | {
|
---|
909 | /* The newly acquired piece of memory at p, of length n,
|
---|
910 | is turned into a free chunk, properly chained in the
|
---|
911 | physical chain.
|
---|
912 | The address of the chunk is returned.
|
---|
913 | */
|
---|
914 | register mallink *ml;
|
---|
915 | /* All of malloc memory is followed by a virtual chunk, the
|
---|
916 | mallink of which starts mallink_size() bytes past the last
|
---|
917 | byte in memory.
|
---|
918 | Its use is prevented by testing for ml == ml_last first.
|
---|
919 | */
|
---|
920 | register mallink *last = ml_last;
|
---|
921 |
|
---|
922 | assert(!last || p == (char *)phys_next_of(last) - mallink_size());
|
---|
923 | ml = (mallink *)((char *)p + mallink_size()); /* bump ml */
|
---|
924 | new_mallink(ml);
|
---|
925 | started_working_on(ml);
|
---|
926 | set_free(ml, 1);
|
---|
927 | set_phys_prev(ml, last);
|
---|
928 | ml_last = ml;
|
---|
929 |
|
---|
930 | set_phys_next(ml, (mallink *)((char *)ml + n));
|
---|
931 | calc_checksum(ml);
|
---|
932 | assert(size_of(ml) + mallink_size() == n);
|
---|
933 | if (last && free_of(last)) {
|
---|
934 | coalesce_backw(ml, last);
|
---|
935 | ml = last;
|
---|
936 | }
|
---|
937 | check_mallinks("create_chunk, phys. linked");
|
---|
938 | return ml;
|
---|
939 | }
|
---|
940 |
|
---|
941 | private
|
---|
942 | truncate(register mallink *ml, size_t size)
|
---|
943 | {
|
---|
944 | /* The chunk ml is truncated.
|
---|
945 | The chunk at ml is split in two.
|
---|
946 | The remaining part is then freed.
|
---|
947 | */
|
---|
948 | register mallink *new = (mallink *)((char *)ml + size);
|
---|
949 | register mallink *ph_next = phys_next_of(ml);
|
---|
950 |
|
---|
951 | new_mallink(new);
|
---|
952 | set_free(new, 1);
|
---|
953 | set_phys_prev(new, ml);
|
---|
954 | set_phys_next(new, ph_next);
|
---|
955 | calc_checksum(new);
|
---|
956 | if (! last_mallink(ml)) {
|
---|
957 | set_phys_prev(ph_next, new);
|
---|
958 | calc_checksum(ph_next);
|
---|
959 | if (free_of(ph_next)) coalesce_forw(new, ph_next);
|
---|
960 | }
|
---|
961 | else ml_last = new;
|
---|
962 | set_phys_next(ml, new);
|
---|
963 | calc_checksum(ml);
|
---|
964 |
|
---|
965 | started_working_on(new);
|
---|
966 | link_free_chunk(new);
|
---|
967 | stopped_working_on(new);
|
---|
968 | check_mallinks("truncate");
|
---|
969 | }
|
---|
970 |
|
---|
971 | private
|
---|
972 | combine_chunks(register mallink *ml1, register mallink *ml2)
|
---|
973 | {
|
---|
974 | /* The chunks ml1 and ml2 are combined.
|
---|
975 | */
|
---|
976 | register mallink *ml3 = phys_next_of(ml2);
|
---|
977 |
|
---|
978 | set_phys_next(ml1, ml3);
|
---|
979 | calc_checksum(ml1);
|
---|
980 | if (!last_mallink(ml2)) {
|
---|
981 | set_phys_prev(ml3, ml1);
|
---|
982 | calc_checksum(ml3);
|
---|
983 | }
|
---|
984 | if (ml_last == ml2)
|
---|
985 | ml_last = ml1;
|
---|
986 | }
|
---|
987 |
|
---|
988 |
|
---|
989 | /**********************************************************/
|
---|
990 | /*
|
---|
991 | /* This was file check.c
|
---|
992 | /*
|
---|
993 | /**********************************************************/
|
---|
994 |
|
---|
995 | /* $Header: /cvsup/minix/src/commands/ash/test/malloc.c,v 1.1.1.1 2005/04/21 14:54:10 beng Exp $ */
|
---|
996 | /*
|
---|
997 | * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
---|
998 | * See the copyright notice in the ACK home directory, in the file "Copyright".
|
---|
999 | */
|
---|
1000 | #include <stdio.h>
|
---|
1001 |
|
---|
1002 | #ifdef CHECK /* otherwise this whole file is skipped */
|
---|
1003 |
|
---|
1004 | /* ??? check these later */
|
---|
1005 | private acquire_malout(void), check_ml_last(const char *s);
|
---|
1006 | private dump_all_mallinks(void), dump_free_list(int i);
|
---|
1007 | private dump_mallink(const char *s, mallink *ml), print_loop(mallink *ml);
|
---|
1008 | private working_on(mallink *ml);
|
---|
1009 | private size_type checksum(mallink *ml);
|
---|
1010 | static FILE *malout;
|
---|
1011 |
|
---|
1012 | private mallink *free_list_entry(int i);
|
---|
1013 |
|
---|
1014 | #define for_free_list(i,p) \
|
---|
1015 | for (p = free_list_entry(i); p; p = log_next_of(p))
|
---|
1016 |
|
---|
1017 | #define for_all_mallinks(ml) /* backwards! */ \
|
---|
1018 | for (ml = ml_last; ml; \
|
---|
1019 | ml = first_mallink(ml) ? MAL_NULL : phys_prev_of(ml))
|
---|
1020 |
|
---|
1021 | /* Maldump */
|
---|
1022 |
|
---|
1023 | static int pr_cnt = 0;
|
---|
1024 |
|
---|
1025 | maldump(int n) {
|
---|
1026 | /* Dump pertinent info in pseudo-readable format;
|
---|
1027 | abort afterwards if n != 0.
|
---|
1028 | */
|
---|
1029 | static int dumping = 0;
|
---|
1030 | int i;
|
---|
1031 |
|
---|
1032 | if (dumping)
|
---|
1033 | return;
|
---|
1034 | dumping++;
|
---|
1035 | acquire_malout();
|
---|
1036 | fprintf(malout,
|
---|
1037 | ">>>>>>>>>>>>>>>> DUMP OF ALL MALLINKS <<<<<<<<<<<<<<<<");
|
---|
1038 | fprintf(malout, " ml_last = %p\n", ml_last);
|
---|
1039 | if (++pr_cnt == 100) pr_cnt = 0;
|
---|
1040 | dump_all_mallinks();
|
---|
1041 | fprintf(malout,
|
---|
1042 | ">>>>>>>>>>>>>>>> DUMP OF FREE_LISTS <<<<<<<<<<<<<<<<\n");
|
---|
1043 | if (++pr_cnt == 100) pr_cnt = 0;
|
---|
1044 | for (i = 0; i < MAX_FLIST; i++)
|
---|
1045 | dump_free_list(i);
|
---|
1046 | fprintf(malout,
|
---|
1047 | ">>>>>>>>>>>>>>>> END OF DUMP <<<<<<<<<<<<<<<<\n");
|
---|
1048 | fclose(malout);
|
---|
1049 | dumping--;
|
---|
1050 | if (n)
|
---|
1051 | abort();
|
---|
1052 | }
|
---|
1053 |
|
---|
1054 | private
|
---|
1055 | acquire_malout(void) {
|
---|
1056 | static char buf[BUFSIZ];
|
---|
1057 |
|
---|
1058 | if (!malout) {
|
---|
1059 | malout = freopen("mal.out", "w", stderr);
|
---|
1060 | setbuf(malout, buf);
|
---|
1061 | }
|
---|
1062 | }
|
---|
1063 |
|
---|
1064 | private
|
---|
1065 | dump_all_mallinks(void) {
|
---|
1066 | mallink *ml;
|
---|
1067 |
|
---|
1068 | for_all_mallinks (ml) {
|
---|
1069 | if (print_loop(ml))
|
---|
1070 | return;
|
---|
1071 | dump_mallink((char *)0, ml);
|
---|
1072 | }
|
---|
1073 | }
|
---|
1074 |
|
---|
1075 | private
|
---|
1076 | dump_free_list(int i) {
|
---|
1077 | mallink *ml = free_list_entry(i);
|
---|
1078 |
|
---|
1079 | if (!ml)
|
---|
1080 | return;
|
---|
1081 | fprintf(malout, "%2d: ", i);
|
---|
1082 | for_free_list(i, ml) {
|
---|
1083 | if (print_loop(ml))
|
---|
1084 | return;
|
---|
1085 | fprintf(malout, "%p ", ml);
|
---|
1086 | }
|
---|
1087 | fprintf(malout, "<\n");
|
---|
1088 | }
|
---|
1089 |
|
---|
1090 | private int
|
---|
1091 | print_loop(mallink *ml) {
|
---|
1092 | if (print_of(ml) == pr_cnt) {
|
---|
1093 | fprintf(malout, "... PRINT LOOP\n");
|
---|
1094 | return 1;
|
---|
1095 | }
|
---|
1096 | set_print(ml, pr_cnt);
|
---|
1097 | return 0;
|
---|
1098 | }
|
---|
1099 |
|
---|
1100 | private
|
---|
1101 | dump_mallink(const char *s, mallink *ml) {
|
---|
1102 | acquire_malout();
|
---|
1103 | if (s)
|
---|
1104 | fprintf(malout, "%s: ", s);
|
---|
1105 | fprintf(malout, "@: %p;", ml);
|
---|
1106 | if (ml && checksum_of(ml) != checksum(ml))
|
---|
1107 | fprintf(malout, ">>>> CORRUPTED <<<<");
|
---|
1108 | if (!ml) {
|
---|
1109 | fprintf(malout, "\n");
|
---|
1110 | return;
|
---|
1111 | }
|
---|
1112 | if (free_of(ml)) {
|
---|
1113 | fprintf(malout, " l_p: %p;", _log_prev_of(ml));
|
---|
1114 | fprintf(malout, " l_n: %p;", _log_next_of(ml));
|
---|
1115 | }
|
---|
1116 | fprintf(malout, " p_s: %p;", prev_size_of(ml));
|
---|
1117 | fprintf(malout, " t_s: %p;", _this_size_of(ml));
|
---|
1118 | fprintf(malout, " sz: %lu;", (unsigned long) size_of(ml));
|
---|
1119 | fprintf(malout, " fr: %d;", free_of(ml));
|
---|
1120 | fprintf(malout, "\n");
|
---|
1121 | }
|
---|
1122 |
|
---|
1123 | /* Check_mallinks() checks the total data structure as accessible
|
---|
1124 | through free_list[] and ml_last. All check_sums should be OK,
|
---|
1125 | except those held in the small array off_colour. This is a
|
---|
1126 | trick to allow to continue checking even when a few mallinks
|
---|
1127 | are temporarily out of order.
|
---|
1128 | Check_mallinks() tests for a lot of internal consistency.
|
---|
1129 | */
|
---|
1130 |
|
---|
1131 | /* Some arbitrary constants */
|
---|
1132 | #define IN_ML_LAST 93
|
---|
1133 | #define IN_FREE_LIST 57 /* and in ml_last */
|
---|
1134 | #define CLEAR 21
|
---|
1135 |
|
---|
1136 | #define VRIJ 1
|
---|
1137 | #define BEZET 2
|
---|
1138 |
|
---|
1139 | private
|
---|
1140 | check_mallinks(const char *s) {
|
---|
1141 | mallink *ml;
|
---|
1142 | size_type size;
|
---|
1143 | int i;
|
---|
1144 | char stat;
|
---|
1145 |
|
---|
1146 | check_ml_last(s);
|
---|
1147 | stat = BEZET;
|
---|
1148 | for_all_mallinks(ml) {
|
---|
1149 | if (checksum_of(ml) != checksum(ml))
|
---|
1150 | Error("mallink info at %p corrupted", s, ml);
|
---|
1151 | if (working_on(ml)) {
|
---|
1152 | stat = BEZET;
|
---|
1153 | continue;
|
---|
1154 | }
|
---|
1155 | if ( !last_mallink(ml) &&
|
---|
1156 | phys_prev_of(phys_next_of(ml)) != ml
|
---|
1157 | )
|
---|
1158 | Error("upward chain bad at %p", s, ml);
|
---|
1159 | if ( !first_mallink(ml) &&
|
---|
1160 | phys_next_of(phys_prev_of(ml)) != ml
|
---|
1161 | )
|
---|
1162 | Error("downward chain bad at %p", s, ml);
|
---|
1163 | if (free_of(ml)) {
|
---|
1164 | if (stat == VRIJ)
|
---|
1165 | Error("free mallink at %p follows free mallink",
|
---|
1166 | s, ml);
|
---|
1167 | stat = VRIJ;
|
---|
1168 | }
|
---|
1169 | else
|
---|
1170 | stat = BEZET;
|
---|
1171 | set_mark(ml, IN_ML_LAST);
|
---|
1172 | }
|
---|
1173 |
|
---|
1174 | for (i = 0, size = MIN_SIZE; i < MAX_FLIST; i++, size *= 2) {
|
---|
1175 | for_free_list(i, ml) {
|
---|
1176 | if (working_on(ml))
|
---|
1177 | continue;
|
---|
1178 | if (!free_of(ml))
|
---|
1179 | Error("occupied mallink %p occurs in free_list", s, ml);
|
---|
1180 | switch (mark_of(ml)) {
|
---|
1181 | case IN_ML_LAST:
|
---|
1182 | set_mark(ml, IN_FREE_LIST);
|
---|
1183 | break;
|
---|
1184 | case IN_FREE_LIST:
|
---|
1185 | Error("mallink %p occurs in 2 free_lists",
|
---|
1186 | s, ml);
|
---|
1187 | default:
|
---|
1188 | Error("unknown mallink %p in free_list",
|
---|
1189 | s, ml);
|
---|
1190 | }
|
---|
1191 | if (size_of(ml) < size)
|
---|
1192 | Error("size of mallink %p too small", s, ml);
|
---|
1193 | if (size_of(ml) >= 2*size)
|
---|
1194 | Error("size of mallink %p too large", s, ml);
|
---|
1195 | }
|
---|
1196 | }
|
---|
1197 | for_all_mallinks (ml) {
|
---|
1198 | if (working_on(ml))
|
---|
1199 | continue;
|
---|
1200 | if (free_of(ml) && mark_of(ml) != IN_FREE_LIST)
|
---|
1201 | Error("free mallink %p is in no free_list", s, ml);
|
---|
1202 | set_mark(ml, CLEAR);
|
---|
1203 | }
|
---|
1204 | }
|
---|
1205 |
|
---|
1206 | private
|
---|
1207 | check_ml_last(const char *s) {
|
---|
1208 | if (ml_last && _this_size_of(ml_last) == 0)
|
---|
1209 | Error("size of ml_last == 0, at %p", s, ml_last);
|
---|
1210 | }
|
---|
1211 |
|
---|
1212 | private size_type
|
---|
1213 | checksum(mallink *ml) {
|
---|
1214 | size_type sum = 0;
|
---|
1215 |
|
---|
1216 | if (free_of(ml)) {
|
---|
1217 | sum += (size_type)_log_prev_of(ml);
|
---|
1218 | sum += (size_type)_log_next_of(ml);
|
---|
1219 | }
|
---|
1220 | sum += (size_type)prev_size_of(ml);
|
---|
1221 | sum += (size_type)_this_size_of(ml);
|
---|
1222 | return sum;
|
---|
1223 | }
|
---|
1224 |
|
---|
1225 | private
|
---|
1226 | calc_checksum(mallink *ml) {
|
---|
1227 | set_checksum(ml, checksum(ml));
|
---|
1228 | }
|
---|
1229 |
|
---|
1230 | #define N_COLOUR 10
|
---|
1231 | static mallink *off_colour[N_COLOUR];
|
---|
1232 |
|
---|
1233 | private
|
---|
1234 | started_working_on(mallink *ml) {
|
---|
1235 | int i;
|
---|
1236 |
|
---|
1237 | for (i = 0; i < N_COLOUR; i++)
|
---|
1238 | if (off_colour[i] == MAL_NULL) {
|
---|
1239 | off_colour[i] = ml;
|
---|
1240 | return;
|
---|
1241 | }
|
---|
1242 | Error("out of off_colour array at %p", "started_working_on", ml);
|
---|
1243 | }
|
---|
1244 |
|
---|
1245 | private
|
---|
1246 | stopped_working_on(mallink *ml) {
|
---|
1247 | int i;
|
---|
1248 |
|
---|
1249 | for (i = 0; i < N_COLOUR; i++)
|
---|
1250 | if (off_colour[i] == ml) {
|
---|
1251 | off_colour[i] = MAL_NULL;
|
---|
1252 | return;
|
---|
1253 | }
|
---|
1254 | Error("stopped working on mallink %p", "stopped_working_on", ml);
|
---|
1255 | }
|
---|
1256 |
|
---|
1257 | private int
|
---|
1258 | working_on(mallink *ml) {
|
---|
1259 | int i;
|
---|
1260 |
|
---|
1261 | for (i = 0; i < N_COLOUR; i++)
|
---|
1262 | if (off_colour[i] == ml)
|
---|
1263 | return 1;
|
---|
1264 | return 0;
|
---|
1265 | }
|
---|
1266 |
|
---|
1267 | private
|
---|
1268 | check_work_empty(const char *s) {
|
---|
1269 | int i;
|
---|
1270 | int cnt = 0;
|
---|
1271 |
|
---|
1272 | for (i = 0; i < N_COLOUR; i++)
|
---|
1273 | if (off_colour[i] != MAL_NULL)
|
---|
1274 | cnt++;
|
---|
1275 | if (cnt != 0)
|
---|
1276 | Error("off_colour not empty", s, MAL_NULL);
|
---|
1277 | }
|
---|
1278 |
|
---|
1279 | private int
|
---|
1280 | Error(const char *fmt, const char *s, mallink *ml) {
|
---|
1281 | static int already_called = 0;
|
---|
1282 |
|
---|
1283 | if (already_called++) return 0;
|
---|
1284 | setbuf(stdout, (char *) 0);
|
---|
1285 | printf("%s: ", s);
|
---|
1286 | printf(fmt, (long)ml);
|
---|
1287 | printf("\n");
|
---|
1288 | acquire_malout();
|
---|
1289 | fprintf(malout, "%s: ", s);
|
---|
1290 | fprintf(malout, fmt, (long)ml);
|
---|
1291 | fprintf(malout, "\n");
|
---|
1292 | fflush(stdout);
|
---|
1293 | maldump(1);
|
---|
1294 | return 0; /* to satisfy lint */
|
---|
1295 | }
|
---|
1296 |
|
---|
1297 | #endif /* CHECK */
|
---|
1298 |
|
---|