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