OSDN Git Service

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