OSDN Git Service

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