home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / sa104os2.zip / SATHR104.ZIP / SATHER / SYSTEM / GC / TEST.C < prev    next >
C/C++ Source or Header  |  1994-11-08  |  23KB  |  907 lines

  1. /* 
  2.  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  3.  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  4.  *
  5.  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  6.  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
  7.  *
  8.  * Permission is hereby granted to use or copy this program
  9.  * for any purpose,  provided the above notices are retained on all copies.
  10.  * Permission to modify the code and to distribute modified code is granted,
  11.  * provided the above notices are retained, and a notice that the code was
  12.  * modified is included with the above copyright notice.
  13.  */
  14. /* Boehm, November 8, 1994 5:50 pm PST */
  15. /* An incomplete test for the garbage collector.          */
  16. /* Some more obscure entry points are not tested at all.    */
  17.  
  18. # if defined(mips) && defined(SYSTYPE_BSD43)
  19.     /* MIPS RISCOS 4 */
  20. # else
  21. #   include <stdlib.h>
  22. # endif
  23. # include <stdio.h>
  24. # include "gc.h"
  25. # include "gc_typed.h"
  26. # include "gc_priv.h"    /* For output and some statistics    */
  27. # include "config.h"
  28.  
  29. # ifdef MSWIN32
  30. #   include <windows.h>
  31. # endif
  32.  
  33. # ifdef PCR
  34. #   include "th/PCR_ThCrSec.h"
  35. #   include "th/PCR_Th.h"
  36. # endif
  37.  
  38. # ifdef SOLARIS_THREADS
  39. #   include <thread.h>
  40. #   include <synch.h>
  41. # endif
  42.  
  43. # if defined(PCR) || defined(SOLARIS_THREADS)
  44. #   define THREADS
  45. # endif
  46.  
  47. # ifdef AMIGA
  48.    long __stack = 200000;
  49. # endif
  50.  
  51. # define FAIL (void)abort()
  52.  
  53. /* AT_END may be defined to excercise the interior pointer test    */
  54. /* if the collector is configured with ALL_INTERIOR_POINTERS.   */
  55. /* As it stands, this test should succeed with either        */
  56. /* configuration.  In the FIND_LEAK configuration, it should    */
  57. /* find lots of leaks, since we free almost nothing.        */
  58.  
  59. struct SEXPR {
  60.     struct SEXPR * sexpr_car;
  61.     struct SEXPR * sexpr_cdr;
  62. };
  63.  
  64.  
  65. # ifdef __STDC__
  66.     typedef void * void_star;
  67. # else
  68.     typedef char * void_star;
  69. # endif
  70.  
  71. typedef struct SEXPR * sexpr;
  72.  
  73. # define INT_TO_SEXPR(x) ((sexpr)(unsigned long)(x))
  74.  
  75. extern sexpr cons();
  76.  
  77. # undef nil
  78. # define nil (INT_TO_SEXPR(0))
  79. # define car(x) ((x) -> sexpr_car)
  80. # define cdr(x) ((x) -> sexpr_cdr)
  81. # define is_nil(x) ((x) == nil)
  82.  
  83.  
  84. int extra_count = 0;        /* Amount of space wasted in cons node */
  85.  
  86. /* Silly implementation of Lisp cons. Intentionally wastes lots of space */
  87. /* to test collector.                                                    */
  88. sexpr cons (x, y)
  89. sexpr x;
  90. sexpr y;
  91. {
  92.     register sexpr r;
  93.     register int *p;
  94.     register my_extra = extra_count;
  95.     
  96.     r = (sexpr) GC_MALLOC_STUBBORN(sizeof(struct SEXPR) + my_extra);
  97.     if (r == 0) {
  98.         (void)GC_printf0("Out of memory\n");
  99.         exit(1);
  100.     }
  101.     for (p = (int *)r;
  102.          ((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
  103.     if (*p) {
  104.         (void)GC_printf1("Found nonzero at 0x%lx - allocator is broken\n",
  105.                      (unsigned long)p);
  106.         FAIL;
  107.         }
  108.         *p = 13;
  109.     }
  110. #   ifdef AT_END
  111.     r = (sexpr)((char *)r + (my_extra & ~7));
  112. #   endif
  113.     r -> sexpr_car = x;
  114.     r -> sexpr_cdr = y;
  115.     my_extra++;
  116.     if ( my_extra >= 5000 ) {
  117.         extra_count = 0;
  118.     } else {
  119.         extra_count = my_extra;
  120.     }
  121.     GC_END_STUBBORN_CHANGE((char *)r);
  122.     return(r);
  123. }
  124.  
  125. sexpr small_cons (x, y)
  126. sexpr x;
  127. sexpr y;
  128. {
  129.     register sexpr r;
  130.     
  131.     r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
  132.     if (r == 0) {
  133.         (void)GC_printf0("Out of memory\n");
  134.         exit(1);
  135.     }
  136.     r -> sexpr_car = x;
  137.     r -> sexpr_cdr = y;
  138.     return(r);
  139. }
  140.  
  141. sexpr small_cons_uncollectable (x, y)
  142. sexpr x;
  143. sexpr y;
  144. {
  145.     register sexpr r;
  146.     
  147.     r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR));
  148.     if (r == 0) {
  149.         (void)GC_printf0("Out of memory\n");
  150.         exit(1);
  151.     }
  152.     r -> sexpr_car = x;
  153.     r -> sexpr_cdr = (sexpr)(~(unsigned long)y);
  154.     return(r);
  155. }
  156.  
  157. /* Return reverse(x) concatenated with y */
  158. sexpr reverse1(x, y)
  159. sexpr x, y;
  160. {
  161.     if (is_nil(x)) {
  162.         return(y);
  163.     } else {
  164.         return( reverse1(cdr(x), cons(car(x), y)) );
  165.     }
  166. }
  167.  
  168. sexpr reverse(x)
  169. sexpr x;
  170. {
  171.     return( reverse1(x, nil) );
  172. }
  173.  
  174. sexpr ints(low, up)
  175. int low, up;
  176. {
  177.     if (low > up) {
  178.     return(nil);
  179.     } else {
  180.         return(small_cons(small_cons(INT_TO_SEXPR(low), nil), ints(low+1, up)));
  181.     }
  182. }
  183.  
  184. /* Too check uncollectable allocation we build lists with disguised cdr    */
  185. /* pointers, and make sure they don't go away.                */
  186. sexpr uncollectable_ints(low, up)
  187. int low, up;
  188. {
  189.     if (low > up) {
  190.     return(nil);
  191.     } else {
  192.         return(small_cons_uncollectable(small_cons(INT_TO_SEXPR(low), nil),
  193.                uncollectable_ints(low+1, up)));
  194.     }
  195. }
  196.  
  197. void check_ints(list, low, up)
  198. sexpr list;
  199. int low, up;
  200. {
  201.     if ((int)(car(car(list))) != low) {
  202.         (void)GC_printf0(
  203.            "List reversal produced incorrect list - collector is broken\n");
  204.         FAIL;
  205.     }
  206.     if (low == up) {
  207.         if (cdr(list) != nil) {
  208.            (void)GC_printf0("List too long - collector is broken\n");
  209.            FAIL;
  210.         }
  211.     } else {
  212.         check_ints(cdr(list), low+1, up);
  213.     }
  214. }
  215.  
  216. # define UNCOLLECTABLE_CDR(x) (sexpr)(~(unsigned long)(cdr(x)))
  217.  
  218. void check_uncollectable_ints(list, low, up)
  219. sexpr list;
  220. int low, up;
  221. {
  222.     if ((int)(car(car(list))) != low) {
  223.         (void)GC_printf0(
  224.            "Uncollectable list corrupted - collector is broken\n");
  225.         FAIL;
  226.     }
  227.     if (low == up) {
  228.         if (UNCOLLECTABLE_CDR(list) != nil) {
  229.            (void)GC_printf0("Uncollectable ist too long - collector is broken\n");
  230.            FAIL;
  231.         }
  232.     } else {
  233.         check_uncollectable_ints(UNCOLLECTABLE_CDR(list), low+1, up);
  234.     }
  235. }
  236.  
  237. /* Not used, but useful for debugging: */
  238. void print_int_list(x)
  239. sexpr x;
  240. {
  241.     if (is_nil(x)) {
  242.         (void)GC_printf0("NIL\n");
  243.     } else {
  244.         (void)GC_printf1("(%ld)", (long)(car(car(x))));
  245.         if (!is_nil(cdr(x))) {
  246.             (void)GC_printf0(", ");
  247.             (void)print_int_list(cdr(x));
  248.         } else {
  249.             (void)GC_printf0("\n");
  250.         }
  251.     }
  252. }
  253.  
  254. /* Try to force a to be strangely aligned */
  255. struct {
  256.   char dummy;
  257.   sexpr aa;
  258. } A;
  259. #define a A.aa
  260.  
  261. /*
  262.  * Repeatedly reverse lists built out of very different sized cons cells.
  263.  * Check that we didn't lose anything.
  264.  */
  265. void reverse_test()
  266. {
  267.     int i;
  268.     sexpr b;
  269.     sexpr c;
  270.     sexpr d;
  271.     sexpr e;
  272. #   if defined(MSWIN32) || defined(MACOS)
  273.       /* Win32S only allows 128K stacks */
  274. #     define BIG 1000
  275. #   else
  276. #     define BIG 4500
  277. #   endif
  278.  
  279.     A.dummy = 17;
  280.     a = ints(1, 49);
  281.     b = ints(1, 50);
  282.     c = ints(1, BIG);
  283.     d = uncollectable_ints(1, 100);
  284.     e = uncollectable_ints(1, 1);
  285.     /* Superficially test interior pointer recognition on stack */
  286.     c = (sexpr)((char *)c + sizeof(char *));
  287.     d = (sexpr)((char *)d + sizeof(char *));
  288. #   ifdef __STDC__
  289.         GC_FREE((void *)e);
  290. #   else
  291.         GC_FREE((char *)e);
  292. #   endif
  293.     check_ints(b,1,50);
  294.     check_ints(a,1,49);
  295.     for (i = 0; i < 50; i++) {
  296.         check_ints(b,1,50);
  297.         b = reverse(reverse(b));
  298.     }
  299.     check_ints(b,1,50);
  300.     check_ints(a,1,49);
  301.     for (i = 0; i < 60; i++) {
  302.         /* This maintains the invariant that a always points to a list of */
  303.         /* 49 integers.  Thus this is thread safe without locks,      */
  304.         /* assuming atomic pointer assignments.                  */
  305.         a = reverse(reverse(a));
  306. #    if !defined(AT_END) && !defined(THREADS)
  307.       /* This is not thread safe, since realloc explicitly deallocates */
  308.           if (i & 1) {
  309.             a = (sexpr)GC_REALLOC((void_star)a, 500);
  310.           } else {
  311.             a = (sexpr)GC_REALLOC((void_star)a, 8200);
  312.           }
  313. #    endif
  314.     }
  315.     check_ints(a,1,49);
  316.     check_ints(b,1,50);
  317.     c = (sexpr)((char *)c - sizeof(char *));
  318.     d = (sexpr)((char *)d - sizeof(char *));
  319.     check_ints(c,1,BIG);
  320.     check_uncollectable_ints(d, 1, 100);
  321. #   ifndef THREADS
  322.     a = 0;
  323. #   endif  
  324.     b = c = 0;
  325. }
  326.  
  327. /*
  328.  * The rest of this builds balanced binary trees, checks that they don't
  329.  * disappear, and tests finalization.
  330.  */
  331. typedef struct treenode {
  332.     int level;
  333.     struct treenode * lchild;
  334.     struct treenode * rchild;
  335. } tn;
  336.  
  337. int finalizable_count = 0;
  338. int finalized_count = 0;
  339. VOLATILE int dropped_something = 0;
  340.  
  341. # ifdef __STDC__
  342.   void finalizer(void * obj, void * client_data)
  343. # else
  344.   void finalizer(obj, client_data)
  345.   char * obj;
  346.   char * client_data;
  347. # endif
  348. {
  349.   tn * t = (tn *)obj;
  350.  
  351. # ifdef PCR
  352.      PCR_ThCrSec_EnterSys();
  353. # endif
  354. # ifdef SOLARIS_THREADS
  355.     static mutex_t incr_lock;
  356.     mutex_lock(&incr_lock);
  357. # endif
  358.   if ((int)client_data != t -> level) {
  359.      (void)GC_printf0("Wrong finalization data - collector is broken\n");
  360.      FAIL;
  361.   }
  362.   finalized_count++;
  363. # ifdef PCR
  364.     PCR_ThCrSec_ExitSys();
  365. # endif
  366. # ifdef SOLARIS_THREADS
  367.     mutex_unlock(&incr_lock);
  368. # endif
  369. }
  370.  
  371. size_t counter = 0;
  372.  
  373. # define MAX_FINALIZED 8000
  374.  
  375. # if !defined(MACOS)
  376.   GC_FAR GC_word live_indicators[MAX_FINALIZED] = {0};
  377. #else
  378.   /* Too big for THINK_C. have to allocate it dynamically. */
  379.   GC_word *live_indicators = 0;
  380. #endif
  381.  
  382. int live_indicators_count = 0;
  383.  
  384. tn * mktree(n)
  385. int n;
  386. {
  387.     tn * result = (tn *)GC_MALLOC(sizeof(tn));
  388.     
  389. #if defined(MACOS)
  390.     /* get around static data limitations. */
  391.     if (!live_indicators)
  392.         live_indicators =
  393.             (GC_word*)NewPtrClear(MAX_FINALIZED * sizeof(GC_word));
  394.     if (!live_indicators) {
  395.         (void)GC_printf0("Out of memory\n");
  396.         exit(1);
  397.     }
  398. #endif
  399.     if (n == 0) return(0);
  400.     if (result == 0) {
  401.         (void)GC_printf0("Out of memory\n");
  402.         exit(1);
  403.     }
  404.     result -> level = n;
  405.     result -> lchild = mktree(n-1);
  406.     result -> rchild = mktree(n-1);
  407.     if (counter++ % 17 == 0 && n >= 2) {
  408.         tn * tmp = result -> lchild -> rchild;
  409.         
  410.         result -> lchild -> rchild = result -> rchild -> lchild;
  411.         result -> rchild -> lchild = tmp;
  412.     }
  413.     if (counter++ % 119 == 0) {
  414.         int my_index;
  415.         
  416.         {
  417. #      ifdef PCR
  418.          PCR_ThCrSec_EnterSys();
  419. #      endif
  420. #      ifdef SOLARIS_THREADS
  421.         static mutex_t incr_lock;
  422.         mutex_lock(&incr_lock);
  423. #      endif
  424.         /* Losing a count here causes erroneous report of failure. */
  425.           finalizable_count++;
  426.           my_index = live_indicators_count++;
  427. #      ifdef PCR
  428.          PCR_ThCrSec_ExitSys();
  429. #      endif
  430. #      ifdef SOLARIS_THREADS
  431.         mutex_unlock(&incr_lock);
  432. #      endif
  433.     }
  434.  
  435.         GC_REGISTER_FINALIZER((void_star)result, finalizer, (void_star)n,
  436.                       (GC_finalization_proc *)0, (void_star *)0);
  437.         if (my_index >= MAX_FINALIZED) {
  438.         GC_printf0("live_indicators overflowed\n");
  439.         FAIL;
  440.     }
  441.         live_indicators[my_index] = 13;
  442.         if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
  443.              (void_star *)(&(live_indicators[my_index])),
  444.              (void_star)result) != 0) {
  445.              GC_printf0("GC_general_register_disappearing_link failed\n");
  446.              FAIL;
  447.         }
  448.         if (GC_unregister_disappearing_link(
  449.              (void_star *)
  450.                 (&(live_indicators[my_index]))) == 0) {
  451.              GC_printf0("GC_unregister_disappearing_link failed\n");
  452.              FAIL;
  453.         }
  454.         if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
  455.              (void_star *)(&(live_indicators[my_index])),
  456.              (void_star)result) != 0) {
  457.              GC_printf0("GC_general_register_disappearing_link failed 2\n");
  458.              FAIL;
  459.         }
  460.     }
  461.     return(result);
  462. }
  463.  
  464. void chktree(t,n)
  465. tn *t;
  466. int n;
  467. {
  468.     if (n == 0 && t != 0) {
  469.         (void)GC_printf0("Clobbered a leaf - collector is broken\n");
  470.         FAIL;
  471.     }
  472.     if (n == 0) return;
  473.     if (t -> level != n) {
  474.         (void)GC_printf1("Lost a node at level %lu - collector is broken\n",
  475.                  (unsigned long)n);
  476.         FAIL;
  477.     }
  478.     if (counter++ % 373 == 0) (void) GC_MALLOC(counter%5001);
  479.     chktree(t -> lchild, n-1);
  480.     if (counter++ % 73 == 0) (void) GC_MALLOC(counter%373);
  481.     chktree(t -> rchild, n-1);
  482. }
  483.  
  484. # ifdef SOLARIS_THREADS
  485. thread_key_t fl_key;
  486.  
  487. void * alloc8bytes()
  488. {
  489.     void ** my_free_list_ptr;
  490.     void * my_free_list;
  491.     
  492.     if (thr_getspecific(fl_key, (void **)(&my_free_list_ptr)) != 0) {
  493.         (void)GC_printf0("thr_getspecific failed\n");
  494.         FAIL;
  495.     }
  496.     if (my_free_list_ptr == 0) {
  497.         my_free_list_ptr = GC_NEW_UNCOLLECTABLE(void *);
  498.         if (thr_setspecific(fl_key, my_free_list_ptr) != 0) {
  499.             (void)GC_printf0("thr_setspecific failed\n");
  500.             FAIL;
  501.         }
  502.     }
  503.     my_free_list = *my_free_list_ptr;
  504.     if (my_free_list == 0) {
  505.         my_free_list = GC_malloc_many(8);
  506.         if (my_free_list == 0) {
  507.             (void)GC_printf0("alloc8bytes out of memory\n");
  508.             FAIL;
  509.         }
  510.     }
  511.     *my_free_list_ptr = GC_NEXT(my_free_list);
  512.     GC_NEXT(my_free_list) = 0;
  513.     return(my_free_list);
  514. }
  515.  
  516. #else
  517. # define alloc8bytes() GC_MALLOC_ATOMIC(8)
  518. #endif
  519.  
  520. void alloc_small(n)
  521. int n;
  522. {
  523.     register int i;
  524.     
  525.     for (i = 0; i < n; i += 8) {
  526.         if (alloc8bytes() == 0) {
  527.             (void)GC_printf0("Out of memory\n");
  528.             FAIL;
  529.         }
  530.     }
  531. }
  532.  
  533. # if defined(THREADS) && defined(GC_DEBUG)
  534. #   define TREE_HEIGHT 15
  535. # else
  536. #   define TREE_HEIGHT 16
  537. # endif
  538. void tree_test()
  539. {
  540.     tn * root;
  541.     register int i;
  542.     
  543.     root = mktree(TREE_HEIGHT);
  544.     alloc_small(5000000);
  545.     chktree(root, TREE_HEIGHT);
  546.     if (finalized_count && ! dropped_something) {
  547.         (void)GC_printf0("Premature finalization - collector is broken\n");
  548.         FAIL;
  549.     }
  550.     dropped_something = 1;
  551.     GC_noop(root);    /* Root needs to remain live until    */
  552.                 /* dropped_something is set.        */
  553.     root = mktree(TREE_HEIGHT);
  554.     chktree(root, TREE_HEIGHT);
  555.     for (i = TREE_HEIGHT; i >= 0; i--) {
  556.         root = mktree(i);
  557.         chktree(root, i);
  558.     }
  559.     alloc_small(5000000);
  560. }
  561.  
  562. unsigned n_tests = 0;
  563.  
  564. /* A very simple test of explicitly typed allocation    */
  565. void typed_test()
  566. {
  567.     GC_word * old, * new;
  568.     GC_word bm3 = 0x3;
  569.     GC_word bm2 = 0x2;
  570.     GC_word bm_large = 0xf7ff7fff;
  571.     GC_descr d1 = GC_make_descriptor(&bm3, 2);
  572.     GC_descr d2 = GC_make_descriptor(&bm2, 2);
  573. #   ifndef LINT
  574.       GC_descr dummy = GC_make_descriptor(&bm_large, 32);
  575. #   endif
  576.     GC_descr d3 = GC_make_descriptor(&bm_large, 32);
  577.     register int i;
  578.     
  579.     old = 0;
  580.     for (i = 0; i < 4000; i++) {
  581.         new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d1);
  582.         new[0] = 17;
  583.         new[1] = (GC_word)old;
  584.         old = new;
  585.         new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d2);
  586.         new[0] = 17;
  587.         new[1] = (GC_word)old;
  588.         old = new;
  589.         new = (GC_word *) GC_malloc_explicitly_typed(33 * sizeof(GC_word), d3);
  590.         new[0] = 17;
  591.         new[1] = (GC_word)old;
  592.         old = new;
  593.         new = (GC_word *) GC_calloc_explicitly_typed(4, 2 * sizeof(GC_word),
  594.                                  d1);
  595.         new[0] = 17;
  596.         new[1] = (GC_word)old;
  597.         old = new;
  598.         if (i & 0xff) {
  599.           new = (GC_word *) GC_calloc_explicitly_typed(7, 3 * sizeof(GC_word),
  600.                                  d2);
  601.         } else {
  602.           new = (GC_word *) GC_calloc_explicitly_typed(1001,
  603.                                      3 * sizeof(GC_word),
  604.                                    d2);
  605.         }
  606.         new[0] = 17;
  607.         new[1] = (GC_word)old;
  608.         old = new;
  609.     }
  610.     for (i = 0; i < 20000; i++) {
  611.         if (new[0] != 17) {
  612.             (void)GC_printf1("typed alloc failed at %lu\n",
  613.                          (unsigned long)i);
  614.             FAIL;
  615.         }
  616.         new[0] = 0;
  617.         old = new;
  618.         new = (GC_word *)(old[1]);
  619.     }
  620. }
  621.  
  622. int fail_count = 0;
  623.  
  624. /*ARGSUSED*/
  625. void fail_proc(x)
  626. ptr_t x;
  627. {
  628.     fail_count++;
  629. }
  630.  
  631. extern void (*GC_is_valid_displacement_print_proc)();
  632.  
  633. extern void (*GC_is_visible_print_proc)();
  634.  
  635. #ifdef THREADS
  636. #   define TEST_FAIL_COUNT(n) 1
  637. #else 
  638. #   define TEST_FAIL_COUNT(n) (fail_count >= (n))
  639. #endif
  640.  
  641. void run_one_test()
  642. {
  643.     char *x;
  644. #   ifdef LINT
  645.         char *y = 0;
  646. #   else
  647.         char *y = (char *)fail_proc;
  648. #   endif
  649.     DCL_LOCK_STATE;
  650.     
  651.     if (GC_size(GC_malloc(7)) != 8
  652.     || GC_size(GC_malloc(15)) != 16) {
  653.         (void)GC_printf0("GC_size produced unexpected results\n");
  654.         FAIL;
  655.     }
  656.     GC_is_valid_displacement_print_proc = fail_proc;
  657.     GC_is_visible_print_proc = fail_proc;
  658.     x = GC_malloc(16);
  659.     if (GC_base(x + 13) != x || GC_base(y) != 0) {
  660.         (void)GC_printf0("GC_base produced incorrect result\n");
  661.     FAIL;
  662.     }
  663.     if (GC_same_obj(x+5, x) != x + 5) {
  664.         (void)GC_printf0("GC_same_obj produced incorrect result\n");
  665.     FAIL;
  666.     }
  667.     if (GC_is_visible(y) != y || GC_is_visible(x) != x) {
  668.         (void)GC_printf0("GC_is_visible produced incorrect result\n");
  669.     FAIL;
  670.     }
  671.     if (!TEST_FAIL_COUNT(1)) {
  672.         (void)GC_printf0("GC_is_visible produced wrong failure indication\n");
  673.         FAIL;
  674.     }
  675.     if (GC_is_valid_displacement(y) != y
  676.         || GC_is_valid_displacement(x) != x
  677.         || GC_is_valid_displacement(x + 3) != x + 3) {
  678.         (void)GC_printf0(
  679.             "GC_is_valid_displacement produced incorrect result\n");
  680.     FAIL;
  681.     }
  682. #   ifndef ALL_INTERIOR_POINTERS
  683.       if (!TEST_FAIL_COUNT(2)) {
  684.         (void)GC_printf0("GC_is_valid_displacement produced wrong failure indication\n");
  685.         FAIL;
  686.       }
  687. #   endif
  688.     /* Test floating point alignment */
  689.     *(double *)GC_MALLOC(sizeof(double)) = 1.0;
  690.     *(double *)GC_MALLOC(sizeof(double)) = 1.0;
  691.     /* Repeated list reversal test. */
  692.     reverse_test();
  693. #   ifdef PRINTSTATS
  694.     GC_printf0("-------------Finished reverse_test\n");
  695. #   endif
  696.     typed_test();
  697. #   ifdef PRINTSTATS
  698.     GC_printf0("-------------Finished typed_test\n");
  699. #   endif
  700.     tree_test();
  701.     LOCK();
  702.     n_tests++;
  703.     UNLOCK();
  704.     
  705. }
  706.  
  707. void check_heap_stats()
  708. {
  709.     unsigned long max_heap_sz;
  710.     register int i;
  711.     int still_live;
  712.     
  713.     if (sizeof(char *) > 4) {
  714.         max_heap_sz = 13000000;
  715.     } else {
  716.         max_heap_sz = 11000000;
  717.     }
  718. #   ifdef GC_DEBUG
  719.     max_heap_sz *= 2;
  720. #       ifdef SPARC
  721.         max_heap_sz *= 2;
  722. #       endif
  723. #   endif
  724.     /* Garbage collect repeatedly so that all inaccessible objects    */
  725.     /* can be finalized.                        */
  726.       while (GC_collect_a_little()) { }
  727.       for (i = 0; i < 16; i++) {
  728.         GC_gcollect();
  729.       }
  730.     (void)GC_printf1("Completed %lu tests\n", (unsigned long)n_tests);
  731.     (void)GC_printf2("Finalized %lu/%lu objects - ",
  732.                  (unsigned long)finalized_count,
  733.                  (unsigned long)finalizable_count);
  734.     if (finalized_count > finalizable_count
  735.         || finalized_count < finalizable_count/2) {
  736.         (void)GC_printf0("finalization is probably broken\n");
  737.         FAIL;
  738.     } else {
  739.         (void)GC_printf0("finalization is probably ok\n");
  740.     }
  741.     still_live = 0;
  742.     for (i = 0; i < MAX_FINALIZED; i++) {
  743.         if (live_indicators[i] != 0) {
  744.             still_live++;
  745.         }
  746.     }
  747.     if (still_live != finalizable_count - finalized_count) {
  748.         (void)GC_printf1
  749.             ("%lu disappearing links remain - disappearing links are broken\n",
  750.              (unsigned long) still_live);
  751.         FAIL;
  752.     }
  753.     (void)GC_printf1("Total number of bytes allocated is %lu\n",
  754.             (unsigned long)
  755.                    WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc));
  756.     (void)GC_printf1("Final heap size is %lu bytes\n",
  757.                  (unsigned long)GC_get_heap_size());
  758.     if (WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc)
  759.         < 33500000*n_tests) {
  760.         (void)GC_printf0("Incorrect execution - missed some allocations\n");
  761.         FAIL;
  762.     }
  763.     if (GC_get_heap_size() > max_heap_sz*n_tests) {
  764.         (void)GC_printf0("Unexpected heap growth - collector may be broken\n");
  765.         FAIL;
  766.     }
  767.     (void)GC_printf0("Collector appears to work\n");
  768. }
  769.  
  770. #if defined(MACOS)
  771. void SetMinimumStack(long minSize)
  772. {
  773.     long newApplLimit;
  774.  
  775.     if (minSize > LMGetDefltStack())
  776.     {
  777.         newApplLimit = (long) GetApplLimit()
  778.                 - (minSize - LMGetDefltStack());
  779.         SetApplLimit((Ptr) newApplLimit);
  780.         MaxApplZone();
  781.     }
  782. }
  783.  
  784. #define cMinStackSpace (512L * 1024L)
  785.  
  786. #endif
  787.  
  788. #if !defined(PCR) && !defined(SOLARIS_THREADS) || defined(LINT)
  789. #ifdef MSWIN32
  790.   int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
  791. #else
  792.   int main()
  793. #endif
  794. {
  795.     n_tests = 0;
  796.     
  797. #   if defined(MACOS)
  798.     /* Make sure we have lots and lots of stack space.     */
  799.     SetMinimumStack(cMinStackSpace);
  800.     /* Cheat and let stdio initialize toolbox for us.    */
  801.     printf("Testing GC Macintosh port.\n");
  802. #   endif
  803.     GC_INIT();    /* Only needed if gc is dynamic library.    */
  804. #   if defined(MPROTECT_VDB) || defined(PROC_VDB)
  805.       GC_enable_incremental();
  806.       (void) GC_printf0("Switched to incremental mode\n");
  807. #     if defined(MPROTECT_VDB)
  808.     (void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
  809. #     else
  810.     (void)GC_printf0("Reading dirty bits from /proc\n");
  811. #      endif
  812. #   endif
  813.     run_one_test();
  814.     check_heap_stats();
  815.     (void)fflush(stdout);
  816. #   ifdef LINT
  817.     /* Entry points we should be testing, but aren't.           */
  818.     /* Some can be tested by defining GC_DEBUG at the top of this file */
  819.     /* This is a bit SunOS4 specific.                   */            
  820.     GC_noop(GC_expand_hp, GC_add_roots, GC_clear_roots,
  821.             GC_register_disappearing_link,
  822.             GC_register_finalizer_ignore_self,
  823.         GC_debug_register_displacement,
  824.             GC_print_obj, GC_debug_change_stubborn,
  825.             GC_debug_end_stubborn_change, GC_debug_malloc_uncollectable,
  826.             GC_debug_free, GC_debug_realloc, GC_generic_malloc_words_small,
  827.             GC_init, GC_make_closure, GC_debug_invoke_finalizer,
  828.             GC_page_was_ever_dirty, GC_is_fresh,
  829.         GC_malloc_ignore_off_page, GC_malloc_atomic_ignore_off_page);
  830. #   endif
  831.     return(0);
  832. }
  833. # endif
  834.  
  835. #ifdef PCR
  836. test()
  837. {
  838.     PCR_Th_T * th1;
  839.     PCR_Th_T * th2;
  840.     int code;
  841.  
  842.     n_tests = 0;
  843.     GC_enable_incremental();
  844.     th1 = PCR_Th_Fork(run_one_test, 0);
  845.     th2 = PCR_Th_Fork(run_one_test, 0);
  846.     run_one_test();
  847.     if (PCR_Th_T_Join(th1, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
  848.         != PCR_ERes_okay || code != 0) {
  849.         (void)GC_printf0("Thread 1 failed\n");
  850.     }
  851.     if (PCR_Th_T_Join(th2, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
  852.         != PCR_ERes_okay || code != 0) {
  853.         (void)GC_printf0("Thread 2 failed\n");
  854.     }
  855.     check_heap_stats();
  856.     (void)fflush(stdout);
  857.     return(0);
  858. }
  859. #endif
  860.  
  861. #ifdef SOLARIS_THREADS
  862. void * thr_run_one_test(void * arg)
  863. {
  864.     run_one_test();
  865.     return(0);
  866. }
  867.  
  868. #ifdef GC_DEBUG
  869. #  define GC_free GC_debug_free
  870. #endif
  871.  
  872. main()
  873. {
  874.     thread_t th1;
  875.     thread_t th2;
  876.     int code;
  877.  
  878.     n_tests = 0;
  879.     GC_INIT();    /* Only needed if gc is dynamic library.    */
  880.     GC_enable_incremental();
  881.     if (thr_keycreate(&fl_key, GC_free) != 0) {
  882.         (void)GC_printf1("Key creation failed %lu\n", (unsigned long)code);
  883.         FAIL;
  884.     }
  885.     if ((code = thr_create(0, 1024*1024, thr_run_one_test, 0, 0, &th1)) != 0) {
  886.         (void)GC_printf1("Thread 1 creation failed %lu\n", (unsigned long)code);
  887.         FAIL;
  888.     }
  889.     if ((code = thr_create(0, 1024*1024, thr_run_one_test, 0, THR_NEW_LWP, &th2)) != 0) {
  890.         (void)GC_printf1("Thread 2 creation failed %lu\n", (unsigned long)code);
  891.         FAIL;
  892.     }
  893.     run_one_test();
  894.     if ((code = thr_join(th1, 0, 0)) != 0) {
  895.         (void)GC_printf1("Thread 1 failed %lu\n", (unsigned long)code);
  896.         FAIL;
  897.     }
  898.     if (thr_join(th2, 0, 0) != 0) {
  899.         (void)GC_printf1("Thread 2 failed %lu\n", (unsigned long)code);
  900.         FAIL;
  901.     }
  902.     check_heap_stats();
  903.     (void)fflush(stdout);
  904.     return(0);
  905. }
  906. #endif
  907.