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