1 /* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002 Free Software Foundation, Inc.
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "libguile/_scm.h"
23 #include "libguile/pairs.h"
24 #include "libguile/gc.h"
25 #include "libguile/private-gc.h"
31 size_t scm_max_segment_size
;
34 scm_i_make_empty_heap_segment (scm_t_cell_type_statistics
*fl
)
36 scm_t_heap_segment
* shs
= malloc (sizeof (scm_t_heap_segment
));
40 fprintf (stderr
, "scm_i_get_new_heap_segment: out of memory.\n");
44 shs
->bounds
[0] = NULL
;
45 shs
->bounds
[1] = NULL
;
49 shs
->next_free_card
= NULL
;
56 Fill SEGMENT with memory both for data and mark bits.
58 RETURN: 1 on success, 0 failure
61 scm_i_initialize_heap_segment_data (scm_t_heap_segment
* segment
, size_t requested
)
66 int card_data_cell_count
= (SCM_GC_CARD_N_CELLS
- SCM_GC_CARD_N_HEADER_CELLS
);
67 int card_count
=1 + (requested
/ sizeof (scm_t_cell
)) / card_data_cell_count
;
70 one card extra due to alignment
72 size_t mem_needed
= (1+card_count
) * SCM_GC_SIZEOF_CARD
73 + SCM_GC_CARD_BVEC_SIZE_IN_LONGS
* card_count
* SCM_SIZEOF_LONG
75 scm_t_c_bvec_long
* bvec_ptr
= 0;
76 scm_t_cell
* memory
= 0;
79 We use malloc to alloc the heap. On GNU libc this is
80 equivalent to mmapping /dev/zero
82 SCM_SYSCALL (memory
= (scm_t_cell
* ) calloc (1, mem_needed
));
87 segment
->malloced
= memory
;
88 segment
->bounds
[0] = SCM_GC_CARD_UP (memory
);
89 segment
->bounds
[1] = segment
->bounds
[0] + card_count
* SCM_GC_CARD_N_CELLS
;
91 segment
->freelist
->heap_size
+= scm_i_segment_cell_count (segment
);
93 bvec_ptr
= (scm_t_c_bvec_long
*) segment
->bounds
[1];
96 Don't init the mem or the bitvector. This is handled by lazy
100 segment
->next_free_card
= segment
->bounds
[0];
101 segment
->first_time
= 1;
106 scm_i_segment_card_count (scm_t_heap_segment
* seg
)
108 return (seg
->bounds
[1] - seg
->bounds
[0]) / SCM_GC_CARD_N_CELLS
;
112 Return the number of available single-cell data cells.
115 scm_i_segment_cell_count (scm_t_heap_segment
* seg
)
117 return scm_i_segment_card_count (seg
) * (SCM_GC_CARD_N_CELLS
- SCM_GC_CARD_N_HEADER_CELLS
)
118 + ((seg
->span
== 2) ? -1 : 0);
122 scm_i_clear_segment_mark_space (scm_t_heap_segment
*seg
)
124 scm_t_cell
* markspace
= seg
->bounds
[1];
126 memset (markspace
, 0x00,
127 scm_i_segment_card_count (seg
) * SCM_GC_CARD_BVEC_SIZE_IN_LONGS
* SCM_SIZEOF_LONG
);
131 Sweep cards from SEG until we've gathered THRESHOLD cells
138 scm_i_sweep_some_cards (scm_t_heap_segment
*seg
)
143 int (*sweeper
) (scm_t_cell
*, SCM
*, scm_t_heap_segment
* )
144 = (seg
->first_time
) ? &scm_i_init_card_freelist
: &scm_i_sweep_card
;
146 scm_t_cell
* next_free
= seg
->next_free_card
;
149 while (collected
< threshold
&& next_free
< seg
->bounds
[1])
151 collected
+= (*sweeper
) (next_free
, &cells
, seg
);
152 next_free
+= SCM_GC_CARD_N_CELLS
;
156 scm_gc_cells_swept
+= cards_swept
* (SCM_GC_CARD_N_CELLS
- SCM_GC_CARD_N_HEADER_CELLS
);
157 scm_gc_cells_collected
+= collected
* seg
->span
;
159 if (!seg
->first_time
)
160 scm_cells_allocated
-= collected
* seg
->span
;
162 seg
->freelist
->collected
+= collected
* seg
->span
;
165 if(next_free
== seg
->bounds
[1])
170 seg
->next_free_card
= next_free
;
176 Force a sweep of this entire segment. This doesn't modify sweep
177 statistics, it just frees the memory pointed to by to-be-swept
180 Implementation is slightly ugh.
182 FIXME: if you do scm_i_sweep_segment(), and then allocate from this
183 segment again, the statistics are off.
186 scm_i_sweep_segment (scm_t_heap_segment
* seg
)
188 scm_t_cell
* p
= seg
->next_free_card
;
189 int yield
= scm_gc_cells_collected
;
190 int coll
= seg
->freelist
->collected
;
191 unsigned long alloc
= scm_cells_allocated
;
193 while (scm_i_sweep_some_cards (seg
) != SCM_EOL
)
196 scm_gc_cells_collected
= yield
;
197 scm_cells_allocated
= alloc
;
198 seg
->freelist
->collected
= coll
;
200 seg
->next_free_card
=p
;
204 scm_i_sweep_all_segments (char const *reason
)
208 for (i
= 0; i
< scm_i_heap_segment_table_size
; i
++)
210 scm_i_sweep_segment (scm_i_heap_segment_table
[i
]);
218 The table is sorted by the address of the data itself. This makes
219 for easy lookups. This is not portable: according to ANSI C,
220 pointers can only be compared within the same object (i.e. the same
221 block of malloced memory.). For machines with weird architectures,
222 this should be revised.
224 (Apparently, for this reason 1.6 and earlier had macros for pointer
227 perhaps it is worthwhile to remove the 2nd level of indirection in
228 the table, but this certainly makes for cleaner code.
230 scm_t_heap_segment
** scm_i_heap_segment_table
;
231 size_t scm_i_heap_segment_table_size
;
232 scm_t_cell
*lowest_cell
;
233 scm_t_cell
*highest_cell
;
237 scm_i_clear_mark_space (void)
240 for (; i
< scm_i_heap_segment_table_size
; i
++)
242 scm_i_clear_segment_mark_space (scm_i_heap_segment_table
[i
]);
248 RETURN: index of inserted segment.
251 scm_i_insert_segment (scm_t_heap_segment
* seg
)
253 size_t size
= (scm_i_heap_segment_table_size
+ 1) * sizeof (scm_t_heap_segment
*);
254 SCM_SYSCALL(scm_i_heap_segment_table
= ((scm_t_heap_segment
**)
255 realloc ((char *)scm_i_heap_segment_table
, size
)));
258 We can't alloc 4 more bytes. This is hopeless.
260 if (!scm_i_heap_segment_table
)
262 fprintf (stderr
, "scm_i_get_new_heap_segment: Could not grow heap segment table.\n");
268 lowest_cell
= seg
->bounds
[0];
269 highest_cell
= seg
->bounds
[1];
273 lowest_cell
= SCM_MIN (lowest_cell
, seg
->bounds
[0]);
274 highest_cell
= SCM_MAX (highest_cell
, seg
->bounds
[1]);
282 while (i
< scm_i_heap_segment_table_size
283 && scm_i_heap_segment_table
[i
]->bounds
[0] <= seg
->bounds
[0])
287 We insert a new entry; if that happens to be before the
288 "current" segment of a freelist, we must move the freelist index
291 if (scm_i_master_freelist
.heap_segment_idx
>= i
)
292 scm_i_master_freelist
.heap_segment_idx
++;
293 if (scm_i_master_freelist2
.heap_segment_idx
>= i
)
294 scm_i_master_freelist2
.heap_segment_idx
++;
296 for (j
= scm_i_heap_segment_table_size
; j
> i
; --j
)
297 scm_i_heap_segment_table
[j
] = scm_i_heap_segment_table
[j
- 1];
299 scm_i_heap_segment_table
[i
] = seg
;
300 scm_i_heap_segment_table_size
++;
307 scm_i_sweep_some_segments (scm_t_cell_type_statistics
* fl
)
309 int i
= fl
->heap_segment_idx
;
310 SCM collected
=SCM_EOL
;
316 i
< scm_i_heap_segment_table_size
; i
++)
318 if (scm_i_heap_segment_table
[i
]->freelist
!= fl
)
321 collected
= scm_i_sweep_some_cards (scm_i_heap_segment_table
[i
]);
324 if (collected
!= SCM_EOL
) /* Don't increment i */
328 fl
->heap_segment_idx
= i
;
337 scm_i_reset_segments (void)
340 for (; i
< scm_i_heap_segment_table_size
; i
++)
342 scm_t_heap_segment
* seg
= scm_i_heap_segment_table
[i
];
343 seg
->next_free_card
= seg
->bounds
[0];
349 Determine whether the given value does actually represent a cell in
350 some heap segment. If this is the case, the number of the heap
351 segment is returned. Otherwise, -1 is returned. Binary search is
352 used to determine the heap segment that contains the cell.
355 I think this function is too long to be inlined. --hwn
358 scm_i_find_heap_segment_containing_object (SCM obj
)
363 if ((scm_t_cell
* ) obj
< lowest_cell
|| (scm_t_cell
*) obj
>= highest_cell
)
368 scm_t_cell
* ptr
= SCM2PTR (obj
);
369 unsigned long int i
= 0;
370 unsigned long int j
= scm_i_heap_segment_table_size
- 1;
372 if (ptr
< scm_i_heap_segment_table
[i
]->bounds
[0])
374 else if (scm_i_heap_segment_table
[j
]->bounds
[1] <= ptr
)
380 if (ptr
< scm_i_heap_segment_table
[i
]->bounds
[1])
384 else if (scm_i_heap_segment_table
[j
]->bounds
[0] <= ptr
)
391 unsigned long int k
= (i
+ j
) / 2;
395 else if (ptr
< scm_i_heap_segment_table
[k
]->bounds
[1])
399 if (ptr
< scm_i_heap_segment_table
[i
]->bounds
[0])
402 else if (scm_i_heap_segment_table
[k
]->bounds
[0] <= ptr
)
406 if (scm_i_heap_segment_table
[j
]->bounds
[1] <= ptr
)
412 if (!SCM_DOUBLECELL_ALIGNED_P (obj
) && scm_i_heap_segment_table
[i
]->span
== 2)
414 else if (SCM_GC_IN_CARD_HEADERP (ptr
))
424 Important entry point: try to grab some memory, and make it into a
427 RETURN: the index of the segment.
430 scm_i_get_new_heap_segment (scm_t_cell_type_statistics
*freelist
, policy_on_error error_policy
)
434 if (scm_gc_heap_lock
)
436 /* Critical code sections (such as the garbage collector) aren't
437 * supposed to add heap segments.
439 fprintf (stderr
, "scm_i_get_new_heap_segment: Can not extend locked heap.\n");
444 /* Assure that the new segment is predicted to be large enough.
446 * New yield should at least equal GC fraction of new heap size, i.e.
448 * y + dh > f * (h + dh)
451 * f : min yield fraction
453 * dh : size of new heap segment
455 * This gives dh > (f * h - y) / (1 - f)
457 float f
= freelist
->min_yield_fraction
/ 100.0;
458 float h
= SCM_HEAP_SIZE
;
460 = (f
* h
- scm_gc_cells_collected
) / (1.0 - f
);
462 /* Make heap grow with factor 1.5 */
463 len
= freelist
->heap_size
/ 2;
465 fprintf (stderr
, "(%ld < %ld)", (long) len
, (long) min_cells
);
469 len
= (unsigned long) min_cells
;
470 len
*= sizeof (scm_t_cell
);
471 /* force new sampling */
472 freelist
->collected
= LONG_MAX
;
475 if (len
> scm_max_segment_size
)
476 len
= scm_max_segment_size
;
477 if (len
< SCM_MIN_HEAP_SEG_SIZE
)
478 len
= SCM_MIN_HEAP_SEG_SIZE
;
481 scm_t_heap_segment
* seg
= scm_i_make_empty_heap_segment (freelist
);
483 /* Allocate with decaying ambition. */
484 while (len
>= SCM_MIN_HEAP_SEG_SIZE
)
486 if (scm_i_initialize_heap_segment_data (seg
, len
))
488 return scm_i_insert_segment (seg
);
495 if (error_policy
== abort_on_error
)
497 fprintf (stderr
, "scm_i_get_new_heap_segment: Could not grow heap.\n");
504 scm_i_make_initial_segment (int init_heap_size
, scm_t_cell_type_statistics
*freelist
)
506 scm_t_heap_segment
* seg
= scm_i_make_empty_heap_segment (freelist
);
508 if (init_heap_size
< 1)
510 init_heap_size
= SCM_DEFAULT_INIT_HEAP_SIZE_1
;
513 if (scm_i_initialize_heap_segment_data (seg
, init_heap_size
))
515 freelist
->heap_segment_idx
= scm_i_insert_segment (seg
);
519 Why the fuck try twice? --hwn
523 scm_i_initialize_heap_segment_data (seg
, SCM_HEAP_SEG_SIZE
);
526 if (freelist
->min_yield_fraction
)
527 freelist
->min_yield
= (freelist
->heap_size
* freelist
->min_yield_fraction