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