implemented Setup.hs to build boehm cpp libs and install them;
[hs-boehmgc.git] / gc-7.2 / tests / test.c
1 /*
2  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
4  * Copyright (c) 1996 by Silicon Graphics.  All rights reserved.
5  *
6  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
7  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
8  *
9  * Permission is hereby granted to use or copy this program
10  * for any purpose,  provided the above notices are retained on all copies.
11  * Permission to modify the code and to distribute modified code is granted,
12  * provided the above notices are retained, and a notice that the code was
13  * modified is included with the above copyright notice.
14  */
15 /* An incomplete test for the garbage collector.                */
16 /* Some more obscure entry points are not tested at all.        */
17 /* This must be compiled with the same flags used to build the  */
18 /* GC.  It uses GC internals to allow more precise results      */
19 /* checking for some of the tests.                              */
20
21 # ifdef HAVE_CONFIG_H
22 #   include "private/config.h"
23 # endif
24
25 # undef GC_BUILD
26
27 #if (defined(DBG_HDRS_ALL) || defined(MAKE_BACK_GRAPH)) && !defined(GC_DEBUG)
28 #  define GC_DEBUG
29 #endif
30
31 #include "gc.h"
32
33 #ifndef NTHREADS /* Number of additional threads to fork. */
34 #  define NTHREADS 5 /* excludes main thread, which also runs a test. */
35         /* Not respected by PCR test. */
36 #endif
37
38 # if defined(mips) && defined(SYSTYPE_BSD43)
39     /* MIPS RISCOS 4 */
40 # else
41 #   include <stdlib.h>
42 # endif
43 # include <stdio.h>
44 # if defined(_WIN32_WCE) && !defined(__GNUC__)
45 #   include <winbase.h>
46 /* #   define assert ASSERT */
47 # else
48 #   include <assert.h>        /* Not normally used, but handy for debugging. */
49 # endif
50
51 # include "gc_typed.h"
52 # include "private/gc_priv.h"   /* For output, locking, MIN_WORDS,      */
53                                 /* some statistics and gcconfig.h.      */
54
55 # if defined(MSWIN32) || defined(MSWINCE)
56 #   include <windows.h>
57 # endif
58
59 #ifdef GC_PRINT_VERBOSE_STATS
60 # define print_stats VERBOSE
61 # define INIT_PRINT_STATS /* empty */
62 #else
63   /* Use own variable as GC_print_stats might not be exported.  */
64   static int print_stats = 0;
65 # ifdef GC_READ_ENV_FILE
66     /* GETENV uses GC internal function in this case.   */
67 #   define INIT_PRINT_STATS /* empty */
68 # else
69 #   define INIT_PRINT_STATS \
70         { \
71           if (0 != GETENV("GC_PRINT_VERBOSE_STATS")) \
72             print_stats = VERBOSE; \
73           else if (0 != GETENV("GC_PRINT_STATS")) \
74             print_stats = 1; \
75         }
76 # endif
77 #endif /* !GC_PRINT_VERBOSE_STATS */
78
79 # ifdef PCR
80 #   include "th/PCR_ThCrSec.h"
81 #   include "th/PCR_Th.h"
82 #   define GC_printf printf
83 # endif
84
85 # if defined(GC_PTHREADS)
86 #   include <pthread.h>
87 # endif
88
89 # if (!defined(THREADS) || !defined(HANDLE_FORK) \
90       || (defined(DARWIN) && defined(MPROTECT_VDB) \
91           && !defined(NO_INCREMENTAL) && !defined(MAKE_BACK_GRAPH))) \
92      && !defined(NO_TEST_HANDLE_FORK)
93 #   define NO_TEST_HANDLE_FORK
94 # endif
95
96 # ifndef NO_TEST_HANDLE_FORK
97 #   include <unistd.h>
98 #   define INIT_FORK_SUPPORT GC_set_handle_fork(1)
99 # else
100 #   define INIT_FORK_SUPPORT /* empty */
101 # endif
102
103 # if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
104     static CRITICAL_SECTION incr_cs;
105 # endif
106
107 # include <stdarg.h>
108
109 #ifndef GC_ALPHA_VERSION
110 # define GC_ALPHA_VERSION GC_TMP_ALPHA_VERSION
111 #endif
112
113 #define CHECH_GCLIB_VERSION \
114             if (GC_get_version() != ((GC_VERSION_MAJOR<<16) \
115                                     | (GC_VERSION_MINOR<<8) \
116                                     | GC_ALPHA_VERSION)) { \
117               GC_printf("libgc version mismatch\n"); \
118               exit(1); \
119             }
120
121 /* Call GC_INIT only on platforms on which we think we really need it,  */
122 /* so that we can test automatic initialization on the rest.            */
123 #if defined(CYGWIN32) || defined (AIX) || defined(DARWIN) \
124         || defined(THREAD_LOCAL_ALLOC) \
125         || (defined(MSWINCE) && !defined(GC_WINMAIN_REDIRECT))
126 #  define GC_OPT_INIT GC_INIT()
127 #else
128 #  define GC_OPT_INIT /* empty */
129 #endif
130
131 #define GC_COND_INIT() \
132     INIT_FORK_SUPPORT; GC_OPT_INIT; CHECH_GCLIB_VERSION; INIT_PRINT_STATS
133
134 #define CHECK_OUT_OF_MEMORY(p) \
135             if ((p) == NULL) { \
136               GC_printf("Out of memory\n"); \
137               exit(1); \
138             }
139
140 /* Allocation Statistics.  Incremented without synchronization. */
141 /* FIXME: We should be using synchronization.                   */
142 int stubborn_count = 0;
143 int uncollectable_count = 0;
144 int collectable_count = 0;
145 int atomic_count = 0;
146 int realloc_count = 0;
147
148 #if defined(GC_AMIGA_FASTALLOC) && defined(AMIGA)
149
150   void GC_amiga_free_all_mem(void);
151   void Amiga_Fail(void){GC_amiga_free_all_mem();abort();}
152 # define FAIL (void)Amiga_Fail()
153   void *GC_amiga_gctest_malloc_explicitly_typed(size_t lb, GC_descr d){
154     void *ret=GC_malloc_explicitly_typed(lb,d);
155     if(ret==NULL){
156                 if(!GC_dont_gc){
157               GC_gcollect();
158               ret=GC_malloc_explicitly_typed(lb,d);
159                 }
160       if(ret==NULL){
161         GC_printf("Out of memory, (typed allocations are not directly "
162                       "supported with the GC_AMIGA_FASTALLOC option.)\n");
163         FAIL;
164       }
165     }
166     return ret;
167   }
168   void *GC_amiga_gctest_calloc_explicitly_typed(size_t a,size_t lb, GC_descr d){
169     void *ret=GC_calloc_explicitly_typed(a,lb,d);
170     if(ret==NULL){
171                 if(!GC_dont_gc){
172               GC_gcollect();
173               ret=GC_calloc_explicitly_typed(a,lb,d);
174                 }
175       if(ret==NULL){
176         GC_printf("Out of memory, (typed allocations are not directly "
177                       "supported with the GC_AMIGA_FASTALLOC option.)\n");
178         FAIL;
179       }
180     }
181     return ret;
182   }
183 # define GC_malloc_explicitly_typed(a,b) GC_amiga_gctest_malloc_explicitly_typed(a,b)
184 # define GC_calloc_explicitly_typed(a,b,c) GC_amiga_gctest_calloc_explicitly_typed(a,b,c)
185
186 #else /* !AMIGA_FASTALLOC */
187
188 # if defined(PCR) || defined(LINT2)
189 #   define FAIL (void)abort()
190 # else
191 #   define FAIL ABORT("Test failed")
192 # endif
193
194 #endif /* !AMIGA_FASTALLOC */
195
196 /* AT_END may be defined to exercise the interior pointer test  */
197 /* if the collector is configured with ALL_INTERIOR_POINTERS.   */
198 /* As it stands, this test should succeed with either           */
199 /* configuration.  In the FIND_LEAK configuration, it should    */
200 /* find lots of leaks, since we free almost nothing.            */
201
202 struct SEXPR {
203     struct SEXPR * sexpr_car;
204     struct SEXPR * sexpr_cdr;
205 };
206
207
208 typedef struct SEXPR * sexpr;
209
210 # define INT_TO_SEXPR(x) ((sexpr)(GC_word)(x))
211 # define SEXPR_TO_INT(x) ((int)(GC_word)(x))
212
213 # undef nil
214 # define nil (INT_TO_SEXPR(0))
215 # define car(x) ((x) -> sexpr_car)
216 # define cdr(x) ((x) -> sexpr_cdr)
217 # define is_nil(x) ((x) == nil)
218
219
220 int extra_count = 0;        /* Amount of space wasted in cons node */
221
222 /* Silly implementation of Lisp cons. Intentionally wastes lots of space */
223 /* to test collector.                                                    */
224 # ifdef VERY_SMALL_CONFIG
225 #   define cons small_cons
226 # else
227 sexpr cons (sexpr x, sexpr y)
228 {
229     sexpr r;
230     int *p;
231     int my_extra = extra_count;
232
233     stubborn_count++;
234     r = (sexpr) GC_MALLOC_STUBBORN(sizeof(struct SEXPR) + my_extra);
235     CHECK_OUT_OF_MEMORY(r);
236     for (p = (int *)r;
237          ((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
238         if (*p) {
239             GC_printf("Found nonzero at %p - allocator is broken\n", p);
240             FAIL;
241         }
242         *p = (int)((13 << 12) + ((p - (int *)r) & 0xfff));
243     }
244 #   ifdef AT_END
245         r = (sexpr)((char *)r + (my_extra & ~7));
246 #   endif
247     r -> sexpr_car = x;
248     r -> sexpr_cdr = y;
249     my_extra++;
250     if ( my_extra >= 5000 ) {
251         extra_count = 0;
252     } else {
253         extra_count = my_extra;
254     }
255     GC_END_STUBBORN_CHANGE((char *)r);
256     return(r);
257 }
258 # endif
259
260 #ifdef GC_GCJ_SUPPORT
261
262 #include "gc_mark.h"
263 #include "gc_gcj.h"
264
265 /* The following struct emulates the vtable in gcj.     */
266 /* This assumes the default value of MARK_DESCR_OFFSET. */
267 struct fake_vtable {
268   void * dummy;         /* class pointer in real gcj.   */
269   GC_word descr;
270 };
271
272 struct fake_vtable gcj_class_struct1 = { 0, sizeof(struct SEXPR)
273                                             + sizeof(struct fake_vtable *) };
274                         /* length based descriptor.     */
275 struct fake_vtable gcj_class_struct2 =
276                         { 0, ((GC_word)3 << (CPP_WORDSZ - 3)) | GC_DS_BITMAP};
277                         /* Bitmap based descriptor.     */
278
279 struct GC_ms_entry * fake_gcj_mark_proc(word * addr,
280                                         struct GC_ms_entry *mark_stack_ptr,
281                                         struct GC_ms_entry *mark_stack_limit,
282                                         word env   )
283 {
284     sexpr x;
285     if (1 == env) {
286         /* Object allocated with debug allocator.       */
287         addr = (word *)GC_USR_PTR_FROM_BASE(addr);
288     }
289     x = (sexpr)(addr + 1); /* Skip the vtable pointer. */
290     mark_stack_ptr = GC_MARK_AND_PUSH(
291                               (void *)(x -> sexpr_cdr), mark_stack_ptr,
292                               mark_stack_limit, (void * *)&(x -> sexpr_cdr));
293     mark_stack_ptr = GC_MARK_AND_PUSH(
294                               (void *)(x -> sexpr_car), mark_stack_ptr,
295                               mark_stack_limit, (void * *)&(x -> sexpr_car));
296     return(mark_stack_ptr);
297 }
298
299 #endif /* GC_GCJ_SUPPORT */
300
301
302 sexpr small_cons (sexpr x, sexpr y)
303 {
304     sexpr r;
305
306     collectable_count++;
307     r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
308     CHECK_OUT_OF_MEMORY(r);
309     r -> sexpr_car = x;
310     r -> sexpr_cdr = y;
311     return(r);
312 }
313
314 sexpr small_cons_uncollectable (sexpr x, sexpr y)
315 {
316     sexpr r;
317
318     uncollectable_count++;
319     r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR));
320     CHECK_OUT_OF_MEMORY(r);
321     r -> sexpr_car = x;
322     r -> sexpr_cdr = (sexpr)(~(GC_word)y);
323     return(r);
324 }
325
326 #ifdef GC_GCJ_SUPPORT
327
328
329 sexpr gcj_cons(sexpr x, sexpr y)
330 {
331     GC_word * r;
332     sexpr result;
333
334     r = (GC_word *) GC_GCJ_MALLOC(sizeof(struct SEXPR)
335                                   + sizeof(struct fake_vtable*),
336                                    &gcj_class_struct2);
337     CHECK_OUT_OF_MEMORY(r);
338     result = (sexpr)(r + 1);
339     result -> sexpr_car = x;
340     result -> sexpr_cdr = y;
341     return(result);
342 }
343 #endif
344
345 /* Return reverse(x) concatenated with y */
346 sexpr reverse1(sexpr x, sexpr y)
347 {
348     if (is_nil(x)) {
349         return(y);
350     } else {
351         return( reverse1(cdr(x), cons(car(x), y)) );
352     }
353 }
354
355 sexpr reverse(sexpr x)
356 {
357 #   ifdef TEST_WITH_SYSTEM_MALLOC
358       malloc(100000);
359 #   endif
360     return( reverse1(x, nil) );
361 }
362
363 sexpr ints(int low, int up)
364 {
365     if (low > up) {
366         return(nil);
367     } else {
368         return(small_cons(small_cons(INT_TO_SEXPR(low), nil), ints(low+1, up)));
369     }
370 }
371
372 #ifdef GC_GCJ_SUPPORT
373 /* Return reverse(x) concatenated with y */
374 sexpr gcj_reverse1(sexpr x, sexpr y)
375 {
376     if (is_nil(x)) {
377         return(y);
378     } else {
379         return( gcj_reverse1(cdr(x), gcj_cons(car(x), y)) );
380     }
381 }
382
383 sexpr gcj_reverse(sexpr x)
384 {
385     return( gcj_reverse1(x, nil) );
386 }
387
388 sexpr gcj_ints(int low, int up)
389 {
390     if (low > up) {
391         return(nil);
392     } else {
393         return(gcj_cons(gcj_cons(INT_TO_SEXPR(low), nil), gcj_ints(low+1, up)));
394     }
395 }
396 #endif /* GC_GCJ_SUPPORT */
397
398 /* To check uncollectable allocation we build lists with disguised cdr  */
399 /* pointers, and make sure they don't go away.                          */
400 sexpr uncollectable_ints(int low, int up)
401 {
402     if (low > up) {
403         return(nil);
404     } else {
405         return(small_cons_uncollectable(small_cons(INT_TO_SEXPR(low), nil),
406                uncollectable_ints(low+1, up)));
407     }
408 }
409
410 void check_ints(sexpr list, int low, int up)
411 {
412     if (SEXPR_TO_INT(car(car(list))) != low) {
413         GC_printf(
414            "List reversal produced incorrect list - collector is broken\n");
415         FAIL;
416     }
417     if (low == up) {
418         if (cdr(list) != nil) {
419            GC_printf("List too long - collector is broken\n");
420            FAIL;
421         }
422     } else {
423         check_ints(cdr(list), low+1, up);
424     }
425 }
426
427 # define UNCOLLECTABLE_CDR(x) (sexpr)(~(GC_word)(cdr(x)))
428
429 void check_uncollectable_ints(sexpr list, int low, int up)
430 {
431     if (SEXPR_TO_INT(car(car(list))) != low) {
432         GC_printf("Uncollectable list corrupted - collector is broken\n");
433         FAIL;
434     }
435     if (low == up) {
436       if (UNCOLLECTABLE_CDR(list) != nil) {
437         GC_printf("Uncollectable list too long - collector is broken\n");
438         FAIL;
439       }
440     } else {
441         check_uncollectable_ints(UNCOLLECTABLE_CDR(list), low+1, up);
442     }
443 }
444
445 /* Not used, but useful for debugging: */
446 void print_int_list(sexpr x)
447 {
448     if (is_nil(x)) {
449         GC_printf("NIL\n");
450     } else {
451         GC_printf("(%d)", SEXPR_TO_INT(car(car(x))));
452         if (!is_nil(cdr(x))) {
453             GC_printf(", ");
454             print_int_list(cdr(x));
455         } else {
456             GC_printf("\n");
457         }
458     }
459 }
460
461 /* ditto: */
462 void check_marks_int_list(sexpr x)
463 {
464     if (!GC_is_marked((ptr_t)x))
465         GC_printf("[unm:%p]", x);
466     else
467         GC_printf("[mkd:%p]", x);
468     if (is_nil(x)) {
469         GC_printf("NIL\n");
470     } else {
471         if (!GC_is_marked((ptr_t)car(x)))
472           GC_printf("[unm car:%p]", car(x));
473         GC_printf("(%d)", SEXPR_TO_INT(car(car(x))));
474         if (!is_nil(cdr(x))) {
475             GC_printf(", ");
476             check_marks_int_list(cdr(x));
477         } else {
478             GC_printf("\n");
479         }
480     }
481 }
482
483 /*
484  * A tiny list reversal test to check thread creation.
485  */
486 #ifdef THREADS
487
488 # ifdef VERY_SMALL_CONFIG
489 #   define TINY_REVERSE_UPPER_VALUE 4
490 # else
491 #   define TINY_REVERSE_UPPER_VALUE 10
492 # endif
493
494 # if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
495     DWORD  __stdcall tiny_reverse_test(void * arg)
496 # else
497     void * tiny_reverse_test(void * arg)
498 # endif
499 {
500     int i;
501     for (i = 0; i < 5; ++i) {
502       check_ints(reverse(reverse(ints(1, TINY_REVERSE_UPPER_VALUE))),
503                  1, TINY_REVERSE_UPPER_VALUE);
504     }
505     return 0;
506 }
507
508 # if defined(GC_PTHREADS)
509     void fork_a_thread(void)
510     {
511       pthread_t t;
512       int code;
513       if ((code = pthread_create(&t, 0, tiny_reverse_test, 0)) != 0) {
514         GC_printf("Small thread creation failed %d\n", code);
515         FAIL;
516       }
517       if ((code = pthread_join(t, 0)) != 0) {
518         GC_printf("Small thread join failed %d\n", code);
519         FAIL;
520       }
521     }
522
523 # elif defined(GC_WIN32_THREADS)
524     void fork_a_thread(void)
525     {
526         DWORD thread_id;
527         HANDLE h;
528         h = GC_CreateThread(NULL, 0, tiny_reverse_test, 0, 0, &thread_id);
529         if (h == (HANDLE)NULL) {
530             GC_printf("Small thread creation failed %d\n",
531                           (int)GetLastError());
532             FAIL;
533         }
534         if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) {
535             GC_printf("Small thread wait failed %d\n",
536                           (int)GetLastError());
537             FAIL;
538         }
539     }
540
541 # endif
542
543 #endif
544
545 /* Try to force a to be strangely aligned */
546 struct {
547   char dummy;
548   sexpr aa;
549 } A;
550 #define a A.aa
551
552 /*
553  * Repeatedly reverse lists built out of very different sized cons cells.
554  * Check that we didn't lose anything.
555  */
556 void *GC_CALLBACK reverse_test_inner(void *data)
557 {
558     int i;
559     sexpr b;
560     sexpr c;
561     sexpr d;
562     sexpr e;
563     sexpr *f, *g, *h;
564
565     if (data == 0) {
566       /* This stack frame is not guaranteed to be scanned. */
567       return GC_call_with_gc_active(reverse_test_inner, (void*)(word)1);
568     }
569
570 #   if /*defined(MSWIN32) ||*/ defined(MACOS)
571       /* Win32S only allows 128K stacks */
572 #     define BIG 1000
573 #   elif defined(PCR)
574       /* PCR default stack is 100K.  Stack frames are up to 120 bytes. */
575 #     define BIG 700
576 #   elif defined(MSWINCE) || defined(RTEMS)
577       /* WinCE only allows 64K stacks */
578 #     define BIG 500
579 #   elif defined(OSF1)
580       /* OSF has limited stack space by default, and large frames. */
581 #     define BIG 200
582 #   elif defined(__MACH__) && defined(__ppc64__)
583 #     define BIG 2500
584 #   else
585 #     define BIG 4500
586 #   endif
587
588     A.dummy = 17;
589     a = ints(1, 49);
590     b = ints(1, 50);
591     c = ints(1, BIG);
592     d = uncollectable_ints(1, 100);
593     e = uncollectable_ints(1, 1);
594     /* Check that realloc updates object descriptors correctly */
595     collectable_count++;
596     f = (sexpr *)GC_MALLOC(4 * sizeof(sexpr));
597     realloc_count++;
598     f = (sexpr *)GC_REALLOC((void *)f, 6 * sizeof(sexpr));
599     CHECK_OUT_OF_MEMORY(f);
600     f[5] = ints(1,17);
601     collectable_count++;
602     g = (sexpr *)GC_MALLOC(513 * sizeof(sexpr));
603     realloc_count++;
604     g = (sexpr *)GC_REALLOC((void *)g, 800 * sizeof(sexpr));
605     CHECK_OUT_OF_MEMORY(g);
606     g[799] = ints(1,18);
607     collectable_count++;
608     h = (sexpr *)GC_MALLOC(1025 * sizeof(sexpr));
609     realloc_count++;
610     h = (sexpr *)GC_REALLOC((void *)h, 2000 * sizeof(sexpr));
611     CHECK_OUT_OF_MEMORY(h);
612 #   ifdef GC_GCJ_SUPPORT
613       h[1999] = gcj_ints(1,200);
614       for (i = 0; i < 51; ++i)
615         h[1999] = gcj_reverse(h[1999]);
616       /* Leave it as the reveresed list for now. */
617 #   else
618       h[1999] = ints(1,200);
619 #   endif
620     /* Try to force some collections and reuse of small list elements */
621     for (i = 0; i < 10; i++) {
622       (void)ints(1, BIG);
623     }
624     /* Superficially test interior pointer recognition on stack */
625     c = (sexpr)((char *)c + sizeof(char *));
626     d = (sexpr)((char *)d + sizeof(char *));
627
628     GC_FREE((void *)e);
629
630     check_ints(b,1,50);
631     check_ints(a,1,49);
632     for (i = 0; i < 50; i++) {
633         check_ints(b,1,50);
634         b = reverse(reverse(b));
635     }
636     check_ints(b,1,50);
637     check_ints(a,1,49);
638     for (i = 0; i < 60; i++) {
639 #       if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
640             if (i % 10 == 0) fork_a_thread();
641 #       endif
642         /* This maintains the invariant that a always points to a list of */
643         /* 49 integers.  Thus this is thread safe without locks,          */
644         /* assuming atomic pointer assignments.                           */
645         a = reverse(reverse(a));
646 #       if !defined(AT_END) && !defined(THREADS)
647           /* This is not thread safe, since realloc explicitly deallocates */
648           if (i & 1) {
649             a = (sexpr)GC_REALLOC((void *)a, 500);
650           } else {
651             a = (sexpr)GC_REALLOC((void *)a, 8200);
652           }
653 #       endif
654     }
655     check_ints(a,1,49);
656     check_ints(b,1,50);
657
658     /* Restore c and d values. */
659     c = (sexpr)((char *)c - sizeof(char *));
660     d = (sexpr)((char *)d - sizeof(char *));
661
662     check_ints(c,1,BIG);
663     check_uncollectable_ints(d, 1, 100);
664     check_ints(f[5], 1,17);
665     check_ints(g[799], 1,18);
666 #   ifdef GC_GCJ_SUPPORT
667       h[1999] = gcj_reverse(h[1999]);
668 #   endif
669     check_ints(h[1999], 1,200);
670 #   ifndef THREADS
671         a = 0;
672 #   endif
673     *(sexpr volatile *)&b = 0;
674     *(sexpr volatile *)&c = 0;
675     return 0;
676 }
677
678 void reverse_test(void)
679 {
680     /* Test GC_do_blocking/GC_call_with_gc_active. */
681     (void)GC_do_blocking(reverse_test_inner, 0);
682 }
683
684 #undef a
685
686 /*
687  * The rest of this builds balanced binary trees, checks that they don't
688  * disappear, and tests finalization.
689  */
690 typedef struct treenode {
691     int level;
692     struct treenode * lchild;
693     struct treenode * rchild;
694 } tn;
695
696 int finalizable_count = 0;
697 int finalized_count = 0;
698 volatile int dropped_something = 0;
699
700 void GC_CALLBACK finalizer(void * obj, void * client_data)
701 {
702   tn * t = (tn *)obj;
703
704 # ifdef PCR
705      PCR_ThCrSec_EnterSys();
706 # endif
707 # if defined(GC_PTHREADS)
708     static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
709     pthread_mutex_lock(&incr_lock);
710 # elif defined(GC_WIN32_THREADS)
711     EnterCriticalSection(&incr_cs);
712 # endif
713   if ((int)(GC_word)client_data != t -> level) {
714      GC_printf("Wrong finalization data - collector is broken\n");
715      FAIL;
716   }
717   finalized_count++;
718   t -> level = -1;      /* detect duplicate finalization immediately */
719 # ifdef PCR
720     PCR_ThCrSec_ExitSys();
721 # endif
722 # if defined(GC_PTHREADS)
723     pthread_mutex_unlock(&incr_lock);
724 # elif defined(GC_WIN32_THREADS)
725     LeaveCriticalSection(&incr_cs);
726 # endif
727 }
728
729 size_t counter = 0;
730
731 # define MAX_FINALIZED (NTHREADS*4000)
732
733 # if !defined(MACOS)
734   GC_FAR GC_word live_indicators[MAX_FINALIZED] = {0};
735 #else
736   /* Too big for THINK_C. have to allocate it dynamically. */
737   GC_word *live_indicators = 0;
738 #endif
739
740 int live_indicators_count = 0;
741
742 tn * mktree(int n)
743 {
744     tn * result = (tn *)GC_MALLOC(sizeof(tn));
745
746     collectable_count++;
747 #   if defined(MACOS)
748         /* get around static data limitations. */
749         if (!live_indicators) {
750           live_indicators =
751                     (GC_word*)NewPtrClear(MAX_FINALIZED * sizeof(GC_word));
752           CHECK_OUT_OF_MEMORY(live_indicators);
753         }
754 #   endif
755     if (n == 0) return(0);
756     CHECK_OUT_OF_MEMORY(result);
757     result -> level = n;
758     result -> lchild = mktree(n-1);
759     result -> rchild = mktree(n-1);
760     if (counter++ % 17 == 0 && n >= 2) {
761         tn * tmp;
762
763         CHECK_OUT_OF_MEMORY(result->lchild);
764         tmp = result -> lchild -> rchild;
765         CHECK_OUT_OF_MEMORY(result->rchild);
766         result -> lchild -> rchild = result -> rchild -> lchild;
767         result -> rchild -> lchild = tmp;
768     }
769     if (counter++ % 119 == 0) {
770         int my_index;
771
772         {
773 #         ifdef PCR
774             PCR_ThCrSec_EnterSys();
775 #         endif
776 #         if defined(GC_PTHREADS)
777             static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
778             pthread_mutex_lock(&incr_lock);
779 #         elif defined(GC_WIN32_THREADS)
780             EnterCriticalSection(&incr_cs);
781 #         endif
782                 /* Losing a count here causes erroneous report of failure. */
783           finalizable_count++;
784           my_index = live_indicators_count++;
785 #         ifdef PCR
786             PCR_ThCrSec_ExitSys();
787 #         endif
788 #         if defined(GC_PTHREADS)
789             pthread_mutex_unlock(&incr_lock);
790 #         elif defined(GC_WIN32_THREADS)
791             LeaveCriticalSection(&incr_cs);
792 #         endif
793         }
794
795         GC_REGISTER_FINALIZER((void *)result, finalizer, (void *)(GC_word)n,
796                               (GC_finalization_proc *)0, (void * *)0);
797         if (my_index >= MAX_FINALIZED) {
798                 GC_printf("live_indicators overflowed\n");
799                 FAIL;
800         }
801         live_indicators[my_index] = 13;
802         if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
803                 (void * *)(&(live_indicators[my_index])),
804                 (void *)result) != 0) {
805                 GC_printf("GC_general_register_disappearing_link failed\n");
806                 FAIL;
807         }
808         if (GC_unregister_disappearing_link(
809                 (void * *)
810                    (&(live_indicators[my_index]))) == 0) {
811                 GC_printf("GC_unregister_disappearing_link failed\n");
812                 FAIL;
813         }
814         if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
815                 (void * *)(&(live_indicators[my_index])),
816                 (void *)result) != 0) {
817                 GC_printf("GC_general_register_disappearing_link failed 2\n");
818                 FAIL;
819         }
820         GC_reachable_here(result);
821     }
822     return(result);
823 }
824
825 void chktree(tn *t, int n)
826 {
827     if (n == 0 && t != 0) {
828         GC_printf("Clobbered a leaf - collector is broken\n");
829         FAIL;
830     }
831     if (n == 0) return;
832     if (t -> level != n) {
833         GC_printf("Lost a node at level %d - collector is broken\n", n);
834         FAIL;
835     }
836     if (counter++ % 373 == 0) {
837         collectable_count++;
838         (void) GC_MALLOC(counter%5001);
839     }
840     chktree(t -> lchild, n-1);
841     if (counter++ % 73 == 0) {
842         collectable_count++;
843         (void) GC_MALLOC(counter%373);
844     }
845     chktree(t -> rchild, n-1);
846 }
847
848
849 #if defined(GC_PTHREADS)
850 pthread_key_t fl_key;
851
852 void * alloc8bytes(void)
853 {
854 # if defined(SMALL_CONFIG) || defined(GC_DEBUG)
855     collectable_count++;
856     return(GC_MALLOC(8));
857 # else
858     void ** my_free_list_ptr;
859     void * my_free_list;
860
861     my_free_list_ptr = (void **)pthread_getspecific(fl_key);
862     if (my_free_list_ptr == 0) {
863         uncollectable_count++;
864         my_free_list_ptr = GC_NEW_UNCOLLECTABLE(void *);
865         CHECK_OUT_OF_MEMORY(my_free_list_ptr);
866         if (pthread_setspecific(fl_key, my_free_list_ptr) != 0) {
867             GC_printf("pthread_setspecific failed\n");
868             FAIL;
869         }
870     }
871     my_free_list = *my_free_list_ptr;
872     if (my_free_list == 0) {
873         my_free_list = GC_malloc_many(8);
874         CHECK_OUT_OF_MEMORY(my_free_list);
875     }
876     *my_free_list_ptr = GC_NEXT(my_free_list);
877     GC_NEXT(my_free_list) = 0;
878     collectable_count++;
879     return(my_free_list);
880 # endif
881 }
882
883 #else
884 #   define alloc8bytes() GC_MALLOC_ATOMIC(8)
885 #endif
886
887 void alloc_small(int n)
888 {
889     int i;
890
891     for (i = 0; i < n; i += 8) {
892         atomic_count++;
893         if (alloc8bytes() == 0) {
894             GC_printf("Out of memory\n");
895             FAIL;
896         }
897     }
898 }
899
900 # if defined(THREADS) && defined(GC_DEBUG)
901 #   ifdef VERY_SMALL_CONFIG
902 #     define TREE_HEIGHT 12
903 #   else
904 #     define TREE_HEIGHT 15
905 #   endif
906 # else
907 #   ifdef VERY_SMALL_CONFIG
908 #     define TREE_HEIGHT 13
909 #   else
910 #     define TREE_HEIGHT 16
911 #   endif
912 # endif
913 void tree_test(void)
914 {
915     tn * root;
916     int i;
917
918     root = mktree(TREE_HEIGHT);
919 #   ifndef VERY_SMALL_CONFIG
920       alloc_small(5000000);
921 #   endif
922     chktree(root, TREE_HEIGHT);
923     if (finalized_count && ! dropped_something) {
924         GC_printf("Premature finalization - collector is broken\n");
925         FAIL;
926     }
927     dropped_something = 1;
928     GC_noop1((word)root);       /* Root needs to remain live until      */
929                                 /* dropped_something is set.            */
930     root = mktree(TREE_HEIGHT);
931     chktree(root, TREE_HEIGHT);
932     for (i = TREE_HEIGHT; i >= 0; i--) {
933         root = mktree(i);
934         chktree(root, i);
935     }
936 #   ifndef VERY_SMALL_CONFIG
937       alloc_small(5000000);
938 #   endif
939 }
940
941 unsigned n_tests = 0;
942
943 GC_word bm_huge[10] = {
944     0xffffffff,
945     0xffffffff,
946     0xffffffff,
947     0xffffffff,
948     0xffffffff,
949     0xffffffff,
950     0xffffffff,
951     0xffffffff,
952     0xffffffff,
953     0x00ffffff,
954 };
955
956 /* A very simple test of explicitly typed allocation    */
957 void typed_test(void)
958 {
959     GC_word * old, * new;
960     GC_word bm3 = 0x3;
961     GC_word bm2 = 0x2;
962     GC_word bm_large = 0xf7ff7fff;
963     GC_descr d1 = GC_make_descriptor(&bm3, 2);
964     GC_descr d2 = GC_make_descriptor(&bm2, 2);
965     GC_descr d3 = GC_make_descriptor(&bm_large, 32);
966     GC_descr d4 = GC_make_descriptor(bm_huge, 320);
967     GC_word * x = (GC_word *)GC_malloc_explicitly_typed(2000, d4);
968     int i;
969
970 #   ifndef LINT
971       (void)GC_make_descriptor(&bm_large, 32);
972 #   endif
973     collectable_count++;
974     old = 0;
975     for (i = 0; i < 4000; i++) {
976         collectable_count++;
977         new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d1);
978         CHECK_OUT_OF_MEMORY(new);
979         if (0 != new[0] || 0 != new[1]) {
980             GC_printf("Bad initialization by GC_malloc_explicitly_typed\n");
981             FAIL;
982         }
983         new[0] = 17;
984         new[1] = (GC_word)old;
985         old = new;
986         collectable_count++;
987         new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d2);
988         CHECK_OUT_OF_MEMORY(new);
989         new[0] = 17;
990         new[1] = (GC_word)old;
991         old = new;
992         collectable_count++;
993         new = (GC_word *) GC_malloc_explicitly_typed(33 * sizeof(GC_word), d3);
994         CHECK_OUT_OF_MEMORY(new);
995         new[0] = 17;
996         new[1] = (GC_word)old;
997         old = new;
998         collectable_count++;
999         new = (GC_word *) GC_calloc_explicitly_typed(4, 2 * sizeof(GC_word),
1000                                                      d1);
1001         CHECK_OUT_OF_MEMORY(new);
1002         new[0] = 17;
1003         new[1] = (GC_word)old;
1004         old = new;
1005         collectable_count++;
1006         if (i & 0xff) {
1007           new = (GC_word *) GC_calloc_explicitly_typed(7, 3 * sizeof(GC_word),
1008                                                      d2);
1009         } else {
1010           new = (GC_word *) GC_calloc_explicitly_typed(1001,
1011                                                        3 * sizeof(GC_word),
1012                                                        d2);
1013           if (new && (0 != new[0] || 0 != new[1])) {
1014             GC_printf("Bad initialization by GC_malloc_explicitly_typed\n");
1015             FAIL;
1016           }
1017         }
1018         CHECK_OUT_OF_MEMORY(new);
1019         new[0] = 17;
1020         new[1] = (GC_word)old;
1021         old = new;
1022     }
1023     for (i = 0; i < 20000; i++) {
1024         if (new[0] != 17) {
1025             GC_printf("typed alloc failed at %lu\n", (unsigned long)i);
1026             FAIL;
1027         }
1028         new[0] = 0;
1029         old = new;
1030         new = (GC_word *)(old[1]);
1031     }
1032     GC_gcollect();
1033     GC_noop1((word)x);
1034 }
1035
1036 int fail_count = 0;
1037
1038 /*ARGSUSED*/
1039 void GC_CALLBACK fail_proc1(void * x)
1040 {
1041     fail_count++;
1042 }
1043
1044 static void uniq(void *p, ...) {
1045   va_list a;
1046   void *q[100];
1047   int n = 0, i, j;
1048   q[n++] = p;
1049   va_start(a,p);
1050   for (;(q[n] = va_arg(a,void *)) != NULL;n++) ;
1051   va_end(a);
1052   for (i=0; i<n; i++)
1053     for (j=0; j<i; j++)
1054       if (q[i] == q[j]) {
1055         GC_printf(
1056               "Apparently failed to mark from some function arguments.\n"
1057               "Perhaps GC_push_regs was configured incorrectly?\n"
1058         );
1059         FAIL;
1060       }
1061 }
1062
1063 #ifdef THREADS
1064 #   define TEST_FAIL_COUNT(n) 1
1065 #else
1066 #   define TEST_FAIL_COUNT(n) (fail_count >= (n))
1067 #endif
1068
1069 void * GC_CALLBACK inc_int_counter(void *pcounter)
1070 {
1071  ++(*(int *)pcounter);
1072  return NULL;
1073 }
1074
1075 void run_one_test(void)
1076 {
1077 #   ifndef DBG_HDRS_ALL
1078         char *x;
1079         char **z;
1080 #       ifdef LINT
1081             char *y = 0;
1082 #       else
1083             char *y = (char *)(GC_word)fail_proc1;
1084 #       endif
1085         CLOCK_TYPE typed_time;
1086 #   endif
1087     CLOCK_TYPE start_time;
1088     CLOCK_TYPE reverse_time;
1089     CLOCK_TYPE tree_time;
1090     unsigned long time_diff;
1091
1092 #   ifdef FIND_LEAK
1093         GC_printf(
1094               "This test program is not designed for leak detection mode\n");
1095         GC_printf("Expect lots of problems\n");
1096 #   endif
1097     GC_FREE(0);
1098 #   ifndef DBG_HDRS_ALL
1099       collectable_count += 3;
1100       if ((GC_size(GC_malloc(7)) != 8 &&
1101            GC_size(GC_malloc(7)) != MIN_WORDS * sizeof(GC_word))
1102            || GC_size(GC_malloc(15)) != 16) {
1103         GC_printf("GC_size produced unexpected results\n");
1104         FAIL;
1105       }
1106       collectable_count += 1;
1107       if (GC_size(GC_malloc(0)) != MIN_WORDS * sizeof(GC_word)) {
1108         GC_printf("GC_malloc(0) failed: GC_size returns %ld\n",
1109                       (unsigned long)GC_size(GC_malloc(0)));
1110         FAIL;
1111       }
1112       collectable_count += 1;
1113       if (GC_size(GC_malloc_uncollectable(0)) != MIN_WORDS * sizeof(GC_word)) {
1114         GC_printf("GC_malloc_uncollectable(0) failed\n");
1115         FAIL;
1116       }
1117       GC_is_valid_displacement_print_proc = fail_proc1;
1118       GC_is_visible_print_proc = fail_proc1;
1119       collectable_count += 1;
1120       x = GC_malloc(16);
1121       if (GC_base(GC_PTR_ADD(x, 13)) != x) {
1122         GC_printf("GC_base(heap ptr) produced incorrect result\n");
1123         FAIL;
1124       }
1125       (void)GC_PRE_INCR(x, 0);
1126       (void)GC_POST_INCR(x);
1127       (void)GC_POST_DECR(x);
1128       if (GC_base(x) != x) {
1129         GC_printf("Bad INCR/DECR result\n");
1130         FAIL;
1131       }
1132 #     ifndef PCR
1133         if (GC_base(y) != 0) {
1134           GC_printf("GC_base(fn_ptr) produced incorrect result\n");
1135           FAIL;
1136         }
1137 #     endif
1138       if (GC_same_obj(x+5, x) != x + 5) {
1139         GC_printf("GC_same_obj produced incorrect result\n");
1140         FAIL;
1141       }
1142       if (GC_is_visible(y) != y || GC_is_visible(x) != x) {
1143         GC_printf("GC_is_visible produced incorrect result\n");
1144         FAIL;
1145       }
1146       z = GC_malloc(8);
1147       GC_PTR_STORE(z, x);
1148       if (*z != x) {
1149         GC_printf("GC_PTR_STORE failed: %p != %p\n", *z, x);
1150         FAIL;
1151       }
1152       if (!TEST_FAIL_COUNT(1)) {
1153 #       if!(defined(POWERPC) || defined(IA64)) || defined(M68K)
1154           /* On POWERPCs function pointers point to a descriptor in the */
1155           /* data segment, so there should have been no failures.       */
1156           /* The same applies to IA64.  Something similar seems to      */
1157           /* be going on with NetBSD/M68K.                              */
1158           GC_printf("GC_is_visible produced wrong failure indication\n");
1159           FAIL;
1160 #       endif
1161       }
1162       if (GC_is_valid_displacement(y) != y
1163         || GC_is_valid_displacement(x) != x
1164         || GC_is_valid_displacement(x + 3) != x + 3) {
1165         GC_printf("GC_is_valid_displacement produced incorrect result\n");
1166         FAIL;
1167       }
1168         {
1169           size_t i;
1170
1171           GC_malloc(17);
1172           for (i = sizeof(GC_word); i < 512; i *= 2) {
1173             GC_word result = (GC_word) GC_memalign(i, 17);
1174             if (result % i != 0 || result == 0 || *(int *)result != 0) FAIL;
1175           }
1176         }
1177 #     ifndef ALL_INTERIOR_POINTERS
1178 #      if defined(RS6000) || defined(POWERPC)
1179         if (!TEST_FAIL_COUNT(1))
1180 #      else
1181         if (!TEST_FAIL_COUNT(GC_get_all_interior_pointers() ? 1 : 2))
1182 #      endif
1183         {
1184           GC_printf(
1185               "GC_is_valid_displacement produced wrong failure indication\n");
1186           FAIL;
1187         }
1188 #     endif
1189 #   endif /* DBG_HDRS_ALL */
1190     /* Test floating point alignment */
1191         collectable_count += 2;
1192         {
1193           double *dp = GC_MALLOC(sizeof(double));
1194           CHECK_OUT_OF_MEMORY(dp);
1195           *dp = 1.0;
1196           dp = GC_MALLOC(sizeof(double));
1197           CHECK_OUT_OF_MEMORY(dp);
1198           *dp = 1.0;
1199         }
1200     /* Test size 0 allocation a bit more */
1201         {
1202            size_t i;
1203            for (i = 0; i < 10000; ++i) {
1204              GC_MALLOC(0);
1205              GC_FREE(GC_MALLOC(0));
1206              GC_MALLOC_ATOMIC(0);
1207              GC_FREE(GC_MALLOC_ATOMIC(0));
1208            }
1209          }
1210 #   ifdef GC_GCJ_SUPPORT
1211       GC_REGISTER_DISPLACEMENT(sizeof(struct fake_vtable *));
1212       GC_init_gcj_malloc(0, (void *)(GC_word)fake_gcj_mark_proc);
1213 #   endif
1214     /* Make sure that fn arguments are visible to the collector.        */
1215       uniq(
1216         GC_malloc(12), GC_malloc(12), GC_malloc(12),
1217         (GC_gcollect(),GC_malloc(12)),
1218         GC_malloc(12), GC_malloc(12), GC_malloc(12),
1219         (GC_gcollect(),GC_malloc(12)),
1220         GC_malloc(12), GC_malloc(12), GC_malloc(12),
1221         (GC_gcollect(),GC_malloc(12)),
1222         GC_malloc(12), GC_malloc(12), GC_malloc(12),
1223         (GC_gcollect(),GC_malloc(12)),
1224         GC_malloc(12), GC_malloc(12), GC_malloc(12),
1225         (GC_gcollect(),GC_malloc(12)),
1226         (void *)0);
1227     /* GC_malloc(0) must return NULL or something we can deallocate. */
1228         GC_free(GC_malloc(0));
1229         GC_free(GC_malloc_atomic(0));
1230         GC_free(GC_malloc(0));
1231         GC_free(GC_malloc_atomic(0));
1232     /* Repeated list reversal test. */
1233         GET_TIME(start_time);
1234         reverse_test();
1235         if (print_stats) {
1236           GET_TIME(reverse_time);
1237           time_diff = MS_TIME_DIFF(reverse_time, start_time);
1238           GC_log_printf("-------------Finished reverse_test at time %u (%p)\n",
1239                         (unsigned) time_diff, &start_time);
1240         }
1241 #   ifndef DBG_HDRS_ALL
1242       typed_test();
1243       if (print_stats) {
1244         GET_TIME(typed_time);
1245         time_diff = MS_TIME_DIFF(typed_time, start_time);
1246         GC_log_printf("-------------Finished typed_test at time %u (%p)\n",
1247                       (unsigned) time_diff, &start_time);
1248       }
1249 #   endif /* DBG_HDRS_ALL */
1250     tree_test();
1251     if (print_stats) {
1252       GET_TIME(tree_time);
1253       time_diff = MS_TIME_DIFF(tree_time, start_time);
1254       GC_log_printf("-------------Finished tree_test at time %u (%p)\n",
1255                     (unsigned) time_diff, &start_time);
1256     }
1257     /* Run reverse_test a second time, so we hopefully notice corruption. */
1258       reverse_test();
1259       if (print_stats) {
1260         GET_TIME(reverse_time);
1261         time_diff = MS_TIME_DIFF(reverse_time, start_time);
1262         GC_log_printf(
1263                 "-------------Finished second reverse_test at time %u (%p)\n",
1264                 (unsigned)time_diff, &start_time);
1265       }
1266     /* GC_allocate_ml and GC_need_to_lock are no longer exported, and   */
1267     /* AO_fetch_and_add1() may be unavailable to update a counter.      */
1268     (void)GC_call_with_alloc_lock(inc_int_counter, &n_tests);
1269 #   ifndef NO_TEST_HANDLE_FORK
1270       if (fork() == 0) {
1271         GC_gcollect();
1272         tiny_reverse_test(0);
1273         GC_gcollect();
1274         if (print_stats)
1275           GC_log_printf("Finished a child process\n");
1276         exit(0);
1277       }
1278 #   endif
1279     if (print_stats)
1280       GC_log_printf("Finished %p\n", &start_time);
1281 }
1282
1283 #define NUMBER_ROUND_UP(v, bound) ((((v) + (bound) - 1) / (bound)) * (bound))
1284
1285 void check_heap_stats(void)
1286 {
1287     size_t max_heap_sz;
1288     int i;
1289     int still_live;
1290 #   ifdef FINALIZE_ON_DEMAND
1291         int late_finalize_count = 0;
1292 #   endif
1293
1294 #   ifdef VERY_SMALL_CONFIG
1295     /* The upper bounds are a guess, which has been empirically */
1296     /* adjusted.  On low end uniprocessors with incremental GC  */
1297     /* these may be particularly dubious, since empirically the */
1298     /* heap tends to grow largely as a result of the GC not     */
1299     /* getting enough cycles.                                   */
1300 #     if CPP_WORDSZ == 64
1301         max_heap_sz = 4500000;
1302 #     else
1303         max_heap_sz = 2800000;
1304 #     endif
1305 #   else
1306 #     if CPP_WORDSZ == 64
1307         max_heap_sz = 23000000;
1308 #     else
1309         max_heap_sz = 16000000;
1310 #     endif
1311 #   endif
1312 #   ifdef GC_DEBUG
1313         max_heap_sz *= 2;
1314 #       ifdef SAVE_CALL_CHAIN
1315             max_heap_sz *= 3;
1316 #           ifdef SAVE_CALL_COUNT
1317                 max_heap_sz += max_heap_sz * SAVE_CALL_COUNT/4;
1318 #           endif
1319 #       endif
1320 #   endif
1321     max_heap_sz *= n_tests;
1322 #   if defined(USE_MMAP) || defined(MSWIN32)
1323       max_heap_sz = NUMBER_ROUND_UP(max_heap_sz, 4 * 1024 * 1024);
1324 #   endif
1325     /* Garbage collect repeatedly so that all inaccessible objects      */
1326     /* can be finalized.                                                */
1327       while (GC_collect_a_little()) { }
1328       for (i = 0; i < 16; i++) {
1329         GC_gcollect();
1330 #   ifdef FINALIZE_ON_DEMAND
1331            late_finalize_count +=
1332 #   endif
1333                 GC_invoke_finalizers();
1334       }
1335       if (print_stats) {
1336           GC_log_printf("Primordial thread stack bottom: %p\n",
1337                         GC_stackbottom);
1338       }
1339     GC_printf("Completed %u tests\n", n_tests);
1340     GC_printf("Allocated %d collectable objects\n", collectable_count);
1341     GC_printf("Allocated %d uncollectable objects\n",
1342                   uncollectable_count);
1343     GC_printf("Allocated %d atomic objects\n", atomic_count);
1344     GC_printf("Allocated %d stubborn objects\n", stubborn_count);
1345     GC_printf("Finalized %d/%d objects - ",
1346                   finalized_count, finalizable_count);
1347 #   ifdef FINALIZE_ON_DEMAND
1348         if (finalized_count != late_finalize_count) {
1349             GC_printf("Demand finalization error\n");
1350             FAIL;
1351         }
1352 #   endif
1353     if (finalized_count > finalizable_count
1354         || finalized_count < finalizable_count/2) {
1355         GC_printf("finalization is probably broken\n");
1356         FAIL;
1357     } else {
1358         GC_printf("finalization is probably ok\n");
1359     }
1360     still_live = 0;
1361     for (i = 0; i < MAX_FINALIZED; i++) {
1362         if (live_indicators[i] != 0) {
1363             still_live++;
1364         }
1365     }
1366     i = finalizable_count - finalized_count - still_live;
1367     if (0 != i) {
1368         GC_printf("%d disappearing links remain and %d more objects "
1369                       "were not finalized\n", still_live, i);
1370         if (i > 10) {
1371             GC_printf("\tVery suspicious!\n");
1372         } else {
1373             GC_printf("\tSlightly suspicious, but probably OK\n");
1374         }
1375     }
1376     GC_printf("Total number of bytes allocated is %lu\n",
1377                   (unsigned long)GC_get_total_bytes());
1378     GC_printf("Final heap size is %lu bytes\n",
1379                   (unsigned long)GC_get_heap_size());
1380     if (GC_get_total_bytes() < n_tests *
1381 #   ifdef VERY_SMALL_CONFIG
1382         2700000
1383 #   else
1384         33500000
1385 #   endif
1386         ) {
1387       GC_printf("Incorrect execution - missed some allocations\n");
1388       FAIL;
1389     }
1390     if (GC_get_heap_size() + GC_get_unmapped_bytes() > max_heap_sz) {
1391         GC_printf("Unexpected heap growth - collector may be broken"
1392                   " (heapsize: %lu, expected: %lu)\n",
1393             (unsigned long)(GC_get_heap_size() + GC_get_unmapped_bytes()),
1394             (unsigned long)max_heap_sz);
1395         FAIL;
1396     }
1397 #   ifdef THREADS
1398       GC_unregister_my_thread(); /* just to check it works (for main) */
1399 #   endif
1400     GC_printf("Collector appears to work\n");
1401 }
1402
1403 #if defined(MACOS)
1404 void SetMinimumStack(long minSize)
1405 {
1406         long newApplLimit;
1407
1408         if (minSize > LMGetDefltStack())
1409         {
1410                 newApplLimit = (long) GetApplLimit()
1411                                 - (minSize - LMGetDefltStack());
1412                 SetApplLimit((Ptr) newApplLimit);
1413                 MaxApplZone();
1414         }
1415 }
1416
1417 #define cMinStackSpace (512L * 1024L)
1418
1419 #endif
1420
1421 void GC_CALLBACK warn_proc(char *msg, GC_word p)
1422 {
1423     GC_printf(msg, (unsigned long)p);
1424     /*FAIL;*/
1425 }
1426
1427 #if defined(MSWINCE) && defined(UNDER_CE)
1428 # define WINMAIN_LPTSTR LPWSTR
1429 #else
1430 # define WINMAIN_LPTSTR LPSTR
1431 #endif
1432
1433 #if !defined(PCR) && !defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) \
1434     || defined(LINT)
1435 #if defined(MSWIN32) && !defined(__MINGW32__) || defined(MSWINCE)
1436   int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev,
1437                        WINMAIN_LPTSTR cmd, int n)
1438 #elif defined(RTEMS)
1439 # include <bsp.h>
1440 # define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
1441 # define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
1442 # define CONFIGURE_RTEMS_INIT_TASKS_TABLE
1443 # define CONFIGURE_MAXIMUM_TASKS 1
1444 # define CONFIGURE_INIT
1445 # define CONFIGURE_INIT_TASK_STACK_SIZE (64*1024)
1446 # include <rtems/confdefs.h>
1447   rtems_task Init(rtems_task_argument ignord)
1448 #else
1449   int main(void)
1450 #endif
1451 {
1452     n_tests = 0;
1453 #   if defined(MACOS)
1454         /* Make sure we have lots and lots of stack space.      */
1455         SetMinimumStack(cMinStackSpace);
1456         /* Cheat and let stdio initialize toolbox for us.       */
1457         printf("Testing GC Macintosh port\n");
1458 #   endif
1459     GC_COND_INIT();
1460     GC_set_warn_proc(warn_proc);
1461 #   if (defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(GWW_VDB)) \
1462           && !defined(MAKE_BACK_GRAPH) && !defined(NO_INCREMENTAL)
1463       GC_enable_incremental();
1464       GC_printf("Switched to incremental mode\n");
1465 #     if defined(MPROTECT_VDB)
1466         GC_printf("Emulating dirty bits with mprotect/signals\n");
1467 #     else
1468 #       ifdef PROC_VDB
1469           GC_printf("Reading dirty bits from /proc\n");
1470 #       elif defined(GWW_VDB)
1471           GC_printf("Using GetWriteWatch-based implementation\n");
1472 #       else
1473           GC_printf("Using DEFAULT_VDB dirty bit implementation\n");
1474 #       endif
1475 #      endif
1476 #   endif
1477     run_one_test();
1478     check_heap_stats();
1479 #   ifndef MSWINCE
1480       fflush(stdout);
1481 #   endif
1482 #   ifdef LINT
1483         /* Entry points we should be testing, but aren't.                  */
1484         /* Some can be tested by defining GC_DEBUG at the top of this file */
1485         /* This is a bit SunOS4 specific.                                  */
1486         GC_noop(GC_expand_hp, GC_add_roots, GC_clear_roots,
1487                 GC_register_disappearing_link,
1488                 GC_register_finalizer_ignore_self,
1489                 GC_debug_register_displacement, GC_debug_change_stubborn,
1490                 GC_debug_end_stubborn_change, GC_debug_malloc_uncollectable,
1491                 GC_debug_free, GC_debug_realloc,
1492                 GC_generic_malloc_words_small, GC_init,
1493                 GC_malloc_ignore_off_page, GC_malloc_atomic_ignore_off_page,
1494                 GC_set_max_heap_size, GC_get_bytes_since_gc,
1495                 GC_get_total_bytes, GC_pre_incr, GC_post_incr);
1496 #   endif
1497 #   ifdef MSWIN32
1498       GC_win32_free_heap();
1499 #   endif
1500 #   ifdef RTEMS
1501       exit(0);
1502 #   else
1503       return(0);
1504 #   endif
1505 }
1506 # endif
1507
1508 #if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
1509
1510 DWORD __stdcall thr_run_one_test(void *arg)
1511 {
1512   run_one_test();
1513   return 0;
1514 }
1515
1516 #ifdef MSWINCE
1517 HANDLE win_created_h;
1518 HWND win_handle;
1519
1520 LRESULT CALLBACK window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1521 {
1522   LRESULT ret = 0;
1523   switch (uMsg) {
1524     case WM_HIBERNATE:
1525       GC_printf("Received WM_HIBERNATE, calling GC_gcollect\n");
1526       /* Force "unmap as much memory as possible" mode. */
1527       GC_gcollect_and_unmap();
1528       break;
1529     case WM_CLOSE:
1530       GC_printf("Received WM_CLOSE, closing window\n");
1531       DestroyWindow(hwnd);
1532       break;
1533     case WM_DESTROY:
1534       PostQuitMessage(0);
1535       break;
1536     default:
1537       ret = DefWindowProc(hwnd, uMsg, wParam, lParam);
1538       break;
1539   }
1540   return ret;
1541 }
1542
1543 DWORD __stdcall thr_window(void *arg)
1544 {
1545   WNDCLASS win_class = {
1546     CS_NOCLOSE,
1547     window_proc,
1548     0,
1549     0,
1550     GetModuleHandle(NULL),
1551     NULL,
1552     NULL,
1553     (HBRUSH)(COLOR_APPWORKSPACE+1),
1554     NULL,
1555     TEXT("GCtestWindow")
1556   };
1557   MSG msg;
1558
1559   if (!RegisterClass(&win_class))
1560     FAIL;
1561
1562   win_handle = CreateWindowEx(
1563     0,
1564     TEXT("GCtestWindow"),
1565     TEXT("GCtest"),
1566     0,
1567     CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1568     NULL,
1569     NULL,
1570     GetModuleHandle(NULL),
1571     NULL);
1572
1573   if (win_handle == NULL)
1574     FAIL;
1575
1576   SetEvent(win_created_h);
1577
1578   ShowWindow(win_handle, SW_SHOW);
1579   UpdateWindow(win_handle);
1580
1581   while (GetMessage(&msg, NULL, 0, 0)) {
1582     TranslateMessage(&msg);
1583     DispatchMessage(&msg);
1584   }
1585
1586   return 0;
1587 }
1588 #endif
1589
1590 int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev,
1591                      WINMAIN_LPTSTR cmd, int n)
1592 {
1593 # if NTHREADS > 0
1594    HANDLE h[NTHREADS];
1595    int i;
1596 # endif
1597 # ifdef MSWINCE
1598     HANDLE win_thr_h;
1599 # endif
1600   DWORD thread_id;
1601 # if defined(GC_DLL) && !defined(GC_NO_THREADS_DISCOVERY) \
1602         && !defined(MSWINCE) && !defined(THREAD_LOCAL_ALLOC) \
1603         && !defined(PARALLEL_MARK)
1604     GC_use_threads_discovery();
1605                 /* Test with implicit thread registration if possible. */
1606     GC_printf("Using DllMain to track threads\n");
1607 # endif
1608   GC_COND_INIT();
1609 # if !defined(MAKE_BACK_GRAPH) && !defined(NO_INCREMENTAL)
1610     GC_enable_incremental();
1611 # endif
1612   InitializeCriticalSection(&incr_cs);
1613   GC_set_warn_proc(warn_proc);
1614 # ifdef MSWINCE
1615     win_created_h = CreateEvent(NULL, FALSE, FALSE, NULL);
1616     if (win_created_h == (HANDLE)NULL) {
1617       GC_printf("Event creation failed %d\n", (int)GetLastError());
1618       FAIL;
1619     }
1620     win_thr_h = GC_CreateThread(NULL, 0, thr_window, 0, 0, &thread_id);
1621     if (win_thr_h == (HANDLE)NULL) {
1622       GC_printf("Thread creation failed %d\n", (int)GetLastError());
1623       FAIL;
1624     }
1625     if (WaitForSingleObject(win_created_h, INFINITE) != WAIT_OBJECT_0)
1626       FAIL;
1627     CloseHandle(win_created_h);
1628 # endif
1629 # if NTHREADS > 0
1630    for (i = 0; i < NTHREADS; i++) {
1631     h[i] = GC_CreateThread(NULL, 0, thr_run_one_test, 0, 0, &thread_id);
1632     if (h[i] == (HANDLE)NULL) {
1633       GC_printf("Thread creation failed %d\n", (int)GetLastError());
1634       FAIL;
1635     }
1636    }
1637 # endif /* NTHREADS > 0 */
1638   run_one_test();
1639 # if NTHREADS > 0
1640    for (i = 0; i < NTHREADS; i++) {
1641     if (WaitForSingleObject(h[i], INFINITE) != WAIT_OBJECT_0) {
1642       GC_printf("Thread wait failed %d\n", (int)GetLastError());
1643       FAIL;
1644     }
1645    }
1646 # endif /* NTHREADS > 0 */
1647 # ifdef MSWINCE
1648     PostMessage(win_handle, WM_CLOSE, 0, 0);
1649     if (WaitForSingleObject(win_thr_h, INFINITE) != WAIT_OBJECT_0)
1650       FAIL;
1651 # endif
1652   check_heap_stats();
1653   return(0);
1654 }
1655
1656 #endif /* GC_WIN32_THREADS */
1657
1658
1659 #ifdef PCR
1660 int test(void)
1661 {
1662     PCR_Th_T * th1;
1663     PCR_Th_T * th2;
1664     int code;
1665
1666     n_tests = 0;
1667     /* GC_enable_incremental(); */
1668     GC_set_warn_proc(warn_proc);
1669     th1 = PCR_Th_Fork(run_one_test, 0);
1670     th2 = PCR_Th_Fork(run_one_test, 0);
1671     run_one_test();
1672     if (PCR_Th_T_Join(th1, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
1673         != PCR_ERes_okay || code != 0) {
1674         GC_printf("Thread 1 failed\n");
1675     }
1676     if (PCR_Th_T_Join(th2, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
1677         != PCR_ERes_okay || code != 0) {
1678         GC_printf("Thread 2 failed\n");
1679     }
1680     check_heap_stats();
1681     return(0);
1682 }
1683 #endif
1684
1685 #if defined(GC_PTHREADS)
1686 void * thr_run_one_test(void * arg)
1687 {
1688     run_one_test();
1689     return(0);
1690 }
1691
1692 #ifdef GC_DEBUG
1693 #  define GC_free GC_debug_free
1694 #endif
1695
1696 int main(void)
1697 {
1698     pthread_t th[NTHREADS];
1699     pthread_attr_t attr;
1700     int code;
1701     int i;
1702 #   ifdef GC_IRIX_THREADS
1703         /* Force a larger stack to be preallocated      */
1704         /* Since the initial can't always grow later.   */
1705         *((volatile char *)&code - 1024*1024) = 0;      /* Require 1 MB */
1706 #   endif /* GC_IRIX_THREADS */
1707 #   if defined(GC_HPUX_THREADS)
1708         /* Default stack size is too small, especially with the 64 bit ABI */
1709         /* Increase it.                                                    */
1710         if (pthread_default_stacksize_np(1024*1024, 0) != 0) {
1711           GC_printf("pthread_default_stacksize_np failed\n");
1712         }
1713 #   endif       /* GC_HPUX_THREADS */
1714 #   ifdef PTW32_STATIC_LIB
1715         pthread_win32_process_attach_np ();
1716         pthread_win32_thread_attach_np ();
1717 #   endif
1718 #   if defined(GC_DARWIN_THREADS) && !defined(GC_NO_THREADS_DISCOVERY) \
1719         && !defined(DARWIN_DONT_PARSE_STACK) && !defined(THREAD_LOCAL_ALLOC)
1720       /* Test with the Darwin implicit thread registration. */
1721       GC_use_threads_discovery();
1722       GC_printf("Using Darwin task-threads-based world stop and push\n");
1723 #   endif
1724     GC_COND_INIT();
1725
1726     pthread_attr_init(&attr);
1727 #   if defined(GC_IRIX_THREADS) || defined(GC_FREEBSD_THREADS) \
1728         || defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS) \
1729         || defined(GC_OPENBSD_THREADS)
1730         pthread_attr_setstacksize(&attr, 1000000);
1731 #   endif
1732     n_tests = 0;
1733 #   if (defined(MPROTECT_VDB)) && !defined(REDIRECT_MALLOC) \
1734             && !defined(MAKE_BACK_GRAPH) && !defined(USE_PROC_FOR_LIBRARIES) \
1735             && !defined(NO_INCREMENTAL)
1736         GC_enable_incremental();
1737         GC_printf("Switched to incremental mode\n");
1738 #     if defined(MPROTECT_VDB)
1739         GC_printf("Emulating dirty bits with mprotect/signals\n");
1740 #     else
1741 #       ifdef PROC_VDB
1742           GC_printf("Reading dirty bits from /proc\n");
1743 #       else
1744           GC_printf("Using DEFAULT_VDB dirty bit implementation\n");
1745 #       endif
1746 #     endif
1747 #   endif
1748     GC_set_warn_proc(warn_proc);
1749     if ((code = pthread_key_create(&fl_key, 0)) != 0) {
1750         GC_printf("Key creation failed %d\n", code);
1751         FAIL;
1752     }
1753     for (i = 0; i < NTHREADS; ++i) {
1754       if ((code = pthread_create(th+i, &attr, thr_run_one_test, 0)) != 0) {
1755         GC_printf("Thread %d creation failed %d\n", i, code);
1756         FAIL;
1757       }
1758     }
1759     run_one_test();
1760     for (i = 0; i < NTHREADS; ++i) {
1761       if ((code = pthread_join(th[i], 0)) != 0) {
1762         GC_printf("Thread %d failed %d\n", i, code);
1763         FAIL;
1764       }
1765     }
1766     check_heap_stats();
1767     (void)fflush(stdout);
1768     pthread_attr_destroy(&attr);
1769     GC_printf("Completed %u collections\n", (unsigned)GC_get_gc_no());
1770 #   ifdef PTW32_STATIC_LIB
1771         pthread_win32_thread_detach_np ();
1772         pthread_win32_process_detach_np ();
1773 #   endif
1774     return(0);
1775 }
1776 #endif /* GC_PTHREADS */