# New Ticket Created by Leopold Toetsch
# Please include the string: [perl #19622]
# in the subject line of all future correspondence about this issue.
# <URL: http://rt.perl.org/rt2/Ticket/Display.html?id=19622 >
I did write:
[1] which BTW seems bogus to me: pool_compact() may be called (when
there is enough reclaimable space), without having a DOD run immediately
before it. So e.g. the on_free_list flag might not reflect current usage
of a buffer.
Here is a program showing more problems with the current implementation:
set S0, "abcdefghij"
set I0, 0
lp:
repeat S1, S0, 5000
ne S0, "abcdefghij", nok
substr S2, S1, 1, 1
ne S2, "b", nok
inc I0
lt I0, 1000, lp
print "ok\n"
end
nok:
print "nok\n"
print S0
print " - "
print S1
print "\n"
end
The substr makes a COW reference of S1, which doesn't set
pool->guaranteed_reclaimable, so when above is run without --gc-debug,
pool->compact gets nether called and the program dies with SIGSEGV - the
real reason is a NULL pointer returned from malloc().
--gc-debug does a DOD run + an unconditional compact_pool, so the
program runs fine.
A proposed change could look like attached patch:
- die when malloc returns zero (IMHO we can't recover)
- always call do_dod_run before compact_pool
- when possibly_reclaimable reaches a certain amount, always compact the
pool - the reclaim_factor (currently 20%) doesn't really matter, it just
allows that the pool gets compacted sooner or later - it is used now as
a probablity meaning 20% of COWed strings might be reclaimable.
leo
-- attachment 1 ------------------------------------------------------
url: http://rt.perl.org/rt2/attach/46630/36629/d8ca8a/resources.c.patch
--- resources.c Fri Dec 27 10:34:28 2002
+++ /home/lt/src/parrot-leo/resources.c Tue Dec 31 14:26:26 2002
@@ -45,6 +45,8 @@
new_block = mem_sys_allocate_zeroed(sizeof(struct Memory_Block) +
alloc_size + 32);
if (!new_block) {
+ fprintf(stderr, "out of mem allocsize = %d\n", (int)alloc_size+32);
+ exit(1);
return NULL;
}
@@ -110,25 +112,25 @@
}
}
if (pool->top_block->free < size) {
+ Parrot_do_dod_run(interpreter);
/* Compact the pool if allowed and worthwhile */
if (pool->compact) {
/* don't bother reclaiming if its just chicken feed */
- if ((pool->possibly_reclaimable + pool->guaranteed_reclaimable) / 2
- > (size_t)(pool->total_allocated * pool->reclaim_factor)
+ if (pool->possibly_reclaimable * pool->reclaim_factor
+ > size
/* don't bother reclaiming if it won't even be enough */
- && (pool->guaranteed_reclaimable > size)
+ || (pool->guaranteed_reclaimable > size)
) {
(*pool->compact) (interpreter, pool);
}
- else {
- Parrot_do_dod_run(interpreter);
- }
}
if (pool->top_block->free < size) {
alloc_new_block(interpreter, size, pool);
interpreter->mem_allocs_since_last_collect++;
if (pool->top_block->free < size) {
+ fprintf(stderr, "out of mem\n");
+ exit(1);
return NULL;
}
}