2 /**********************************************************/
4 /* This was file READ_ME
6 /**********************************************************/
10 malloc(), free(), realloc()
12 Dick Grune, Free University, Amsterdam
13 Modified by Ceriel Jacobs, Free University, Amsterdam,
16 $Id: READ_ME,v 1.2 1994/06/24 11:55:09 ceriel Exp $
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.
25 If you switch on the NON_STANDARD macro (see param.h) every block
26 costs 2 pointers overhead (otherwise it's 4).
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
37 /**********************************************************/
39 /* This was file size_type.h
41 /**********************************************************/
43 #if _EM_WSIZE == _EM_PSIZE
44 typedef unsigned int size_type;
45 #elif _EM_LSIZE == _EM_PSIZE
46 typedef unsigned long size_type;
48 #error funny pointer size
53 /**********************************************************/
55 /* This was file param.h
57 /**********************************************************/
59 /* $Id: param.h,v 1.2 1994/06/24 11:55:32 ceriel Exp $ */
61 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
62 * See the copyright notice in the ACK home directory, in the file "Copyright".
65 # define NON_STANDARD /* If defined, the contents of a block
66 will NOT be left undisturbed after it
67 is freed, as opposed to what it says
68 in the manual (malloc(2)).
69 Setting this option reduces the memory
70 overhead considerably. I personally
71 consider the specified behaviour an
72 artefact of the original
76 # undef ASSERT /* If defined, some inexpensive tests
77 will be made to ensure the
78 correctness of some sensitive data.
79 It often turns an uncontrolled crash
80 into a controlled one.
83 # undef CHECK /* If defined, extensive and expensive
84 tests will be done, inculding a
85 checksum on the mallinks (chunk
86 information blocks). The resulting
87 information will be printed on a file
89 Additionally a function
91 will be defined, which will dump
92 pertinent info in pseudo-readable
93 form; it aborts afterwards if n != 0.
96 # undef EXTERN /* If defined, all static names will
97 become extern, which is a help in
98 using adb(1) or prof(1)
101 # define STORE /* If defined, separate free lists will
102 be kept of chunks with small sizes,
103 to speed things up a little.
106 # undef SYSTEM /* If defined, the system module is used.
107 Otherwise, "sbrk" is called directly.
111 /* alignment common to all types */
112 #define LOG_MIN_SIZE 3
113 #define LOG_MAX_SIZE 24
116 /**********************************************************/
118 /* This was file impl.h
120 /**********************************************************/
122 /* $Id: impl.h,v 1.3 1994/06/24 11:55:21 ceriel Exp $ */
124 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
125 * See the copyright notice in the ACK home directory, in the file "Copyright".
127 /* This file essentially describes how the mallink info block
131 #define MIN_SIZE (1<<LOG_MIN_SIZE)
132 #define MAX_FLIST (LOG_MAX_SIZE - LOG_MIN_SIZE)
133 #if ALIGNMENT != 4 && ALIGNMENT != 8 && ALIGNMENT != 16
134 #error ALIGNMENT must be 4, 8 or 16
135 #elif ALIGNMENT % _EM_LSIZE
136 /* since calloc() does it's initialization in longs */
137 #error ALIGNMENT must be a multiple of the long size
139 #define align(n) (((n) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))
146 typedef union _inf mallink;
147 #define MAL_NULL ((mallink *)0)
149 /* Access macros; only these macros know where to find values.
150 They are also lvalues.
154 #else /* def NON_STANDARD */
156 #endif /* NON_STANDARD */
158 #define _log_prev_of(ml) ((ml)[-1+OFF_SET]).ptr
159 #define _log_next_of(ml) ((ml)[-2+OFF_SET]).ptr
160 #define _phys_prev_of(ml) ((ml)[-3+OFF_SET]).ptr
161 #define _this_size_of(ml) ((ml)[-4+OFF_SET]).ui
164 #else /* ifdef CHECK */
165 #define _checksum_of(ml) ((ml)[-5+OFF_SET]).ui
166 #define _print_of(ml) ((ml)[-6+OFF_SET]).ui
167 #define _mark_of(ml) ((ml)[-7+OFF_SET]).ui
171 #define mallink_size() (size_t) \
172 align((N_WORDS - OFF_SET) * sizeof (mallink))
175 #define set_mark(ml,e) (_mark_of(ml) = (e))
176 #define mark_of(ml) (_mark_of(ml))
178 #define set_checksum(ml,e) (_checksum_of(ml) = (e))
179 #define checksum_of(ml) (_checksum_of(ml))
182 #define new_mallink(ml) ( _log_prev_of(ml) = 0, \
183 _log_next_of(ml) = 0, \
184 _phys_prev_of(ml) = 0, \
185 _this_size_of(ml) = 0 )
187 #define block_of_mallink(ml) ((void *)ml)
188 #define mallink_of_block(addr) ((mallink *)addr)
190 #define public extern
191 #define publicdata extern
193 #define private static
194 #define privatedata static
195 #else /* def EXTERN */
196 #define private extern
201 private m_assert(const char *fn, int ln);
202 #define assert(b) (!(b) ? m_assert(__FILE__, __LINE__) : 0)
203 #else /* ndef ASSERT */
208 /**********************************************************/
210 /* This was file check.h
212 /**********************************************************/
214 /* $Id: check.h,v 1.2 1994/06/24 11:55:15 ceriel Exp $ */
216 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
217 * See the copyright notice in the ACK home directory, in the file "Copyright".
221 private check_mallinks(const char *s), calc_checksum(mallink *ml);
222 private check_work_empty(const char *s);
223 private started_working_on(mallink *ml), stopped_working_on(mallink *ml);
225 #else /* ifndef CHECK */
227 #define maldump(n) abort()
228 #define check_mallinks(s) 0
229 #define calc_checksum(ml) 0
230 #define started_working_on(ml) 0
231 #define stopped_working_on(ml) 0
232 #define check_work_empty(s) 0
237 /**********************************************************/
239 /* This was file log.h
241 /**********************************************************/
243 /* $Id: log.h,v 1.2 1994/06/24 11:55:26 ceriel Exp $ */
245 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
246 * See the copyright notice in the ACK home directory, in the file "Copyright".
248 /* Algorithms to manipulate the doubly-linked lists of free
252 private link_free_chunk(mallink *ml), unlink_free_chunk(mallink *ml);
253 private mallink *first_present(int class);
254 private mallink *search_free_list(int class, size_t n);
257 #define in_store(ml) ((size_type)_phys_prev_of(ml) & STORE_BIT)
258 #define set_store(ml, e) \
259 (_phys_prev_of(ml) = (mallink *) \
260 ((e) ? (size_type) _phys_prev_of(ml) | STORE_BIT : \
261 (size_type) _phys_prev_of(ml) & ~STORE_BIT))
263 #define set_log_prev(ml,e) (_log_prev_of(ml) = (e))
264 #define log_prev_of(ml) (mallink *) (_log_prev_of(ml))
266 #define set_log_next(ml,e) (_log_next_of(ml) = (e))
267 #define log_next_of(ml) (mallink *) (_log_next_of(ml))
271 /**********************************************************/
273 /* This was file phys.h
275 /**********************************************************/
277 /* $Id: phys.h,v 1.4 1994/06/24 11:55:38 ceriel Exp $ */
279 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
280 * See the copyright notice in the ACK home directory, in the file "Copyright".
282 /* Algorithms to manipulate the doubly-linked list of physical
285 privatedata mallink *ml_last;
290 #define BITS (FREE_BIT|STORE_BIT)
292 #define BITS (FREE_BIT)
295 #define __bits(ml) ((int)((size_type)_phys_prev_of(ml) & BITS))
296 #define __free_of(ml) ((int)((size_type)_phys_prev_of(ml) & FREE_BIT))
297 #define __phys_prev_of(ml) ((mallink *)((size_type)_phys_prev_of(ml) & ~BITS))
298 #define prev_size_of(ml) ((char *)(ml) - \
299 (char *)__phys_prev_of(ml) - \
302 #define set_phys_prev(ml,e) \
303 (_phys_prev_of(ml) = (mallink *) ((char *)e + __bits(ml)))
306 private Error(const char *fmt, const char *s, mallink *ml);
307 #define phys_prev_of(ml) (mallink *) \
308 (first_mallink(ml) ? \
309 (char *)Error("phys_prev_of first_mallink %p", "somewhere", ml) : \
310 (char *)__phys_prev_of(ml) \
312 #else /* ndef CHECK */
313 #define phys_prev_of(ml) __phys_prev_of(ml)
316 #define first_mallink(ml) (int) (__phys_prev_of(ml) == 0)
317 #define last_mallink(ml) (int) ((ml) == ml_last)
319 /* There is an ambiguity in the semantics of phys_next_of: sometimes
320 one wants it to return MAL_NULL if there is no next chunk, at
321 other times one wants the address of the virtual chunk at the
322 end of memory. The present version returns the address of the
323 (virtual) chunk and relies on the user to test last_mallink(ml)
326 #define size_of(ml) (_this_size_of(ml) - mallink_size())
327 #define set_phys_next(ml,e) \
328 (_this_size_of(ml) = (size_type)((char *)(e) - (char *)(ml)))
329 #define phys_next_of(ml) (mallink *) ((char *)(ml) + _this_size_of(ml))
331 #define set_free(ml,e) \
332 (_phys_prev_of(ml) = (mallink *) \
333 ((e) ? (size_type) _phys_prev_of(ml) | FREE_BIT : \
334 (size_type) _phys_prev_of(ml) & ~FREE_BIT))
335 #define free_of(ml) (__free_of(ml))
337 #define coalesce_forw(ml,nxt) ( unlink_free_chunk(nxt), \
338 combine_chunks((ml), (nxt)))
340 #define coalesce_backw(ml,prv) ( unlink_free_chunk(prv), \
341 stopped_working_on(ml), \
342 combine_chunks((prv), (ml)), \
343 started_working_on(prv))
346 #define set_print(ml,e) (_print_of(ml) = (e))
347 #define print_of(ml) (_print_of(ml))
350 private truncate(mallink *ml, size_t size);
351 private combine_chunks(register mallink *ml1, register mallink *ml2);
352 private mallink *create_chunk(void *p, size_t n);
355 /**********************************************************/
357 /* This was file mal.c
359 /**********************************************************/
361 /* $Id: mal.c,v 1.5 1994/06/24 11:55:29 ceriel Exp $ */
363 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
364 * See the copyright notice in the ACK home directory, in the file "Copyright".
369 /* Malloc space is traversed by N doubly-linked lists of chunks, each
370 containing a couple of house-keeping data addressed as a
371 'mallink' and a piece of useful space, called the block.
372 The N lists are accessed through their starting pointers in
373 free_list[]. Free_list[n] points to a list of chunks between
374 2**(n+LOG_MIN_SIZE) and 2**(n+LOG_MIN_SIZE+1)-1, which means
375 that the smallest chunk is 2**LOG_MIN_SIZE (== MIN_SIZE).
380 #define SBRK sys_break
383 #define ILL_BREAK (void *)(-1) /* funny failure value */
385 extern void *SBRK(int incr);
388 private do_free(mallink *ml), sell_out(void);
389 privatedata mallink *store[MAX_STORE];
393 malloc(register size_t n)
394 {check_mallinks("malloc entry");{
395 register mallink *ml;
396 register int min_class;
401 if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
403 if (n <= MAX_STORE*MIN_SIZE) {
404 /* look in the store first */
405 register mallink **stp = &store[(n >> LOG_MIN_SIZE) - 1];
408 *stp = log_next_of(ml);
410 check_mallinks("malloc fast exit");
411 assert(! in_store(ml));
412 return block_of_mallink(ml);
417 check_work_empty("malloc, entry");
419 /* Acquire a chunk of at least size n if at all possible;
423 /* Inline substitution of "smallest".
425 register size_t n1 = n;
427 assert(n1 < (1L << LOG_MAX_SIZE));
433 } while (n1 >= MIN_SIZE);
436 if (min_class >= MAX_FLIST)
437 return NULL; /* we don't deal in blocks that big */
438 ml = first_present(min_class);
439 if (ml == MAL_NULL) {
442 #define GRABSIZE 4096 /* Power of 2 */
443 register size_t req =
444 ((MIN_SIZE<<min_class)+ mallink_size() + GRABSIZE - 1) &
448 /* first align SBRK() */
451 SBRK((int) (align((size_type) p) - (size_type) p));
454 /* SBRK takes an int; sorry ... */
460 if (p == ILL_BREAK) {
461 req = n + mallink_size();
462 if ((int) req >= 0) p = SBRK((int)req);
464 if (p == ILL_BREAK) {
465 /* Now this is bad. The system will not give us
466 more memory. We can only liquidate our store
471 ml = first_present(min_class);
472 if (ml == MAL_NULL) {
474 /* In this emergency we try to locate a suitable
475 chunk in the free_list just below the safe
476 one; some of these chunks may fit the job.
478 ml = search_free_list(min_class - 1, n);
479 if (!ml) /* really out of space */
481 started_working_on(ml);
482 unlink_free_chunk(ml);
483 check_mallinks("suitable_chunk, forced");
486 else started_working_on(ml);
490 assert((size_type)p == align((size_type)p));
491 ml = create_chunk(p, req);
493 check_mallinks("suitable_chunk, extended");
495 else started_working_on(ml);
497 /* we have a chunk */
500 check_mallinks("suitable_chunk, removed");
502 if (n + MIN_SIZE <= size_of(ml)) {
505 stopped_working_on(ml);
506 check_mallinks("malloc exit");
507 check_work_empty("malloc exit");
509 assert(! in_store(ml));
511 return block_of_mallink(ml);
516 {check_mallinks("free entry");{
517 register mallink *ml;
520 check_mallinks("free(0) very fast exit");
524 ml = mallink_of_block(addr);
527 if (free_of(ml) || in_store(ml))
528 return; /* user frees free block */
529 if (size_of(ml) <= MAX_STORE*MIN_SIZE) {
530 /* return to store */
531 mallink **stp = &store[(size_of(ml) >> LOG_MIN_SIZE) - 1];
533 set_log_next(ml, *stp);
537 check_mallinks("free fast exit");
541 check_mallinks("free exit");
546 do_free(register mallink *ml)
551 if (free_of(ml)) return;
553 started_working_on(ml);
556 if (! last_mallink(ml)) {
557 register mallink *next = phys_next_of(ml);
559 if (free_of(next)) coalesce_forw(ml, next);
562 if (! first_mallink(ml)) {
563 register mallink *prev = phys_prev_of(ml);
566 coalesce_backw(ml, prev);
571 stopped_working_on(ml);
572 check_work_empty("free");
574 /* Compile-time checks on param.h */
576 case MIN_SIZE < OFF_SET * sizeof(mallink): break;
578 /* If this statement does not compile due to duplicate case
579 entry, the minimum size block cannot hold the links for
580 the free blocks. Either raise LOG_MIN_SIZE or switch
585 case sizeof(void *) != sizeof(size_type): break;
587 /* If this statement does not compile due to duplicate
588 case entry, size_type is not defined correctly.
589 Redefine and compile again.
595 realloc(void *addr, register size_t n)
596 {check_mallinks("realloc entry");{
597 register mallink *ml, *ph_next;
598 register size_type size;
601 /* Behave like most Unix realloc's when handed a
610 ml = mallink_of_block(addr);
611 if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
614 register mallink *stp = store[(size_of(ml) >> LOG_MIN_SIZE) - 1];
615 mallink *stp1 = NULL;
618 stp = log_next_of(stp);
620 stp = log_next_of(stp);
621 if (! stp1) store[(size_of(ml) >> LOG_MIN_SIZE) - 1] = stp;
622 else set_log_next(stp1, stp);
628 unlink_free_chunk(ml);
629 set_free(ml, 0); /* user reallocs free block */
631 started_working_on(ml);
633 if ( /* we can simplify the problem by adding the next chunk: */
636 (ph_next = phys_next_of(ml), free_of(ph_next)) &&
637 n <= size + mallink_size() + size_of(ph_next)
639 /* add in the physically next chunk */
640 unlink_free_chunk(ph_next);
641 combine_chunks(ml, ph_next);
643 check_mallinks("realloc, combining");
645 if (n > size) { /* this didn't help */
647 register char *l1, *l2 = addr;
649 stopped_working_on(ml);
650 if (!(new = l1 = malloc(n))) return NULL; /* no way */
651 while (size--) *l1++ = *l2++;
653 check_work_empty("mv_realloc");
655 assert(! in_store(mallink_of_block(new)));
659 /* it helped, but maybe too well */
661 if (n + MIN_SIZE <= size_of(ml)) {
664 stopped_working_on(ml);
665 check_mallinks("realloc exit");
666 check_work_empty("realloc");
668 assert(! in_store(ml));
674 calloc(size_t nmemb, size_t size)
675 {check_mallinks("calloc entry");{
679 if (size == 0) return NULL;
680 if (nmemb == 0) return NULL;
682 /* Check for overflow on the multiplication. The peephole-optimizer
683 * will eliminate all but one of the possibilities.
685 if (sizeof(size_t) == sizeof(int)) {
686 if (UINT_MAX / size < nmemb) return NULL;
687 } else if (sizeof(size_t) == sizeof(long)) {
688 if (ULONG_MAX / size < nmemb) return NULL;
689 } else return NULL; /* can't happen, can it ? */
692 if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
693 if (n >= (1L << LOG_MAX_SIZE)) return NULL;
694 l1 = (long *) malloc(n);
695 l2 = l1 + (n / sizeof(long)); /* n is at least long aligned */
696 while ( l2 != l1 ) *--l2 = 0;
697 check_mallinks("calloc exit");
698 check_work_empty("calloc exit");
701 /* Auxiliary routines */
706 /* Frees all block in store.
708 register mallink **stp;
710 for (stp = &store[0]; stp < &store[MAX_STORE]; stp++) {
711 register mallink *ml = *stp;
714 *stp = log_next_of(ml);
726 m_assert(const char *fn, int ln)
732 write(2, ": malloc assert failed in line ", 31);
733 ch = (ln / 100) + '0'; write(2, &ch, 1); ln %= 100;
734 ch = (ln / 10) + '0'; write(2, &ch, 1); ln %= 10;
735 ch = (ln / 1) + '0'; write(2, &ch, 1);
742 /**********************************************************/
744 /* This was file log.c
746 /**********************************************************/
748 /* $Id: log.c,v 1.4 1994/06/24 11:55:23 ceriel Exp $ */
750 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
751 * See the copyright notice in the ACK home directory, in the file "Copyright".
754 /* Logical manipulations.
755 The chunks are properly chained in the physical chain.
758 privatedata mallink *free_list[MAX_FLIST+1];
761 link_free_chunk(register mallink *ml)
763 /* The free chunk ml is inserted in its proper logical
766 register mallink **mlp = &free_list[0];
767 register size_type n = size_of(ml);
768 register mallink *ml1;
770 assert(n < (1L << LOG_MAX_SIZE));
776 while (n >= MIN_SIZE);
779 set_log_prev(ml, MAL_NULL);
780 set_log_next(ml, ml1);
785 set_log_prev(ml1, ml);
792 unlink_free_chunk(register mallink *ml)
794 /* Unlinks a free chunk from (the middle of) the
797 register mallink *next = log_next_of(ml);
798 register mallink *prev = log_prev_of(ml);
801 /* it is the first in the chain */
802 register mallink **mlp = &free_list[-1];
803 register size_type n = size_of(ml);
805 assert(n < (1L << LOG_MAX_SIZE));
810 while (n >= MIN_SIZE);
814 set_log_next(prev, next);
818 set_log_prev(next, prev);
824 search_free_list(int class, size_t n)
826 /* Searches the free_list[class] for a chunk of at least size n;
827 since it is searching a slightly undersized list,
828 such a block may not be there.
830 register mallink *ml;
832 for (ml = free_list[class]; ml; ml = log_next_of(ml))
833 if (size_of(ml) >= n)
835 return MAL_NULL; /* nothing found */
839 first_present(int class)
841 /* Find the index i in free_list[] such that:
842 i >= class && free_list[i] != MAL_NULL.
843 Return MAL_NULL if no such i exists;
844 Otherwise, return the first block of this list, after
847 register mallink **mlp, *ml;
849 for (mlp = &free_list[class]; mlp < &free_list[MAX_FLIST]; mlp++) {
850 if ((ml = *mlp) != MAL_NULL) {
852 *mlp = log_next_of(ml); /* may be MAL_NULL */
854 /* unhook backward link
856 set_log_prev(*mlp, MAL_NULL);
867 free_list_entry(int i) {
868 /* To allow maldump.c access to log.c's private data.
875 /**********************************************************/
877 /* This was file phys.c
879 /**********************************************************/
881 /* $Id: phys.c,v 1.2 1994/06/24 11:55:35 ceriel Exp $ */
883 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
884 * See the copyright notice in the ACK home directory, in the file "Copyright".
888 /* Physical manipulations.
889 The blocks concerned are not in any logical chain.
893 create_chunk(void *p, size_t n)
895 /* The newly acquired piece of memory at p, of length n,
896 is turned into a free chunk, properly chained in the
898 The address of the chunk is returned.
900 register mallink *ml;
901 /* All of malloc memory is followed by a virtual chunk, the
902 mallink of which starts mallink_size() bytes past the last
904 Its use is prevented by testing for ml == ml_last first.
906 register mallink *last = ml_last;
908 assert(!last || p == (char *)phys_next_of(last) - mallink_size());
909 ml = (mallink *)((char *)p + mallink_size()); /* bump ml */
911 started_working_on(ml);
913 set_phys_prev(ml, last);
916 set_phys_next(ml, (mallink *)((char *)ml + n));
918 assert(size_of(ml) + mallink_size() == n);
919 if (last && free_of(last)) {
920 coalesce_backw(ml, last);
923 check_mallinks("create_chunk, phys. linked");
928 truncate(register mallink *ml, size_t size)
930 /* The chunk ml is truncated.
931 The chunk at ml is split in two.
932 The remaining part is then freed.
934 register mallink *new = (mallink *)((char *)ml + size);
935 register mallink *ph_next = phys_next_of(ml);
939 set_phys_prev(new, ml);
940 set_phys_next(new, ph_next);
942 if (! last_mallink(ml)) {
943 set_phys_prev(ph_next, new);
944 calc_checksum(ph_next);
945 if (free_of(ph_next)) coalesce_forw(new, ph_next);
948 set_phys_next(ml, new);
951 started_working_on(new);
952 link_free_chunk(new);
953 stopped_working_on(new);
954 check_mallinks("truncate");
958 combine_chunks(register mallink *ml1, register mallink *ml2)
960 /* The chunks ml1 and ml2 are combined.
962 register mallink *ml3 = phys_next_of(ml2);
964 set_phys_next(ml1, ml3);
966 if (!last_mallink(ml2)) {
967 set_phys_prev(ml3, ml1);
975 /**********************************************************/
977 /* This was file check.c
979 /**********************************************************/
981 /* $Id: check.c,v 1.4 1994/06/24 11:55:12 ceriel Exp $ */
983 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
984 * See the copyright notice in the ACK home directory, in the file "Copyright".
988 #ifdef CHECK /* otherwise this whole file is skipped */
990 /* ??? check these later */
991 private acquire_malout(void), check_ml_last(const char *s);
992 private dump_all_mallinks(void), dump_free_list(int i);
993 private dump_mallink(const char *s, mallink *ml), print_loop(mallink *ml);
994 private working_on(mallink *ml);
995 private size_type checksum(mallink *ml);
998 private mallink *free_list_entry(int i);
1000 #define for_free_list(i,p) \
1001 for (p = free_list_entry(i); p; p = log_next_of(p))
1003 #define for_all_mallinks(ml) /* backwards! */ \
1004 for (ml = ml_last; ml; \
1005 ml = first_mallink(ml) ? MAL_NULL : phys_prev_of(ml))
1009 static int pr_cnt = 0;
1012 /* Dump pertinent info in pseudo-readable format;
1013 abort afterwards if n != 0.
1015 static int dumping = 0;
1023 ">>>>>>>>>>>>>>>> DUMP OF ALL MALLINKS <<<<<<<<<<<<<<<<");
1024 fprintf(malout, " ml_last = %p\n", ml_last);
1025 if (++pr_cnt == 100) pr_cnt = 0;
1026 dump_all_mallinks();
1028 ">>>>>>>>>>>>>>>> DUMP OF FREE_LISTS <<<<<<<<<<<<<<<<\n");
1029 if (++pr_cnt == 100) pr_cnt = 0;
1030 for (i = 0; i < MAX_FLIST; i++)
1033 ">>>>>>>>>>>>>>>> END OF DUMP <<<<<<<<<<<<<<<<\n");
1041 acquire_malout(void) {
1042 static char buf[BUFSIZ];
1045 malout = freopen("mal.out", "w", stderr);
1046 setbuf(malout, buf);
1051 dump_all_mallinks(void) {
1054 for_all_mallinks (ml) {
1057 dump_mallink((char *)0, ml);
1062 dump_free_list(int i) {
1063 mallink *ml = free_list_entry(i);
1067 fprintf(malout, "%2d: ", i);
1068 for_free_list(i, ml) {
1071 fprintf(malout, "%p ", ml);
1073 fprintf(malout, "<\n");
1077 print_loop(mallink *ml) {
1078 if (print_of(ml) == pr_cnt) {
1079 fprintf(malout, "... PRINT LOOP\n");
1082 set_print(ml, pr_cnt);
1087 dump_mallink(const char *s, mallink *ml) {
1090 fprintf(malout, "%s: ", s);
1091 fprintf(malout, "@: %p;", ml);
1092 if (ml && checksum_of(ml) != checksum(ml))
1093 fprintf(malout, ">>>> CORRUPTED <<<<");
1095 fprintf(malout, "\n");
1099 fprintf(malout, " l_p: %p;", _log_prev_of(ml));
1100 fprintf(malout, " l_n: %p;", _log_next_of(ml));
1102 fprintf(malout, " p_s: %p;", prev_size_of(ml));
1103 fprintf(malout, " t_s: %p;", _this_size_of(ml));
1104 fprintf(malout, " sz: %lu;", (unsigned long) size_of(ml));
1105 fprintf(malout, " fr: %d;", free_of(ml));
1106 fprintf(malout, "\n");
1109 /* Check_mallinks() checks the total data structure as accessible
1110 through free_list[] and ml_last. All check_sums should be OK,
1111 except those held in the small array off_colour. This is a
1112 trick to allow to continue checking even when a few mallinks
1113 are temporarily out of order.
1114 Check_mallinks() tests for a lot of internal consistency.
1117 /* Some arbitrary constants */
1118 #define IN_ML_LAST 93
1119 #define IN_FREE_LIST 57 /* and in ml_last */
1126 check_mallinks(const char *s) {
1134 for_all_mallinks(ml) {
1135 if (checksum_of(ml) != checksum(ml))
1136 Error("mallink info at %p corrupted", s, ml);
1137 if (working_on(ml)) {
1141 if ( !last_mallink(ml) &&
1142 phys_prev_of(phys_next_of(ml)) != ml
1144 Error("upward chain bad at %p", s, ml);
1145 if ( !first_mallink(ml) &&
1146 phys_next_of(phys_prev_of(ml)) != ml
1148 Error("downward chain bad at %p", s, ml);
1151 Error("free mallink at %p follows free mallink",
1157 set_mark(ml, IN_ML_LAST);
1160 for (i = 0, size = MIN_SIZE; i < MAX_FLIST; i++, size *= 2) {
1161 for_free_list(i, ml) {
1165 Error("occupied mallink %p occurs in free_list", s, ml);
1166 switch (mark_of(ml)) {
1168 set_mark(ml, IN_FREE_LIST);
1171 Error("mallink %p occurs in 2 free_lists",
1174 Error("unknown mallink %p in free_list",
1177 if (size_of(ml) < size)
1178 Error("size of mallink %p too small", s, ml);
1179 if (size_of(ml) >= 2*size)
1180 Error("size of mallink %p too large", s, ml);
1183 for_all_mallinks (ml) {
1186 if (free_of(ml) && mark_of(ml) != IN_FREE_LIST)
1187 Error("free mallink %p is in no free_list", s, ml);
1188 set_mark(ml, CLEAR);
1193 check_ml_last(const char *s) {
1194 if (ml_last && _this_size_of(ml_last) == 0)
1195 Error("size of ml_last == 0, at %p", s, ml_last);
1199 checksum(mallink *ml) {
1203 sum += (size_type)_log_prev_of(ml);
1204 sum += (size_type)_log_next_of(ml);
1206 sum += (size_type)prev_size_of(ml);
1207 sum += (size_type)_this_size_of(ml);
1212 calc_checksum(mallink *ml) {
1213 set_checksum(ml, checksum(ml));
1217 static mallink *off_colour[N_COLOUR];
1220 started_working_on(mallink *ml) {
1223 for (i = 0; i < N_COLOUR; i++)
1224 if (off_colour[i] == MAL_NULL) {
1228 Error("out of off_colour array at %p", "started_working_on", ml);
1232 stopped_working_on(mallink *ml) {
1235 for (i = 0; i < N_COLOUR; i++)
1236 if (off_colour[i] == ml) {
1237 off_colour[i] = MAL_NULL;
1240 Error("stopped working on mallink %p", "stopped_working_on", ml);
1244 working_on(mallink *ml) {
1247 for (i = 0; i < N_COLOUR; i++)
1248 if (off_colour[i] == ml)
1254 check_work_empty(const char *s) {
1258 for (i = 0; i < N_COLOUR; i++)
1259 if (off_colour[i] != MAL_NULL)
1262 Error("off_colour not empty", s, MAL_NULL);
1266 Error(const char *fmt, const char *s, mallink *ml) {
1267 static int already_called = 0;
1269 if (already_called++) return 0;
1270 setbuf(stdout, (char *) 0);
1272 printf(fmt, (long)ml);
1275 fprintf(malout, "%s: ", s);
1276 fprintf(malout, fmt, (long)ml);
1277 fprintf(malout, "\n");
1280 return 0; /* to satisfy lint */