00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 # include <stdio.h>
00021 # include <signal.h>
00022 # include <sys/types.h>
00023 # include "gc_private.h"
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 word GC_non_gc_bytes = 0;
00074
00075 word GC_gc_no = 0;
00076
00077 char * GC_copyright[] =
00078 {"Copyright 1988,1989 Hans-J. Boehm and Alan J. Demers",
00079 "Copyright (c) 1991,1992 by Xerox Corporation. All rights reserved.",
00080 "THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY",
00081 " EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK."};
00082
00083
00084
00085
00086 extern signed_word GC_mem_found;
00087
00088
00089
00090 void GC_clear_hdr_marks(hhdr)
00091 register hdr * hhdr;
00092 {
00093 bzero((char *)hhdr -> hb_marks, (int)(MARK_BITS_SZ*sizeof(word)));
00094 }
00095
00096
00097
00098
00099
00100 static void clear_marks_for_block(h, dummy)
00101 struct hblk *h;
00102 word dummy;
00103 {
00104 register hdr * hhdr = HDR(h);
00105
00106 GC_clear_hdr_marks(hhdr);
00107 }
00108
00109
00110
00111
00112 static void clear_marks()
00113 {
00114 GC_apply_to_all_blocks(clear_marks_for_block, (word)0);
00115 }
00116
00117 bool GC_dont_expand = 0;
00118
00119 word GC_free_space_divisor = 4;
00120
00121
00122
00123 static word min_words_allocd()
00124 {
00125 int dummy;
00126 # ifdef THREADS
00127
00128 register signed_word stack_size = 10000;
00129 # else
00130 register signed_word stack_size = (ptr_t)(&dummy) - GC_stackbottom;
00131 # endif
00132 register word total_root_size;
00133
00134
00135
00136 if (stack_size < 0) stack_size = -stack_size;
00137 total_root_size = 2 * stack_size + GC_root_size;
00138 return(BYTES_TO_WORDS(GC_heapsize + total_root_size)/GC_free_space_divisor);
00139 }
00140
00141
00142
00143
00144 word GC_adj_words_allocd()
00145 {
00146 register signed_word result;
00147 register signed_word expl_managed =
00148 BYTES_TO_WORDS((long)GC_non_gc_bytes
00149 - (long)GC_non_gc_bytes_at_gc);
00150
00151
00152
00153
00154
00155 result = (signed_word)GC_words_allocd
00156 - (signed_word)GC_mem_freed - expl_managed;
00157 if (result > (signed_word)GC_words_allocd) result = GC_words_allocd;
00158
00159 if (result < (signed_word)(GC_words_allocd >> 2)) {
00160
00161
00162
00163
00164 return(GC_words_allocd >> 3);
00165 } else {
00166 return(result);
00167 }
00168 }
00169
00170
00171
00172
00173
00174
00175
00176 void GC_clear_a_few_frames()
00177 {
00178 # define NWORDS 64
00179 word frames[NWORDS];
00180 register int i;
00181
00182 for (i = 0; i < NWORDS; i++) frames[i] = 0;
00183 }
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 bool GC_gcollect_inner(force)
00195 bool force;
00196
00197
00198 {
00199 # ifdef PRINTTIMES
00200 CLOCK_TYPE start_time;
00201 CLOCK_TYPE mark_time;
00202 CLOCK_TYPE done_time;
00203 # endif
00204
00205 if (!force && !GC_dont_expand
00206 && GC_adj_words_allocd() < min_words_allocd()) return(FALSE);
00207 # ifdef PRINTTIMES
00208 GET_TIME(start_time);
00209 # endif
00210 # ifdef PRINTSTATS
00211 GC_printf2("Collection %lu reclaimed %ld bytes\n",
00212 (unsigned long) GC_gc_no,
00213 (long)WORDS_TO_BYTES(GC_mem_found));
00214 # endif
00215 GC_gc_no++;
00216 # ifdef GATHERSTATS
00217 GC_mem_found = 0;
00218 GC_composite_in_use = 0;
00219 GC_atomic_in_use = 0;
00220 # endif
00221 # ifdef PRINTSTATS
00222 GC_printf2("Collection number %lu after %lu allocated bytes ",
00223 (unsigned long) GC_gc_no,
00224 (unsigned long) WORDS_TO_BYTES(GC_words_allocd));
00225 GC_printf1("(heapsize = %lu bytes)\n",
00226 (unsigned long) GC_heapsize);
00227
00228
00229 GC_printf0("");
00230 # endif
00231
00232 clear_marks();
00233
00234 STOP_WORLD();
00235
00236
00237
00238 GC_clear_a_few_frames();
00239 GC_noop(0,0,0,0,0,0);
00240 GC_mark_roots();
00241 GC_promote_black_lists();
00242
00243
00244 if (GC_debugging_started) {
00245 GC_check_heap();
00246 }
00247
00248 START_WORLD();
00249
00250 # ifdef PRINTTIMES
00251 GET_TIME(mark_time);
00252 # endif
00253
00254
00255 # ifdef FIND_LEAK
00256
00257
00258 {
00259 register word size;
00260 register ptr_t p;
00261 register struct hblk * h;
00262 register hdr * hhdr;
00263 register int word_no;
00264 int kind;
00265
00266 for (kind = 0; kind < GC_n_kinds; kind++) {
00267 for (size = 1; size <= MAXOBJSZ; size++) {
00268 for (p= GC_obj_kinds[kind].ok_freelist[size];
00269 p != 0; p=obj_link(p)){
00270 h = HBLKPTR(p);
00271 hhdr = HDR(h);
00272 word_no = (((word *)p) - ((word *)h));
00273 set_mark_bit_from_hdr(hhdr, word_no);
00274 }
00275 }
00276 }
00277 }
00278
00279 GC_start_reclaim(TRUE);
00280 # else
00281
00282 GC_finalize();
00283
00284
00285
00286
00287
00288
00289
00290 {
00291 register word size;
00292 register ptr_t p;
00293 register struct hblk * h;
00294 register hdr * hhdr;
00295 register int word_no;
00296 int kind;
00297
00298 for (kind = 0; kind < GC_n_kinds; kind++) {
00299 for (size = 1; size <= MAXOBJSZ; size++) {
00300 for (p= GC_obj_kinds[kind].ok_freelist[size];
00301 p != 0; p=obj_link(p)){
00302 h = HBLKPTR(p);
00303 hhdr = HDR(h);
00304 word_no = (((word *)p) - ((word *)h));
00305 clear_mark_bit_from_hdr(hhdr, word_no);
00306 GC_mem_found -= size;
00307 }
00308 }
00309 }
00310 }
00311
00312
00313 # ifdef PRINTSTATS
00314 GC_printf1("Bytes recovered before GC_reclaim - f.l. count = %ld\n",
00315 (long)WORDS_TO_BYTES(GC_mem_found));
00316 # endif
00317
00318
00319 GC_start_reclaim(FALSE);
00320
00321 # endif
00322
00323 # ifdef PRINTSTATS
00324 GC_printf2(
00325 "Immediately reclaimed %ld bytes in heap of size %lu bytes\n",
00326 (long)WORDS_TO_BYTES(GC_mem_found),
00327 (unsigned long)GC_heapsize);
00328 GC_printf2("%lu (atomic) + %lu (composite) bytes in use\n",
00329 (unsigned long)WORDS_TO_BYTES(GC_atomic_in_use),
00330 (unsigned long)WORDS_TO_BYTES(GC_composite_in_use));
00331 # endif
00332
00333
00334 GC_words_allocd_before_gc += GC_words_allocd;
00335 GC_non_gc_bytes_at_gc = GC_non_gc_bytes;
00336 GC_words_allocd = 0;
00337 GC_mem_freed = 0;
00338
00339
00340 # ifdef PRINTTIMES
00341 GET_TIME(done_time);
00342 GC_printf2("Garbage collection took %lu + %lu msecs\n",
00343 MS_TIME_DIFF(mark_time,start_time),
00344 MS_TIME_DIFF(done_time,mark_time));
00345 # endif
00346 return(TRUE);
00347 }
00348
00349
00350 void GC_gcollect()
00351 {
00352 DCL_LOCK_STATE;
00353
00354 DISABLE_SIGNALS();
00355 LOCK();
00356 if (!GC_is_initialized) GC_init_inner();
00357
00358 GC_noop(0,0,0,0,0,0);
00359 (void) GC_gcollect_inner(TRUE);
00360 UNLOCK();
00361 ENABLE_SIGNALS();
00362 }
00363
00364
00365
00366
00367
00368 void GC_add_to_heap(p, bytes)
00369 struct hblk *p;
00370 word bytes;
00371 {
00372 word words;
00373
00374 GC_install_header(p);
00375 words = BYTES_TO_WORDS(bytes - HDR_BYTES);
00376 HDR(p) -> hb_sz = words;
00377 GC_freehblk(p);
00378 GC_heapsize += bytes;
00379 if ((ptr_t)p <= GC_least_plausible_heap_addr
00380 || GC_least_plausible_heap_addr == 0) {
00381 GC_least_plausible_heap_addr = (ptr_t)p - sizeof(word);
00382
00383
00384
00385
00386 }
00387 if ((ptr_t)p + bytes >= GC_greatest_plausible_heap_addr) {
00388 GC_greatest_plausible_heap_addr = (ptr_t)p + bytes;
00389 }
00390 }
00391
00392 ptr_t GC_least_plausible_heap_addr = (ptr_t)ONES;
00393 ptr_t GC_greatest_plausible_heap_addr = 0;
00394
00395 ptr_t GC_max(x,y)
00396 ptr_t x, y;
00397 {
00398 return(x > y? x : y);
00399 }
00400
00401 ptr_t GC_min(x,y)
00402 ptr_t x, y;
00403 {
00404 return(x < y? x : y);
00405 }
00406
00407
00408
00409
00410
00411
00412
00413 bool GC_expand_hp_inner(n)
00414 word n;
00415 {
00416 word bytes = n * HBLKSIZE;
00417 struct hblk * space = GET_MEM(bytes);
00418 word expansion_slop;
00419
00420
00421 if (n > 2*GC_hincr) {
00422 GC_hincr = n/2;
00423 }
00424 if( space == 0 ) {
00425 return(FALSE);
00426 }
00427 # ifdef PRINTSTATS
00428 GC_printf1("Increasing heap size by %lu\n",
00429 (unsigned long)bytes);
00430 # endif
00431 expansion_slop = 8 * WORDS_TO_BYTES(min_words_allocd());
00432 if (5 * HBLKSIZE * MAXHINCR > expansion_slop) {
00433 expansion_slop = 5 * HBLKSIZE * MAXHINCR;
00434 }
00435 if (GC_last_heap_addr == 0 && !((word)space & SIGNB)
00436 || GC_last_heap_addr != 0 && GC_last_heap_addr < (ptr_t)space) {
00437
00438 GC_greatest_plausible_heap_addr =
00439 GC_max(GC_greatest_plausible_heap_addr,
00440 (ptr_t)space + bytes + expansion_slop);
00441 } else {
00442
00443 GC_least_plausible_heap_addr =
00444 GC_min(GC_least_plausible_heap_addr,
00445 (ptr_t)space - expansion_slop);
00446 }
00447 GC_prev_heap_addr = GC_last_heap_addr;
00448 GC_last_heap_addr = (ptr_t)space;
00449 GC_add_to_heap(space, bytes);
00450 return(TRUE);
00451 }
00452
00453
00454 int GC_expand_hp(n)
00455 int n;
00456 {
00457 int result;
00458 DCL_LOCK_STATE;
00459
00460 DISABLE_SIGNALS();
00461 LOCK();
00462 if (!GC_is_initialized) GC_init_inner();
00463 result = (int)GC_expand_hp_inner((word)n);
00464 UNLOCK();
00465 ENABLE_SIGNALS();
00466 return(result);
00467 }
00468
00469 void GC_collect_or_expand(needed_blocks)
00470 word needed_blocks;
00471 {
00472 static int count = 0;
00473
00474 if (GC_dont_gc || !GC_gcollect_inner(FALSE)) {
00475 if (!GC_expand_hp_inner(GC_hincr + needed_blocks)
00476 && !GC_expand_hp_inner(needed_blocks)) {
00477 if (count++ < 20) {
00478 WARN("Out of Memory! Trying to continue ...\n");
00479 GC_gcollect_inner(TRUE);
00480 } else {
00481 GC_err_printf0("Out of Memory! Giving up!\n");
00482 EXIT();
00483 }
00484 }
00485 update_GC_hincr;
00486 }
00487 }
00488
00489
00490
00491
00492
00493
00494
00495 ptr_t GC_allocobj(sz, kind)
00496 word sz;
00497 int kind;
00498 {
00499 register ptr_t * flh = &(GC_obj_kinds[kind].ok_freelist[sz]);
00500
00501 if (sz == 0) return(0);
00502
00503 while (*flh == 0) {
00504 GC_continue_reclaim(sz, kind);
00505 if (*flh == 0) {
00506 GC_new_hblk(sz, kind);
00507 }
00508 if (*flh == 0) {
00509 GC_collect_or_expand((word)1);
00510 }
00511 }
00512 return(*flh);
00513 }