OSDN Git Service

* os_dep.c: glibc 2.1 requires asm/sigcontext.h, not
[pf3gnuchains/gcc-fork.git] / boehm-gc / reclaim.c
1 /* 
2  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
4  *
5  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
6  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
7  *
8  * Permission is hereby granted to use or copy this program
9  * for any purpose,  provided the above notices are retained on all copies.
10  * Permission to modify the code and to distribute modified code is granted,
11  * provided the above notices are retained, and a notice that the code was
12  * modified is included with the above copyright notice.
13  */
14 /* Boehm, February 15, 1996 2:41 pm PST */
15
16 #include <stdio.h>
17 #include "gc_priv.h"
18
19 signed_word GC_mem_found = 0;
20                         /* Number of words of memory reclaimed     */
21
22 # ifdef FIND_LEAK
23 static void report_leak(p, sz)
24 ptr_t p;
25 word sz;
26 {
27     if (HDR(p) -> hb_obj_kind == PTRFREE) {
28         GC_err_printf0("Leaked atomic object at ");
29     } else {
30         GC_err_printf0("Leaked composite object at ");
31     }
32     if (GC_debugging_started && GC_has_debug_info(p)) {
33         GC_print_obj(p);
34     } else {
35         GC_err_printf2("0x%lx (appr. size = %ld)\n",
36                       (unsigned long)p,
37                       (unsigned long)WORDS_TO_BYTES(sz));
38     }
39 }
40
41 #   define FOUND_FREE(hblk, word_no) \
42       if (abort_if_found) { \
43          report_leak((ptr_t)hblk + WORDS_TO_BYTES(word_no), \
44                      HDR(hblk) -> hb_sz); \
45       }
46 # else
47 #   define FOUND_FREE(hblk, word_no)
48 # endif
49
50 /*
51  * reclaim phase
52  *
53  */
54
55
56 /*
57  * Test whether a block is completely empty, i.e. contains no marked
58  * objects.  This does not require the block to be in physical
59  * memory.
60  */
61  
62 GC_bool GC_block_empty(hhdr)
63 register hdr * hhdr;
64 {
65     register word *p = (word *)(&(hhdr -> hb_marks[0]));
66     register word * plim =
67                         (word *)(&(hhdr -> hb_marks[MARK_BITS_SZ]));
68     while (p < plim) {
69         if (*p++) return(FALSE);
70     }
71     return(TRUE);
72 }
73
74 # ifdef GATHERSTATS
75 #   define INCR_WORDS(sz) n_words_found += (sz)
76 # else
77 #   define INCR_WORDS(sz)
78 # endif
79 /*
80  * Restore unmarked small objects in h of size sz to the object
81  * free list.  Returns the new list.
82  * Clears unmarked objects.
83  */
84 /*ARGSUSED*/
85 ptr_t GC_reclaim_clear(hbp, hhdr, sz, list, abort_if_found)
86 register struct hblk *hbp;      /* ptr to current heap block            */
87 register hdr * hhdr;
88 GC_bool abort_if_found;         /* Abort if a reclaimable object is found */
89 register ptr_t list;
90 register word sz;
91 {
92     register int word_no;
93     register word *p, *q, *plim;
94 #   ifdef GATHERSTATS
95         register int n_words_found = 0;
96 #   endif        
97     
98     p = (word *)(hbp->hb_body);
99     word_no = HDR_WORDS;
100     plim = (word *)((((word)hbp) + HBLKSIZE)
101                    - WORDS_TO_BYTES(sz));
102
103     /* go through all words in block */
104         while( p <= plim )  {
105             if( mark_bit_from_hdr(hhdr, word_no) ) {
106                 p += sz;
107             } else {
108                 FOUND_FREE(hbp, word_no);
109                 INCR_WORDS(sz);
110                 /* object is available - put on list */
111                     obj_link(p) = list;
112                     list = ((ptr_t)p);
113                 /* Clear object, advance p to next object in the process */
114                     q = p + sz;
115                     p++; /* Skip link field */
116                     while (p < q) {
117                         *p++ = 0;
118                     }
119             }
120             word_no += sz;
121         }
122 #   ifdef GATHERSTATS
123         GC_mem_found += n_words_found;
124 #   endif
125     return(list);
126 }
127
128 #ifndef SMALL_CONFIG
129
130 /*
131  * A special case for 2 word composite objects (e.g. cons cells):
132  */
133 /*ARGSUSED*/
134 ptr_t GC_reclaim_clear2(hbp, hhdr, list, abort_if_found)
135 register struct hblk *hbp;      /* ptr to current heap block            */
136 hdr * hhdr;
137 GC_bool abort_if_found;         /* Abort if a reclaimable object is found */
138 register ptr_t list;
139 {
140     register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]);
141     register word *p, *plim;
142 #   ifdef GATHERSTATS
143         register int n_words_found = 0;
144 #   endif
145     register word mark_word;
146     register int i;
147 #   define DO_OBJ(start_displ) \
148         if (!(mark_word & ((word)1 << start_displ))) { \
149             FOUND_FREE(hbp, p - (word *)hbp + start_displ); \
150             p[start_displ] = (word)list; \
151             list = (ptr_t)(p+start_displ); \
152             p[start_displ+1] = 0; \
153             INCR_WORDS(2); \
154         }
155     
156     p = (word *)(hbp->hb_body);
157     plim = (word *)(((word)hbp) + HBLKSIZE);
158
159     /* go through all words in block */
160         while( p < plim )  {
161             mark_word = *mark_word_addr++;
162             for (i = 0; i < WORDSZ; i += 8) {
163                 DO_OBJ(0);
164                 DO_OBJ(2);
165                 DO_OBJ(4);
166                 DO_OBJ(6);
167                 p += 8;
168                 mark_word >>= 8;
169             }
170         }               
171 #   ifdef GATHERSTATS
172         GC_mem_found += n_words_found;
173 #   endif
174     return(list);
175 #   undef DO_OBJ
176 }
177
178 /*
179  * Another special case for 4 word composite objects:
180  */
181 /*ARGSUSED*/
182 ptr_t GC_reclaim_clear4(hbp, hhdr, list, abort_if_found)
183 register struct hblk *hbp;      /* ptr to current heap block            */
184 hdr * hhdr;
185 GC_bool abort_if_found;         /* Abort if a reclaimable object is found */
186 register ptr_t list;
187 {
188     register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]);
189     register word *p, *plim;
190 #   ifdef GATHERSTATS
191         register int n_words_found = 0;
192 #   endif
193     register word mark_word;
194 #   define DO_OBJ(start_displ) \
195         if (!(mark_word & ((word)1 << start_displ))) { \
196             FOUND_FREE(hbp, p - (word *)hbp + start_displ); \
197             p[start_displ] = (word)list; \
198             list = (ptr_t)(p+start_displ); \
199             p[start_displ+1] = 0; \
200             p[start_displ+2] = 0; \
201             p[start_displ+3] = 0; \
202             INCR_WORDS(4); \
203         }
204     
205     p = (word *)(hbp->hb_body);
206     plim = (word *)(((word)hbp) + HBLKSIZE);
207
208     /* go through all words in block */
209         while( p < plim )  {
210             mark_word = *mark_word_addr++;
211             DO_OBJ(0);
212             DO_OBJ(4);
213             DO_OBJ(8);
214             DO_OBJ(12);
215             DO_OBJ(16);
216             DO_OBJ(20);
217             DO_OBJ(24);
218             DO_OBJ(28);
219 #           if CPP_WORDSZ == 64
220               DO_OBJ(32);
221               DO_OBJ(36);
222               DO_OBJ(40);
223               DO_OBJ(44);
224               DO_OBJ(48);
225               DO_OBJ(52);
226               DO_OBJ(56);
227               DO_OBJ(60);
228 #           endif
229             p += WORDSZ;
230         }               
231 #   ifdef GATHERSTATS
232         GC_mem_found += n_words_found;
233 #   endif
234     return(list);
235 #   undef DO_OBJ
236 }
237
238 #endif /* !SMALL_CONFIG */
239
240 /* The same thing, but don't clear objects: */
241 /*ARGSUSED*/
242 ptr_t GC_reclaim_uninit(hbp, hhdr, sz, list, abort_if_found)
243 register struct hblk *hbp;      /* ptr to current heap block            */
244 register hdr * hhdr;
245 GC_bool abort_if_found;         /* Abort if a reclaimable object is found */
246 register ptr_t list;
247 register word sz;
248 {
249     register int word_no;
250     register word *p, *plim;
251 #   ifdef GATHERSTATS
252         register int n_words_found = 0;
253 #   endif
254     
255     p = (word *)(hbp->hb_body);
256     word_no = HDR_WORDS;
257     plim = (word *)((((word)hbp) + HBLKSIZE)
258                    - WORDS_TO_BYTES(sz));
259
260     /* go through all words in block */
261         while( p <= plim )  {
262             if( !mark_bit_from_hdr(hhdr, word_no) ) {
263                 FOUND_FREE(hbp, word_no);
264                 INCR_WORDS(sz);
265                 /* object is available - put on list */
266                     obj_link(p) = list;
267                     list = ((ptr_t)p);
268             }
269             p += sz;
270             word_no += sz;
271         }
272 #   ifdef GATHERSTATS
273         GC_mem_found += n_words_found;
274 #   endif
275     return(list);
276 }
277
278 #ifndef SMALL_CONFIG
279 /*
280  * Another special case for 2 word atomic objects:
281  */
282 /*ARGSUSED*/
283 ptr_t GC_reclaim_uninit2(hbp, hhdr, list, abort_if_found)
284 register struct hblk *hbp;      /* ptr to current heap block            */
285 hdr * hhdr;
286 GC_bool abort_if_found;         /* Abort if a reclaimable object is found */
287 register ptr_t list;
288 {
289     register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]);
290     register word *p, *plim;
291 #   ifdef GATHERSTATS
292         register int n_words_found = 0;
293 #   endif
294     register word mark_word;
295     register int i;
296 #   define DO_OBJ(start_displ) \
297         if (!(mark_word & ((word)1 << start_displ))) { \
298             FOUND_FREE(hbp, p - (word *)hbp + start_displ); \
299             p[start_displ] = (word)list; \
300             list = (ptr_t)(p+start_displ); \
301             INCR_WORDS(2); \
302         }
303     
304     p = (word *)(hbp->hb_body);
305     plim = (word *)(((word)hbp) + HBLKSIZE);
306
307     /* go through all words in block */
308         while( p < plim )  {
309             mark_word = *mark_word_addr++;
310             for (i = 0; i < WORDSZ; i += 8) {
311                 DO_OBJ(0);
312                 DO_OBJ(2);
313                 DO_OBJ(4);
314                 DO_OBJ(6);
315                 p += 8;
316                 mark_word >>= 8;
317             }
318         }               
319 #   ifdef GATHERSTATS
320         GC_mem_found += n_words_found;
321 #   endif
322     return(list);
323 #   undef DO_OBJ
324 }
325
326 /*
327  * Another special case for 4 word atomic objects:
328  */
329 /*ARGSUSED*/
330 ptr_t GC_reclaim_uninit4(hbp, hhdr, list, abort_if_found)
331 register struct hblk *hbp;      /* ptr to current heap block            */
332 hdr * hhdr;
333 GC_bool abort_if_found;         /* Abort if a reclaimable object is found */
334 register ptr_t list;
335 {
336     register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]);
337     register word *p, *plim;
338 #   ifdef GATHERSTATS
339         register int n_words_found = 0;
340 #   endif
341     register word mark_word;
342 #   define DO_OBJ(start_displ) \
343         if (!(mark_word & ((word)1 << start_displ))) { \
344             FOUND_FREE(hbp, p - (word *)hbp + start_displ); \
345             p[start_displ] = (word)list; \
346             list = (ptr_t)(p+start_displ); \
347             INCR_WORDS(4); \
348         }
349     
350     p = (word *)(hbp->hb_body);
351     plim = (word *)(((word)hbp) + HBLKSIZE);
352
353     /* go through all words in block */
354         while( p < plim )  {
355             mark_word = *mark_word_addr++;
356             DO_OBJ(0);
357             DO_OBJ(4);
358             DO_OBJ(8);
359             DO_OBJ(12);
360             DO_OBJ(16);
361             DO_OBJ(20);
362             DO_OBJ(24);
363             DO_OBJ(28);
364 #           if CPP_WORDSZ == 64
365               DO_OBJ(32);
366               DO_OBJ(36);
367               DO_OBJ(40);
368               DO_OBJ(44);
369               DO_OBJ(48);
370               DO_OBJ(52);
371               DO_OBJ(56);
372               DO_OBJ(60);
373 #           endif
374             p += WORDSZ;
375         }               
376 #   ifdef GATHERSTATS
377         GC_mem_found += n_words_found;
378 #   endif
379     return(list);
380 #   undef DO_OBJ
381 }
382
383 /* Finally the one word case, which never requires any clearing: */
384 /*ARGSUSED*/
385 ptr_t GC_reclaim1(hbp, hhdr, list, abort_if_found)
386 register struct hblk *hbp;      /* ptr to current heap block            */
387 hdr * hhdr;
388 GC_bool abort_if_found;         /* Abort if a reclaimable object is found */
389 register ptr_t list;
390 {
391     register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]);
392     register word *p, *plim;
393 #   ifdef GATHERSTATS
394         register int n_words_found = 0;
395 #   endif
396     register word mark_word;
397     register int i;
398 #   define DO_OBJ(start_displ) \
399         if (!(mark_word & ((word)1 << start_displ))) { \
400             FOUND_FREE(hbp, p - (word *)hbp + start_displ); \
401             p[start_displ] = (word)list; \
402             list = (ptr_t)(p+start_displ); \
403             INCR_WORDS(1); \
404         }
405     
406     p = (word *)(hbp->hb_body);
407     plim = (word *)(((word)hbp) + HBLKSIZE);
408
409     /* go through all words in block */
410         while( p < plim )  {
411             mark_word = *mark_word_addr++;
412             for (i = 0; i < WORDSZ; i += 4) {
413                 DO_OBJ(0);
414                 DO_OBJ(1);
415                 DO_OBJ(2);
416                 DO_OBJ(3);
417                 p += 4;
418                 mark_word >>= 4;
419             }
420         }               
421 #   ifdef GATHERSTATS
422         GC_mem_found += n_words_found;
423 #   endif
424     return(list);
425 #   undef DO_OBJ
426 }
427
428 #endif /* !SMALL_CONFIG */
429
430 /*
431  * Restore unmarked small objects in the block pointed to by hbp
432  * to the appropriate object free list.
433  * If entirely empty blocks are to be completely deallocated, then
434  * caller should perform that check.
435  */
436 void GC_reclaim_small_nonempty_block(hbp, abort_if_found)
437 register struct hblk *hbp;      /* ptr to current heap block            */
438 int abort_if_found;             /* Abort if a reclaimable object is found */
439 {
440     hdr * hhdr;
441     register word sz;           /* size of objects in current block     */
442     register struct obj_kind * ok;
443     register ptr_t * flh;
444     register int kind;
445     
446     hhdr = HDR(hbp);
447     sz = hhdr -> hb_sz;
448     hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
449     kind = hhdr -> hb_obj_kind;
450     ok = &GC_obj_kinds[kind];
451     flh = &(ok -> ok_freelist[sz]);
452     GC_write_hint(hbp);
453
454     if (ok -> ok_init) {
455       switch(sz) {
456 #      ifndef SMALL_CONFIG
457         case 1:
458             *flh = GC_reclaim1(hbp, hhdr, *flh, abort_if_found);
459             break;
460         case 2:
461             *flh = GC_reclaim_clear2(hbp, hhdr, *flh, abort_if_found);
462             break;
463         case 4:
464             *flh = GC_reclaim_clear4(hbp, hhdr, *flh, abort_if_found);
465             break;
466 #      endif
467         default:
468             *flh = GC_reclaim_clear(hbp, hhdr, sz, *flh, abort_if_found);
469             break;
470       }
471     } else {
472       switch(sz) {
473 #      ifndef SMALL_CONFIG
474         case 1:
475             *flh = GC_reclaim1(hbp, hhdr, *flh, abort_if_found);
476             break;
477         case 2:
478             *flh = GC_reclaim_uninit2(hbp, hhdr, *flh, abort_if_found);
479             break;
480         case 4:
481             *flh = GC_reclaim_uninit4(hbp, hhdr, *flh, abort_if_found);
482             break;
483 #      endif
484         default:
485             *flh = GC_reclaim_uninit(hbp, hhdr, sz, *flh, abort_if_found);
486             break;
487       }
488     } 
489     if (IS_UNCOLLECTABLE(kind)) GC_set_hdr_marks(hhdr);
490 }
491
492 /*
493  * Restore an unmarked large object or an entirely empty blocks of small objects
494  * to the heap block free list.
495  * Otherwise enqueue the block for later processing
496  * by GC_reclaim_small_nonempty_block.
497  * If abort_if_found is TRUE, then process any block immediately.
498  */
499 void GC_reclaim_block(hbp, abort_if_found)
500 register struct hblk *hbp;      /* ptr to current heap block            */
501 word abort_if_found;            /* Abort if a reclaimable object is found */
502 {
503     register hdr * hhdr;
504     register word sz;           /* size of objects in current block     */
505     register struct obj_kind * ok;
506     struct hblk ** rlh;
507
508     hhdr = HDR(hbp);
509     sz = hhdr -> hb_sz;
510     ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
511
512     if( sz > MAXOBJSZ ) {  /* 1 big object */
513         if( !mark_bit_from_hdr(hhdr, HDR_WORDS) ) {
514             FOUND_FREE(hbp, HDR_WORDS);
515 #           ifdef GATHERSTATS
516                 GC_mem_found += sz;
517 #           endif
518             GC_freehblk(hbp);
519         }
520     } else {
521         GC_bool empty = GC_block_empty(hhdr);
522         if (abort_if_found) {
523           GC_reclaim_small_nonempty_block(hbp, (int)abort_if_found);
524         } else if (empty) {
525 #         ifdef GATHERSTATS
526             GC_mem_found += BYTES_TO_WORDS(HBLKSIZE);
527 #         endif
528           GC_freehblk(hbp);
529         } else {
530           /* group of smaller objects, enqueue the real work */
531           rlh = &(ok -> ok_reclaim_list[sz]);
532           hhdr -> hb_next = *rlh;
533           *rlh = hbp;
534         }
535     }
536 }
537
538 #if !defined(NO_DEBUGGING)
539 /* Routines to gather and print heap block info         */
540 /* intended for debugging.  Otherwise should be called  */
541 /* with lock.                                           */
542 static size_t number_of_blocks;
543 static size_t total_bytes;
544
545 /* Number of set bits in a word.  Not performance critical.     */
546 static int set_bits(n)
547 word n;
548 {
549     register word m = n;
550     register int result = 0;
551     
552     while (m > 0) {
553         if (m & 1) result++;
554         m >>= 1;
555     }
556     return(result);
557 }
558
559 /* Return the number of set mark bits in the given header       */
560 int GC_n_set_marks(hhdr)
561 hdr * hhdr;
562 {
563     register int result = 0;
564     register int i;
565     
566     for (i = 0; i < MARK_BITS_SZ; i++) {
567         result += set_bits(hhdr -> hb_marks[i]);
568     }
569     return(result);
570 }
571
572 /*ARGSUSED*/
573 void GC_print_block_descr(h, dummy)
574 struct hblk *h;
575 word dummy;
576 {
577     register hdr * hhdr = HDR(h);
578     register size_t bytes = WORDS_TO_BYTES(hhdr -> hb_sz);
579     
580     GC_printf3("(%lu:%lu,%lu)", (unsigned long)(hhdr -> hb_obj_kind),
581                                 (unsigned long)bytes,
582                                 (unsigned long)(GC_n_set_marks(hhdr)));
583     bytes += HDR_BYTES + HBLKSIZE-1;
584     bytes &= ~(HBLKSIZE-1);
585     total_bytes += bytes;
586     number_of_blocks++;
587 }
588
589 void GC_print_block_list()
590 {
591     GC_printf0("(kind(0=ptrfree,1=normal,2=unc.,3=stubborn):size_in_bytes, #_marks_set)\n");
592     number_of_blocks = 0;
593     total_bytes = 0;
594     GC_apply_to_all_blocks(GC_print_block_descr, (word)0);
595     GC_printf2("\nblocks = %lu, bytes = %lu\n",
596                (unsigned long)number_of_blocks,
597                (unsigned long)total_bytes);
598 }
599
600 #endif /* NO_DEBUGGING */
601
602 /*
603  * Do the same thing on the entire heap, after first clearing small object
604  * free lists (if we are not just looking for leaks).
605  */
606 void GC_start_reclaim(abort_if_found)
607 int abort_if_found;             /* Abort if a GC_reclaimable object is found */
608 {
609     int kind;
610     
611     /* Clear reclaim- and free-lists */
612       for (kind = 0; kind < GC_n_kinds; kind++) {
613         register ptr_t *fop;
614         register ptr_t *lim;
615         register struct hblk ** rlp;
616         register struct hblk ** rlim;
617         register struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list;
618         
619         if (rlist == 0) continue;       /* This kind not used.  */
620         if (!abort_if_found) {
621             lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJSZ+1]);
622             for( fop = GC_obj_kinds[kind].ok_freelist; fop < lim; fop++ ) {
623               *fop = 0;
624             }
625         } /* otherwise free list objects are marked,    */
626           /* and its safe to leave them                 */
627         rlim = rlist + MAXOBJSZ+1;
628         for( rlp = rlist; rlp < rlim; rlp++ ) {
629             *rlp = 0;
630         }
631       }
632     
633 #   ifdef PRINTBLOCKS
634         GC_printf0("GC_reclaim: current block sizes:\n");
635         GC_print_block_list();
636 #   endif
637
638   /* Go through all heap blocks (in hblklist) and reclaim unmarked objects */
639   /* or enqueue the block for later processing.                            */
640     GC_apply_to_all_blocks(GC_reclaim_block, (word)abort_if_found);
641     
642 }
643
644 /*
645  * Sweep blocks of the indicated object size and kind until either the
646  * appropriate free list is nonempty, or there are no more blocks to
647  * sweep.
648  */
649 void GC_continue_reclaim(sz, kind)
650 word sz;        /* words */
651 int kind;
652 {
653     register hdr * hhdr;
654     register struct hblk * hbp;
655     register struct obj_kind * ok = &(GC_obj_kinds[kind]);
656     struct hblk ** rlh = ok -> ok_reclaim_list;
657     ptr_t *flh = &(ok -> ok_freelist[sz]);
658     
659     if (rlh == 0) return;       /* No blocks of this kind.      */
660     rlh += sz;
661     while ((hbp = *rlh) != 0) {
662         hhdr = HDR(hbp);
663         *rlh = hhdr -> hb_next;
664         GC_reclaim_small_nonempty_block(hbp, FALSE);
665         if (*flh != 0) break;
666     }
667 }
668
669 /*
670  * Reclaim all small blocks waiting to be reclaimed.
671  * Abort and return FALSE when/if (*stop_func)() returns TRUE.
672  * If this returns TRUE, then it's safe to restart the world
673  * with incorrectly cleared mark bits.
674  * If ignore_old is TRUE, then reclain only blocks that have been 
675  * recently reclaimed, and discard the rest.
676  * Stop_func may be 0.
677  */
678 GC_bool GC_reclaim_all(stop_func, ignore_old)
679 GC_stop_func stop_func;
680 GC_bool ignore_old;
681 {
682     register word sz;
683     register int kind;
684     register hdr * hhdr;
685     register struct hblk * hbp;
686     register struct obj_kind * ok;
687     struct hblk ** rlp;
688     struct hblk ** rlh;
689 #   ifdef PRINTTIMES
690         CLOCK_TYPE start_time;
691         CLOCK_TYPE done_time;
692         
693         GET_TIME(start_time);
694 #   endif
695     
696     for (kind = 0; kind < GC_n_kinds; kind++) {
697         ok = &(GC_obj_kinds[kind]);
698         rlp = ok -> ok_reclaim_list;
699         if (rlp == 0) continue;
700         for (sz = 1; sz <= MAXOBJSZ; sz++) {
701             rlh = rlp + sz;
702             while ((hbp = *rlh) != 0) {
703                 if (stop_func != (GC_stop_func)0 && (*stop_func)()) {
704                     return(FALSE);
705                 }
706                 hhdr = HDR(hbp);
707                 *rlh = hhdr -> hb_next;
708                 if (!ignore_old || hhdr -> hb_last_reclaimed == GC_gc_no - 1) {
709                     /* It's likely we'll need it this time, too */
710                     /* It's been touched recently, so this      */
711                     /* shouldn't trigger paging.                */
712                     GC_reclaim_small_nonempty_block(hbp, FALSE);
713                 }
714             }
715         }
716     }
717 #   ifdef PRINTTIMES
718         GET_TIME(done_time);
719         GC_printf1("Disposing of reclaim lists took %lu msecs\n",
720                    MS_TIME_DIFF(done_time,start_time));
721 #   endif
722     return(TRUE);
723 }