Back to index

lightning-sunbird  0.9+nobinonly
test.c
Go to the documentation of this file.
00001 /* 
00002  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
00003  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
00004  * Copyright (c) 1996 by Silicon Graphics.  All rights reserved.
00005  *
00006  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
00007  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
00008  *
00009  * Permission is hereby granted to use or copy this program
00010  * for any purpose,  provided the above notices are retained on all copies.
00011  * Permission to modify the code and to distribute modified code is granted,
00012  * provided the above notices are retained, and a notice that the code was
00013  * modified is included with the above copyright notice.
00014  */
00015 /* An incomplete test for the garbage collector.               */
00016 /* Some more obscure entry points are not tested at all.       */
00017 
00018 # if defined(mips) && defined(SYSTYPE_BSD43)
00019     /* MIPS RISCOS 4 */
00020 # else
00021 #   include <stdlib.h>
00022 # endif
00023 # include <stdio.h>
00024 # include <assert.h> /* Not normally used, but handy for debugging. */
00025 # include "gc.h"
00026 # include "gc_typed.h"
00027 # include "gc_priv.h"       /* For output, locking,  and some statistics     */
00028 # include "gcconfig.h"
00029 
00030 # ifdef MSWIN32
00031 #   include <windows.h>
00032 # endif
00033 
00034 # ifdef PCR
00035 #   include "th/PCR_ThCrSec.h"
00036 #   include "th/PCR_Th.h"
00037 #   undef GC_printf0
00038 #   define GC_printf0 printf
00039 #   undef GC_printf1
00040 #   define GC_printf1 printf
00041 # endif
00042 
00043 # ifdef SOLARIS_THREADS
00044 #   include <thread.h>
00045 #   include <synch.h>
00046 # endif
00047 
00048 # if defined(IRIX_THREADS) || defined(LINUX_THREADS)
00049 #   include <pthread.h>
00050 # endif
00051 
00052 # ifdef WIN32_THREADS
00053 #   include <process.h>
00054     static CRITICAL_SECTION incr_cs;
00055 # endif
00056 # if defined(PCR) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS)
00057 #   define THREADS
00058 # endif
00059 
00060 # ifdef AMIGA
00061    long __stack = 200000;
00062 # endif
00063 
00064 # define FAIL (void)abort()
00065 
00066 /* AT_END may be defined to excercise the interior pointer test       */
00067 /* if the collector is configured with ALL_INTERIOR_POINTERS.   */
00068 /* As it stands, this test should succeed with either          */
00069 /* configuration.  In the FIND_LEAK configuration, it should   */
00070 /* find lots of leaks, since we free almost nothing.           */
00071 
00072 struct SEXPR {
00073     struct SEXPR * sexpr_car;
00074     struct SEXPR * sexpr_cdr;
00075 };
00076 
00077 
00078 typedef struct SEXPR * sexpr;
00079 
00080 # define INT_TO_SEXPR(x) ((sexpr)(unsigned long)(x))
00081 
00082 # undef nil
00083 # define nil (INT_TO_SEXPR(0))
00084 # define car(x) ((x) -> sexpr_car)
00085 # define cdr(x) ((x) -> sexpr_cdr)
00086 # define is_nil(x) ((x) == nil)
00087 
00088 
00089 int extra_count = 0;        /* Amount of space wasted in cons node */
00090 
00091 /* Silly implementation of Lisp cons. Intentionally wastes lots of space */
00092 /* to test collector.                                                    */
00093 sexpr cons (x, y)
00094 sexpr x;
00095 sexpr y;
00096 {
00097     register sexpr r;
00098     register int *p;
00099     register int my_extra = extra_count;
00100     
00101     r = (sexpr) GC_MALLOC_STUBBORN(sizeof(struct SEXPR) + my_extra);
00102     if (r == 0) {
00103         (void)GC_printf0("Out of memory\n");
00104         exit(1);
00105     }
00106     for (p = (int *)r;
00107          ((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
00108        if (*p) {
00109            (void)GC_printf1("Found nonzero at 0x%lx - allocator is broken\n",
00110                           (unsigned long)p);
00111            FAIL;
00112         }
00113         *p = 13;
00114     }
00115 #   ifdef AT_END
00116        r = (sexpr)((char *)r + (my_extra & ~7));
00117 #   endif
00118     r -> sexpr_car = x;
00119     r -> sexpr_cdr = y;
00120     my_extra++;
00121     if ( my_extra >= 5000 ) {
00122         extra_count = 0;
00123     } else {
00124         extra_count = my_extra;
00125     }
00126     GC_END_STUBBORN_CHANGE((char *)r);
00127     return(r);
00128 }
00129 
00130 sexpr small_cons (x, y)
00131 sexpr x;
00132 sexpr y;
00133 {
00134     register sexpr r;
00135     
00136     r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
00137     if (r == 0) {
00138         (void)GC_printf0("Out of memory\n");
00139         exit(1);
00140     }
00141     r -> sexpr_car = x;
00142     r -> sexpr_cdr = y;
00143     return(r);
00144 }
00145 
00146 sexpr small_cons_uncollectable (x, y)
00147 sexpr x;
00148 sexpr y;
00149 {
00150     register sexpr r;
00151     
00152     r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR));
00153 assert(GC_is_marked(r));
00154     if (r == 0) {
00155         (void)GC_printf0("Out of memory\n");
00156         exit(1);
00157     }
00158     r -> sexpr_car = x;
00159     r -> sexpr_cdr = (sexpr)(~(unsigned long)y);
00160     return(r);
00161 }
00162 
00163 /* Return reverse(x) concatenated with y */
00164 sexpr reverse1(x, y)
00165 sexpr x, y;
00166 {
00167     if (is_nil(x)) {
00168         return(y);
00169     } else {
00170         return( reverse1(cdr(x), cons(car(x), y)) );
00171     }
00172 }
00173 
00174 sexpr reverse(x)
00175 sexpr x;
00176 {
00177     return( reverse1(x, nil) );
00178 }
00179 
00180 sexpr ints(low, up)
00181 int low, up;
00182 {
00183     if (low > up) {
00184        return(nil);
00185     } else {
00186         return(small_cons(small_cons(INT_TO_SEXPR(low), nil), ints(low+1, up)));
00187     }
00188 }
00189 
00190 /* To check uncollectable allocation we build lists with disguised cdr       */
00191 /* pointers, and make sure they don't go away.                        */
00192 sexpr uncollectable_ints(low, up)
00193 int low, up;
00194 {
00195     if (low > up) {
00196        return(nil);
00197     } else {
00198         return(small_cons_uncollectable(small_cons(INT_TO_SEXPR(low), nil),
00199                uncollectable_ints(low+1, up)));
00200     }
00201 }
00202 
00203 void check_ints(list, low, up)
00204 sexpr list;
00205 int low, up;
00206 {
00207     if ((int)(GC_word)(car(car(list))) != low) {
00208         (void)GC_printf0(
00209            "List reversal produced incorrect list - collector is broken\n");
00210         FAIL;
00211     }
00212     if (low == up) {
00213         if (cdr(list) != nil) {
00214            (void)GC_printf0("List too long - collector is broken\n");
00215            FAIL;
00216         }
00217     } else {
00218         check_ints(cdr(list), low+1, up);
00219     }
00220 }
00221 
00222 # define UNCOLLECTABLE_CDR(x) (sexpr)(~(unsigned long)(cdr(x)))
00223 
00224 void check_uncollectable_ints(list, low, up)
00225 sexpr list;
00226 int low, up;
00227 {
00228 assert(GC_is_marked(list));
00229     if ((int)(GC_word)(car(car(list))) != low) {
00230         (void)GC_printf0(
00231            "Uncollectable list corrupted - collector is broken\n");
00232         FAIL;
00233     }
00234     if (low == up) {
00235         if (UNCOLLECTABLE_CDR(list) != nil) {
00236            (void)GC_printf0("Uncollectable list too long - collector is broken\n");
00237            FAIL;
00238         }
00239     } else {
00240         check_uncollectable_ints(UNCOLLECTABLE_CDR(list), low+1, up);
00241     }
00242 }
00243 
00244 /* Not used, but useful for debugging: */
00245 void print_int_list(x)
00246 sexpr x;
00247 {
00248     if (is_nil(x)) {
00249         (void)GC_printf0("NIL\n");
00250     } else {
00251         (void)GC_printf1("(%ld)", (long)(car(car(x))));
00252         if (!is_nil(cdr(x))) {
00253             (void)GC_printf0(", ");
00254             (void)print_int_list(cdr(x));
00255         } else {
00256             (void)GC_printf0("\n");
00257         }
00258     }
00259 }
00260 
00261 /* Try to force a to be strangely aligned */
00262 struct {
00263   char dummy;
00264   sexpr aa;
00265 } A;
00266 #define a A.aa
00267 
00268 /*
00269  * A tiny list reversal test to check thread creation.
00270  */
00271 #ifdef THREADS
00272 
00273 # ifdef WIN32_THREADS
00274     unsigned __stdcall tiny_reverse_test(void * arg)
00275 # else
00276     void * tiny_reverse_test(void * arg)
00277 # endif
00278 {
00279     check_ints(reverse(reverse(ints(1,10))), 1, 10);
00280     return 0;
00281 }
00282 
00283 # if defined(IRIX_THREADS) || defined(LINUX_THREADS) \
00284      || defined(SOLARIS_PTHREADS)
00285     void fork_a_thread()
00286     {
00287       pthread_t t;
00288       int code;
00289       if ((code = pthread_create(&t, 0, tiny_reverse_test, 0)) != 0) {
00290        (void)GC_printf1("Small thread creation failed %lu\n",
00291                        (unsigned long)code);
00292        FAIL;
00293       }
00294       if ((code = pthread_join(t, 0)) != 0) {
00295         (void)GC_printf1("Small thread join failed %lu\n",
00296        (unsigned long)code);
00297         FAIL;
00298       }
00299     }
00300 
00301 # elif defined(WIN32_THREADS)
00302     void fork_a_thread()
00303     {
00304        unsigned thread_id;
00305        HANDLE h;
00306        h = (HANDLE)_beginthreadex(NULL, 0, tiny_reverse_test,
00307                                0, 0, &thread_id);
00308         if (h == (HANDLE)-1) {
00309             (void)GC_printf1("Small thread creation failed %lu\n",
00310                           (unsigned long)GetLastError());
00311            FAIL;
00312         }
00313        if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) {
00314            (void)GC_printf1("Small thread wait failed %lu\n",
00315                           (unsigned long)GetLastError());
00316            FAIL;
00317        }
00318     }
00319 
00320 /* # elif defined(SOLARIS_THREADS) */
00321 
00322 # else
00323 
00324 #   define fork_a_thread()
00325 
00326 # endif
00327 
00328 #else
00329 
00330 # define fork_a_thread()
00331 
00332 #endif 
00333 
00334 /*
00335  * Repeatedly reverse lists built out of very different sized cons cells.
00336  * Check that we didn't lose anything.
00337  */
00338 void reverse_test()
00339 {
00340     int i;
00341     sexpr b;
00342     sexpr c;
00343     sexpr d;
00344     sexpr e;
00345     sexpr *f, *g, *h;
00346 #   if defined(MSWIN32) || defined(MACOS)
00347       /* Win32S only allows 128K stacks */
00348 #     define BIG 1000
00349 #   else
00350 #     if defined PCR
00351        /* PCR default stack is 100K.  Stack frames are up to 120 bytes. */
00352 #      define BIG 700
00353 #     else
00354 #       define BIG 4500
00355 #     endif
00356 #   endif
00357 
00358     A.dummy = 17;
00359     a = ints(1, 49);
00360     b = ints(1, 50);
00361     c = ints(1, BIG);
00362     d = uncollectable_ints(1, 100);
00363     e = uncollectable_ints(1, 1);
00364     /* Check that realloc updates object descriptors correctly */
00365     f = (sexpr *)GC_malloc(4 * sizeof(sexpr));
00366     f = (sexpr *)GC_realloc((GC_PTR)f, 6 * sizeof(sexpr));
00367     f[5] = ints(1,17);
00368     g = (sexpr *)GC_malloc(513 * sizeof(sexpr));
00369     g = (sexpr *)GC_realloc((GC_PTR)g, 800 * sizeof(sexpr));
00370     g[799] = ints(1,18);
00371     h = (sexpr *)GC_malloc(1025 * sizeof(sexpr));
00372     h = (sexpr *)GC_realloc((GC_PTR)h, 2000 * sizeof(sexpr));
00373     h[1999] = ints(1,19);
00374     /* Try to force some collections and reuse of small list elements */
00375       for (i = 0; i < 10; i++) {
00376         (void)ints(1, BIG);
00377       }
00378     /* Superficially test interior pointer recognition on stack */
00379     c = (sexpr)((char *)c + sizeof(char *));
00380     d = (sexpr)((char *)d + sizeof(char *));
00381 
00382 #   ifdef __STDC__
00383         GC_FREE((void *)e);
00384 #   else
00385         GC_FREE((char *)e);
00386 #   endif
00387     check_ints(b,1,50);
00388     check_ints(a,1,49);
00389     for (i = 0; i < 50; i++) {
00390         check_ints(b,1,50);
00391         b = reverse(reverse(b));
00392     }
00393     check_ints(b,1,50);
00394     check_ints(a,1,49);
00395     for (i = 0; i < 60; i++) {
00396        if (i % 10 == 0) fork_a_thread();
00397        /* This maintains the invariant that a always points to a list of */
00398        /* 49 integers.  Thus this is thread safe without locks,         */
00399        /* assuming atomic pointer assignments.                          */
00400         a = reverse(reverse(a));
00401 #      if !defined(AT_END) && !defined(THREADS)
00402          /* This is not thread safe, since realloc explicitly deallocates */
00403           if (i & 1) {
00404             a = (sexpr)GC_REALLOC((GC_PTR)a, 500);
00405           } else {
00406             a = (sexpr)GC_REALLOC((GC_PTR)a, 8200);
00407           }
00408 #      endif
00409     }
00410     check_ints(a,1,49);
00411     check_ints(b,1,50);
00412     c = (sexpr)((char *)c - sizeof(char *));
00413     d = (sexpr)((char *)d - sizeof(char *));
00414     check_ints(c,1,BIG);
00415     check_uncollectable_ints(d, 1, 100);
00416     check_ints(f[5], 1,17);
00417     check_ints(g[799], 1,18);
00418     check_ints(h[1999], 1,19);
00419 #   ifndef THREADS
00420        a = 0;
00421 #   endif  
00422     b = c = 0;
00423 }
00424 
00425 /*
00426  * The rest of this builds balanced binary trees, checks that they don't
00427  * disappear, and tests finalization.
00428  */
00429 typedef struct treenode {
00430     int level;
00431     struct treenode * lchild;
00432     struct treenode * rchild;
00433 } tn;
00434 
00435 int finalizable_count = 0;
00436 int finalized_count = 0;
00437 VOLATILE int dropped_something = 0;
00438 
00439 # ifdef __STDC__
00440   void finalizer(void * obj, void * client_data)
00441 # else
00442   void finalizer(obj, client_data)
00443   char * obj;
00444   char * client_data;
00445 # endif
00446 {
00447   tn * t = (tn *)obj;
00448 
00449 # ifdef PCR
00450      PCR_ThCrSec_EnterSys();
00451 # endif
00452 # ifdef SOLARIS_THREADS
00453     static mutex_t incr_lock;
00454     mutex_lock(&incr_lock);
00455 # endif
00456 # if  defined(IRIX_THREADS) || defined(LINUX_THREADS)
00457     static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
00458     pthread_mutex_lock(&incr_lock);
00459 # endif
00460 # ifdef WIN32_THREADS
00461     EnterCriticalSection(&incr_cs);
00462 # endif
00463   if ((int)(GC_word)client_data != t -> level) {
00464      (void)GC_printf0("Wrong finalization data - collector is broken\n");
00465      FAIL;
00466   }
00467   finalized_count++;
00468 # ifdef PCR
00469     PCR_ThCrSec_ExitSys();
00470 # endif
00471 # ifdef SOLARIS_THREADS
00472     mutex_unlock(&incr_lock);
00473 # endif
00474 # if defined(IRIX_THREADS) || defined(LINUX_THREADS)
00475     pthread_mutex_unlock(&incr_lock);
00476 # endif
00477 # ifdef WIN32_THREADS
00478     LeaveCriticalSection(&incr_cs);
00479 # endif
00480 }
00481 
00482 size_t counter = 0;
00483 
00484 # define MAX_FINALIZED 8000
00485 
00486 # if !defined(MACOS)
00487   GC_FAR GC_word live_indicators[MAX_FINALIZED] = {0};
00488 #else
00489   /* Too big for THINK_C. have to allocate it dynamically. */
00490   GC_word *live_indicators = 0;
00491 #endif
00492 
00493 int live_indicators_count = 0;
00494 
00495 tn * mktree(n)
00496 int n;
00497 {
00498     tn * result = (tn *)GC_MALLOC(sizeof(tn));
00499     
00500 #if defined(MACOS)
00501        /* get around static data limitations. */
00502        if (!live_indicators)
00503               live_indicators =
00504                   (GC_word*)NewPtrClear(MAX_FINALIZED * sizeof(GC_word));
00505        if (!live_indicators) {
00506         (void)GC_printf0("Out of memory\n");
00507         exit(1);
00508     }
00509 #endif
00510     if (n == 0) return(0);
00511     if (result == 0) {
00512         (void)GC_printf0("Out of memory\n");
00513         exit(1);
00514     }
00515     result -> level = n;
00516     result -> lchild = mktree(n-1);
00517     result -> rchild = mktree(n-1);
00518     if (counter++ % 17 == 0 && n >= 2) {
00519         tn * tmp = result -> lchild -> rchild;
00520         
00521         result -> lchild -> rchild = result -> rchild -> lchild;
00522         result -> rchild -> lchild = tmp;
00523     }
00524     if (counter++ % 119 == 0) {
00525         int my_index;
00526         
00527         {
00528 #        ifdef PCR
00529            PCR_ThCrSec_EnterSys();
00530 #        endif
00531 #        ifdef SOLARIS_THREADS
00532            static mutex_t incr_lock;
00533            mutex_lock(&incr_lock);
00534 #        endif
00535 #         if defined(IRIX_THREADS) || defined(LINUX_THREADS)
00536             static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
00537             pthread_mutex_lock(&incr_lock);
00538 #         endif
00539 #         ifdef WIN32_THREADS
00540             EnterCriticalSection(&incr_cs);
00541 #         endif
00542               /* Losing a count here causes erroneous report of failure. */
00543           finalizable_count++;
00544           my_index = live_indicators_count++;
00545 #        ifdef PCR
00546            PCR_ThCrSec_ExitSys();
00547 #        endif
00548 #        ifdef SOLARIS_THREADS
00549            mutex_unlock(&incr_lock);
00550 #        endif
00551 #        if defined(IRIX_THREADS) || defined(LINUX_THREADS)
00552            pthread_mutex_unlock(&incr_lock);
00553 #        endif
00554 #         ifdef WIN32_THREADS
00555             LeaveCriticalSection(&incr_cs);
00556 #         endif
00557        }
00558 
00559         GC_REGISTER_FINALIZER((GC_PTR)result, finalizer, (GC_PTR)(GC_word)n,
00560                            (GC_finalization_proc *)0, (GC_PTR *)0);
00561         if (my_index >= MAX_FINALIZED) {
00562               GC_printf0("live_indicators overflowed\n");
00563               FAIL;
00564        }
00565         live_indicators[my_index] = 13;
00566         if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
00567               (GC_PTR *)(&(live_indicators[my_index])),
00568               (GC_PTR)result) != 0) {
00569               GC_printf0("GC_general_register_disappearing_link failed\n");
00570               FAIL;
00571         }
00572         if (GC_unregister_disappearing_link(
00573               (GC_PTR *)
00574                  (&(live_indicators[my_index]))) == 0) {
00575               GC_printf0("GC_unregister_disappearing_link failed\n");
00576               FAIL;
00577         }
00578         if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
00579               (GC_PTR *)(&(live_indicators[my_index])),
00580               (GC_PTR)result) != 0) {
00581               GC_printf0("GC_general_register_disappearing_link failed 2\n");
00582               FAIL;
00583         }
00584     }
00585     return(result);
00586 }
00587 
00588 void chktree(t,n)
00589 tn *t;
00590 int n;
00591 {
00592     if (n == 0 && t != 0) {
00593         (void)GC_printf0("Clobbered a leaf - collector is broken\n");
00594         FAIL;
00595     }
00596     if (n == 0) return;
00597     if (t -> level != n) {
00598         (void)GC_printf1("Lost a node at level %lu - collector is broken\n",
00599                       (unsigned long)n);
00600         FAIL;
00601     }
00602     if (counter++ % 373 == 0) (void) GC_MALLOC(counter%5001);
00603     chktree(t -> lchild, n-1);
00604     if (counter++ % 73 == 0) (void) GC_MALLOC(counter%373);
00605     chktree(t -> rchild, n-1);
00606 }
00607 
00608 # if defined(SOLARIS_THREADS) && !defined(_SOLARIS_PTHREADS)
00609 thread_key_t fl_key;
00610 
00611 void * alloc8bytes()
00612 {
00613 # ifdef SMALL_CONFIG
00614     return(GC_malloc(8));
00615 # else
00616     void ** my_free_list_ptr;
00617     void * my_free_list;
00618     
00619     if (thr_getspecific(fl_key, (void **)(&my_free_list_ptr)) != 0) {
00620        (void)GC_printf0("thr_getspecific failed\n");
00621        FAIL;
00622     }
00623     if (my_free_list_ptr == 0) {
00624         my_free_list_ptr = GC_NEW_UNCOLLECTABLE(void *);
00625         if (thr_setspecific(fl_key, my_free_list_ptr) != 0) {
00626            (void)GC_printf0("thr_setspecific failed\n");
00627            FAIL;
00628         }
00629     }
00630     my_free_list = *my_free_list_ptr;
00631     if (my_free_list == 0) {
00632         my_free_list = GC_malloc_many(8);
00633         if (my_free_list == 0) {
00634             (void)GC_printf0("alloc8bytes out of memory\n");
00635            FAIL;
00636         }
00637     }
00638     *my_free_list_ptr = GC_NEXT(my_free_list);
00639     GC_NEXT(my_free_list) = 0;
00640     return(my_free_list);
00641 # endif
00642 }
00643 
00644 #else
00645 
00646 # if defined(_SOLARIS_PTHREADS) || defined(IRIX_THREADS) \
00647      || defined(LINUX_THREADS)
00648 pthread_key_t fl_key;
00649 
00650 void * alloc8bytes()
00651 {
00652 # ifdef SMALL_CONFIG
00653     return(GC_malloc(8));
00654 # else
00655     void ** my_free_list_ptr;
00656     void * my_free_list;
00657     
00658     my_free_list_ptr = (void **)pthread_getspecific(fl_key);
00659     if (my_free_list_ptr == 0) {
00660         my_free_list_ptr = GC_NEW_UNCOLLECTABLE(void *);
00661         if (pthread_setspecific(fl_key, my_free_list_ptr) != 0) {
00662            (void)GC_printf0("pthread_setspecific failed\n");
00663            FAIL;
00664         }
00665     }
00666     my_free_list = *my_free_list_ptr;
00667     if (my_free_list == 0) {
00668         my_free_list = GC_malloc_many(8);
00669         if (my_free_list == 0) {
00670             (void)GC_printf0("alloc8bytes out of memory\n");
00671            FAIL;
00672         }
00673     }
00674     *my_free_list_ptr = GC_NEXT(my_free_list);
00675     GC_NEXT(my_free_list) = 0;
00676     return(my_free_list);
00677 # endif
00678 }
00679 
00680 # else
00681 #   define alloc8bytes() GC_MALLOC_ATOMIC(8)
00682 # endif
00683 #endif
00684 
00685 void alloc_small(n)
00686 int n;
00687 {
00688     register int i;
00689     
00690     for (i = 0; i < n; i += 8) {
00691         if (alloc8bytes() == 0) {
00692             (void)GC_printf0("Out of memory\n");
00693             FAIL;
00694         }
00695     }
00696 }
00697 
00698 # if defined(THREADS) && defined(GC_DEBUG)
00699 #   define TREE_HEIGHT 15
00700 # else
00701 #   define TREE_HEIGHT 16
00702 # endif
00703 void tree_test()
00704 {
00705     tn * root;
00706     register int i;
00707     
00708     root = mktree(TREE_HEIGHT);
00709     alloc_small(5000000);
00710     chktree(root, TREE_HEIGHT);
00711     if (finalized_count && ! dropped_something) {
00712         (void)GC_printf0("Premature finalization - collector is broken\n");
00713         FAIL;
00714     }
00715     dropped_something = 1;
00716     GC_noop(root);   /* Root needs to remain live until */
00717                      /* dropped_something is set.              */
00718     root = mktree(TREE_HEIGHT);
00719     chktree(root, TREE_HEIGHT);
00720     for (i = TREE_HEIGHT; i >= 0; i--) {
00721         root = mktree(i);
00722         chktree(root, i);
00723     }
00724     alloc_small(5000000);
00725 }
00726 
00727 unsigned n_tests = 0;
00728 
00729 GC_word bm_huge[10] = {
00730     0xffffffff,
00731     0xffffffff,
00732     0xffffffff,
00733     0xffffffff,
00734     0xffffffff,
00735     0xffffffff,
00736     0xffffffff,
00737     0xffffffff,
00738     0xffffffff,
00739     0x00ffffff,
00740 };
00741 
00742 
00743 /* A very simple test of explicitly typed allocation    */
00744 void typed_test()
00745 {
00746     GC_word * old, * new;
00747     GC_word bm3 = 0x3;
00748     GC_word bm2 = 0x2;
00749     GC_word bm_large = 0xf7ff7fff;
00750     GC_descr d1 = GC_make_descriptor(&bm3, 2);
00751     GC_descr d2 = GC_make_descriptor(&bm2, 2);
00752 #   ifndef LINT
00753       GC_descr dummy = GC_make_descriptor(&bm_large, 32);
00754 #   endif
00755     GC_descr d3 = GC_make_descriptor(&bm_large, 32);
00756     GC_descr d4 = GC_make_descriptor(bm_huge, 320);
00757     GC_word * x = (GC_word *)GC_malloc_explicitly_typed(2000, d4);
00758     register int i;
00759     
00760     old = 0;
00761     for (i = 0; i < 4000; i++) {
00762         new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d1);
00763         new[0] = 17;
00764         new[1] = (GC_word)old;
00765         old = new;
00766         new = (GC_word *) GC_malloc_explicitly_typed(4 * sizeof(GC_word), d2);
00767         new[0] = 17;
00768         new[1] = (GC_word)old;
00769         old = new;
00770         new = (GC_word *) GC_malloc_explicitly_typed(33 * sizeof(GC_word), d3);
00771         new[0] = 17;
00772         new[1] = (GC_word)old;
00773         old = new;
00774         new = (GC_word *) GC_calloc_explicitly_typed(4, 2 * sizeof(GC_word),
00775                                                d1);
00776         new[0] = 17;
00777         new[1] = (GC_word)old;
00778         old = new;
00779         if (i & 0xff) {
00780           new = (GC_word *) GC_calloc_explicitly_typed(7, 3 * sizeof(GC_word),
00781                                                d2);
00782         } else {
00783           new = (GC_word *) GC_calloc_explicitly_typed(1001,
00784                                                  3 * sizeof(GC_word),
00785                                                  d2);
00786         }
00787         new[0] = 17;
00788         new[1] = (GC_word)old;
00789         old = new;
00790     }
00791     for (i = 0; i < 20000; i++) {
00792         if (new[0] != 17) {
00793             (void)GC_printf1("typed alloc failed at %lu\n",
00794                           (unsigned long)i);
00795             FAIL;
00796         }
00797         new[0] = 0;
00798         old = new;
00799         new = (GC_word *)(old[1]);
00800     }
00801     GC_gcollect();
00802     GC_noop(x);
00803 }
00804 
00805 int fail_count = 0;
00806 
00807 #ifndef __STDC__
00808 /*ARGSUSED*/
00809 void fail_proc1(x)
00810 GC_PTR x;
00811 {
00812     fail_count++;
00813 }
00814 
00815 #else
00816 
00817 /*ARGSUSED*/
00818 void fail_proc1(GC_PTR x)
00819 {
00820     fail_count++;
00821 }   
00822 
00823 #endif /* __STDC__ */
00824 
00825 #ifdef THREADS
00826 #   define TEST_FAIL_COUNT(n) 1
00827 #else 
00828 #   define TEST_FAIL_COUNT(n) (fail_count >= (n))
00829 #endif
00830 
00831 void run_one_test()
00832 {
00833     char *x;
00834 #   ifdef LINT
00835        char *y = 0;
00836 #   else
00837        char *y = (char *)(size_t)fail_proc1;
00838 #   endif
00839     DCL_LOCK_STATE;
00840     
00841 #   ifdef FIND_LEAK
00842        (void)GC_printf0(
00843               "This test program is not designed for leak detection mode\n");
00844        (void)GC_printf0("Expect lots of problems.\n");
00845 #   endif
00846     if (GC_size(GC_malloc(7)) != 8
00847        || GC_size(GC_malloc(15)) != 16) {
00848            (void)GC_printf0("GC_size produced unexpected results\n");
00849            FAIL;
00850     }
00851     if (GC_size(GC_malloc(0)) != 4 && GC_size(GC_malloc(0)) != 8) {
00852        (void)GC_printf0("GC_malloc(0) failed\n");
00853            FAIL;
00854     }
00855     if (GC_size(GC_malloc_uncollectable(0)) != 4
00856         && GC_size(GC_malloc_uncollectable(0)) != 8) {
00857        (void)GC_printf0("GC_malloc_uncollectable(0) failed\n");
00858            FAIL;
00859     }
00860     GC_is_valid_displacement_print_proc = fail_proc1;
00861     GC_is_visible_print_proc = fail_proc1;
00862     x = GC_malloc(16);
00863     if (GC_base(x + 13) != x) {
00864        (void)GC_printf0("GC_base(heap ptr) produced incorrect result\n");
00865        FAIL;
00866     }
00867 #   ifndef PCR
00868       if (GC_base(y) != 0) {
00869        (void)GC_printf0("GC_base(fn_ptr) produced incorrect result\n");
00870        FAIL;
00871       }
00872 #   endif
00873     if (GC_same_obj(x+5, x) != x + 5) {
00874        (void)GC_printf0("GC_same_obj produced incorrect result\n");
00875        FAIL;
00876     }
00877     if (GC_is_visible(y) != y || GC_is_visible(x) != x) {
00878        (void)GC_printf0("GC_is_visible produced incorrect result\n");
00879        FAIL;
00880     }
00881     if (!TEST_FAIL_COUNT(1)) {
00882 #      if!(defined(RS6000) || defined(POWERPC))
00883          /* ON RS6000s function pointers point to a descriptor in the */
00884          /* data segment, so there should have been no failures.      */
00885          (void)GC_printf0("GC_is_visible produced wrong failure indication\n");
00886          FAIL;
00887 #      endif
00888     }
00889     if (GC_is_valid_displacement(y) != y
00890         || GC_is_valid_displacement(x) != x
00891         || GC_is_valid_displacement(x + 3) != x + 3) {
00892        (void)GC_printf0(
00893               "GC_is_valid_displacement produced incorrect result\n");
00894        FAIL;
00895     }
00896 #   ifndef ALL_INTERIOR_POINTERS
00897 #    if defined(RS6000) || defined(POWERPC)
00898       if (!TEST_FAIL_COUNT(1)) {
00899 #    else
00900       if (!TEST_FAIL_COUNT(2)) {
00901 #    endif
00902        (void)GC_printf0("GC_is_valid_displacement produced wrong failure indication\n");
00903        FAIL;
00904       }
00905 #   endif
00906     /* Test floating point alignment */
00907        *(double *)GC_MALLOC(sizeof(double)) = 1.0;
00908        *(double *)GC_MALLOC(sizeof(double)) = 1.0;
00909     /* Repeated list reversal test. */
00910        reverse_test();
00911 #   ifdef PRINTSTATS
00912        GC_printf0("-------------Finished reverse_test\n");
00913 #   endif
00914     typed_test();
00915 #   ifdef PRINTSTATS
00916        GC_printf0("-------------Finished typed_test\n");
00917 #   endif
00918     tree_test();
00919     LOCK();
00920     n_tests++;
00921     UNLOCK();
00922     /* GC_printf1("Finished %x\n", pthread_self()); */
00923 }
00924 
00925 void check_heap_stats()
00926 {
00927     unsigned long max_heap_sz;
00928     register int i;
00929     int still_live;
00930     int late_finalize_count = 0;
00931     
00932     if (sizeof(char *) > 4) {
00933         max_heap_sz = 13000000;
00934     } else {
00935        max_heap_sz = 11000000;
00936     }
00937 #   ifdef GC_DEBUG
00938        max_heap_sz *= 2;
00939 #       ifdef SPARC
00940            max_heap_sz *= 2;
00941 #       endif
00942 #   endif
00943     /* Garbage collect repeatedly so that all inaccessible objects    */
00944     /* can be finalized.                                       */
00945       while (GC_collect_a_little()) { }
00946       for (i = 0; i < 16; i++) {
00947         GC_gcollect();
00948         late_finalize_count += GC_invoke_finalizers();
00949       }
00950     (void)GC_printf1("Completed %lu tests\n", (unsigned long)n_tests);
00951     (void)GC_printf2("Finalized %lu/%lu objects - ",
00952                    (unsigned long)finalized_count,
00953                    (unsigned long)finalizable_count);
00954 #   ifdef FINALIZE_ON_DEMAND
00955        if (finalized_count != late_finalize_count) {
00956             (void)GC_printf0("Demand finalization error\n");
00957            FAIL;
00958        }
00959 #   endif
00960     if (finalized_count > finalizable_count
00961         || finalized_count < finalizable_count/2) {
00962         (void)GC_printf0("finalization is probably broken\n");
00963         FAIL;
00964     } else {
00965         (void)GC_printf0("finalization is probably ok\n");
00966     }
00967     still_live = 0;
00968     for (i = 0; i < MAX_FINALIZED; i++) {
00969        if (live_indicators[i] != 0) {
00970            still_live++;
00971        }
00972     }
00973     i = finalizable_count - finalized_count - still_live;
00974     if (0 != i) {
00975         (void)GC_printf2
00976             ("%lu disappearing links remain and %lu more objects were not finalized\n",
00977              (unsigned long) still_live, (unsigned long)i);
00978         if (i > 10) {
00979            GC_printf0("\tVery suspicious!\n");
00980        } else {
00981            GC_printf0("\tSlightly suspicious, but probably OK.\n");
00982        }
00983     }
00984     (void)GC_printf1("Total number of bytes allocated is %lu\n",
00985               (unsigned long)
00986                   WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc));
00987     (void)GC_printf1("Final heap size is %lu bytes\n",
00988                    (unsigned long)GC_get_heap_size());
00989     if (WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc)
00990         < 33500000*n_tests) {
00991         (void)GC_printf0("Incorrect execution - missed some allocations\n");
00992         FAIL;
00993     }
00994     if (GC_get_heap_size() > max_heap_sz*n_tests) {
00995         (void)GC_printf0("Unexpected heap growth - collector may be broken\n");
00996         FAIL;
00997     }
00998     (void)GC_printf0("Collector appears to work\n");
00999 }
01000 
01001 #if defined(MACOS)
01002 void SetMinimumStack(long minSize)
01003 {
01004        long newApplLimit;
01005 
01006        if (minSize > LMGetDefltStack())
01007        {
01008               newApplLimit = (long) GetApplLimit()
01009                             - (minSize - LMGetDefltStack());
01010               SetApplLimit((Ptr) newApplLimit);
01011               MaxApplZone();
01012        }
01013 }
01014 
01015 #define cMinStackSpace (512L * 1024L)
01016 
01017 #endif
01018 
01019 #ifdef __STDC__
01020     void warn_proc(char *msg, GC_word p)
01021 #else
01022     void warn_proc(msg, p)
01023     char *msg;
01024     GC_word p;
01025 #endif
01026 {
01027     GC_printf1(msg, (unsigned long)p);
01028     FAIL;
01029 }
01030 
01031 
01032 #if !defined(PCR) && !defined(SOLARIS_THREADS) && !defined(WIN32_THREADS) \
01033   && !defined(IRIX_THREADS) && !defined(LINUX_THREADS) || defined(LINT)
01034 #ifdef MSWIN32
01035   int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
01036 #else
01037   int main()
01038 #endif
01039 {
01040 #   if defined(DJGPP)
01041        int dummy;
01042 #   endif
01043     n_tests = 0;
01044     
01045 #   if defined(DJGPP)
01046        /* No good way to determine stack base from library; do it */
01047        /* manually on this platform.                              */
01048        GC_stackbottom = (GC_PTR)(&dummy);
01049 #   endif
01050 #   if defined(MACOS)
01051        /* Make sure we have lots and lots of stack space.      */
01052        SetMinimumStack(cMinStackSpace);
01053        /* Cheat and let stdio initialize toolbox for us.       */
01054        printf("Testing GC Macintosh port.\n");
01055 #   endif
01056     GC_INIT();       /* Only needed if gc is dynamic library.  */
01057     (void) GC_set_warn_proc(warn_proc);
01058 #   if defined(MPROTECT_VDB) || defined(PROC_VDB)
01059       GC_enable_incremental();
01060       (void) GC_printf0("Switched to incremental mode\n");
01061 #     if defined(MPROTECT_VDB)
01062        (void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
01063 #     else
01064        (void)GC_printf0("Reading dirty bits from /proc\n");
01065 #      endif
01066 #   endif
01067     run_one_test();
01068     check_heap_stats();
01069     (void)fflush(stdout);
01070 #   ifdef LINT
01071        /* Entry points we should be testing, but aren't.                 */
01072        /* Some can be tested by defining GC_DEBUG at the top of this file */
01073        /* This is a bit SunOS4 specific.                          */                
01074        GC_noop(GC_expand_hp, GC_add_roots, GC_clear_roots,
01075                GC_register_disappearing_link,
01076                GC_register_finalizer_ignore_self,
01077               GC_debug_register_displacement,
01078                GC_print_obj, GC_debug_change_stubborn,
01079                GC_debug_end_stubborn_change, GC_debug_malloc_uncollectable,
01080                GC_debug_free, GC_debug_realloc, GC_generic_malloc_words_small,
01081                GC_init, GC_make_closure, GC_debug_invoke_finalizer,
01082                GC_page_was_ever_dirty, GC_is_fresh,
01083               GC_malloc_ignore_off_page, GC_malloc_atomic_ignore_off_page,
01084               GC_set_max_heap_size, GC_get_bytes_since_gc,
01085               GC_pre_incr, GC_post_incr);
01086 #   endif
01087 #   ifdef MSWIN32
01088       GC_win32_free_heap();
01089 #   endif
01090     return(0);
01091 }
01092 # endif
01093 
01094 #ifdef WIN32_THREADS
01095 
01096 unsigned __stdcall thr_run_one_test(void *arg)
01097 {
01098   run_one_test();
01099   return 0;
01100 }
01101 
01102 #define NTEST 2 
01103 
01104 int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
01105 {
01106 # if NTEST > 0
01107    HANDLE h[NTEST];
01108 # endif
01109   int i;
01110   unsigned thread_id;
01111 # if 0
01112     GC_enable_incremental();
01113 # endif
01114   InitializeCriticalSection(&incr_cs);
01115   (void) GC_set_warn_proc(warn_proc);
01116   for (i = 0; i < NTEST; i++) {
01117     h[i] = (HANDLE)_beginthreadex(NULL, 0, thr_run_one_test, 0, 0, &thread_id);
01118     if (h[i] == (HANDLE)-1) {
01119       (void)GC_printf1("Thread creation failed %lu\n", (unsigned long)GetLastError());
01120       FAIL;
01121     }
01122   }
01123   run_one_test();
01124   for (i = 0; i < NTEST; i++)
01125     if (WaitForSingleObject(h[i], INFINITE) != WAIT_OBJECT_0) {
01126       (void)GC_printf1("Thread wait failed %lu\n", (unsigned long)GetLastError());
01127       FAIL;
01128     }
01129   check_heap_stats();
01130   (void)fflush(stdout);
01131   return(0);
01132 }
01133 
01134 #endif /* WIN32_THREADS */
01135 
01136 
01137 #ifdef PCR
01138 test()
01139 {
01140     PCR_Th_T * th1;
01141     PCR_Th_T * th2;
01142     int code;
01143 
01144     n_tests = 0;
01145     /* GC_enable_incremental(); */
01146     (void) GC_set_warn_proc(warn_proc);
01147     th1 = PCR_Th_Fork(run_one_test, 0);
01148     th2 = PCR_Th_Fork(run_one_test, 0);
01149     run_one_test();
01150     if (PCR_Th_T_Join(th1, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
01151         != PCR_ERes_okay || code != 0) {
01152         (void)GC_printf0("Thread 1 failed\n");
01153     }
01154     if (PCR_Th_T_Join(th2, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
01155         != PCR_ERes_okay || code != 0) {
01156         (void)GC_printf0("Thread 2 failed\n");
01157     }
01158     check_heap_stats();
01159     (void)fflush(stdout);
01160     return(0);
01161 }
01162 #endif
01163 
01164 #if defined(SOLARIS_THREADS) || defined(IRIX_THREADS) || defined(LINUX_THREADS)
01165 void * thr_run_one_test(void * arg)
01166 {
01167     run_one_test();
01168     return(0);
01169 }
01170 
01171 #ifdef GC_DEBUG
01172 #  define GC_free GC_debug_free
01173 #endif
01174 
01175 #ifdef SOLARIS_THREADS
01176 main()
01177 {
01178     thread_t th1;
01179     thread_t th2;
01180     int code;
01181 
01182     n_tests = 0;
01183     GC_INIT();       /* Only needed if gc is dynamic library.  */
01184     GC_enable_incremental();
01185     (void) GC_set_warn_proc(warn_proc);
01186     if (thr_keycreate(&fl_key, GC_free) != 0) {
01187         (void)GC_printf1("Key creation failed %lu\n", (unsigned long)code);
01188        FAIL;
01189     }
01190     if ((code = thr_create(0, 1024*1024, thr_run_one_test, 0, 0, &th1)) != 0) {
01191        (void)GC_printf1("Thread 1 creation failed %lu\n", (unsigned long)code);
01192        FAIL;
01193     }
01194     if ((code = thr_create(0, 1024*1024, thr_run_one_test, 0, THR_NEW_LWP, &th2)) != 0) {
01195        (void)GC_printf1("Thread 2 creation failed %lu\n", (unsigned long)code);
01196        FAIL;
01197     }
01198     run_one_test();
01199     if ((code = thr_join(th1, 0, 0)) != 0) {
01200         (void)GC_printf1("Thread 1 failed %lu\n", (unsigned long)code);
01201         FAIL;
01202     }
01203     if (thr_join(th2, 0, 0) != 0) {
01204         (void)GC_printf1("Thread 2 failed %lu\n", (unsigned long)code);
01205         FAIL;
01206     }
01207     check_heap_stats();
01208     (void)fflush(stdout);
01209     return(0);
01210 }
01211 #else /* pthreads */
01212 main()
01213 {
01214     pthread_t th1;
01215     pthread_t th2;
01216     pthread_attr_t attr;
01217     int code;
01218 
01219 #   ifdef IRIX_THREADS
01220        /* Force a larger stack to be preallocated      */
01221        /* Since the initial cant always grow later.     */
01222        *((volatile char *)&code - 1024*1024) = 0;      /* Require 1 Mb */
01223 #   endif /* IRIX_THREADS */
01224     pthread_attr_init(&attr);
01225 #   ifdef IRIX_THREADS
01226        pthread_attr_setstacksize(&attr, 1000000);
01227 #   endif
01228     n_tests = 0;
01229 #   ifdef MPROTECT_VDB
01230        GC_enable_incremental();
01231         (void) GC_printf0("Switched to incremental mode\n");
01232        (void) GC_printf0("Emulating dirty bits with mprotect/signals\n");
01233 #   endif
01234     (void) GC_set_warn_proc(warn_proc);
01235     if (pthread_key_create(&fl_key, 0) != 0) {
01236         (void)GC_printf1("Key creation failed %lu\n", (unsigned long)code);
01237        FAIL;
01238     }
01239     if ((code = pthread_create(&th1, &attr, thr_run_one_test, 0)) != 0) {
01240        (void)GC_printf1("Thread 1 creation failed %lu\n", (unsigned long)code);
01241        FAIL;
01242     }
01243     if ((code = pthread_create(&th2, &attr, thr_run_one_test, 0)) != 0) {
01244        (void)GC_printf1("Thread 2 creation failed %lu\n", (unsigned long)code);
01245        FAIL;
01246     }
01247     run_one_test();
01248     if ((code = pthread_join(th1, 0)) != 0) {
01249         (void)GC_printf1("Thread 1 failed %lu\n", (unsigned long)code);
01250         FAIL;
01251     }
01252     if (pthread_join(th2, 0) != 0) {
01253         (void)GC_printf1("Thread 2 failed %lu\n", (unsigned long)code);
01254         FAIL;
01255     }
01256     check_heap_stats();
01257     (void)fflush(stdout);
01258     pthread_attr_destroy(&attr);
01259     GC_printf1("Completed %d collections\n", GC_gc_no);
01260     return(0);
01261 }
01262 #endif /* pthreads */
01263 #endif /* SOLARIS_THREADS || IRIX_THREADS || LINUX_THREADS */