Andrew Torda said:
I have a perl module built out of XSUBs.
The functions malloc() space, build structures and return
pointers to perl. Perl calls their destructor routines with no
problems. The C structures go back to the perl interpreter, as
T_PTROBJ things, specified in a typemap file.
Now, if I use threads, I
make lots of new data
break my arrays into 2 pieces
threads->new( myfunc, @array_to_read_from);
threads->new( myfunc, @array_to_read_from);
thread[0]->join
thread[1]->join
Unfortunately, at the join() stage, each thread decides to
cleanup, and call the destructors for my @array_to_read_from.
Obviously free() gets called multiple times, terrible things
happen to the heap and everything dies.
Can't quite reproduce the exact problem. I gather that '@array_to_read_from'
is an array of these "pointer" objects. Below my sig is an Inline::C script
that (I think) does pretty much as described (and not much else). It doesn't
use a typemap, but I don't think there's any relevance in that.
I find that there's no problem at the join() stage. The cleanup of the
pointer objects does not take place (afaict) until the script is about to
exit (which is as it should be). At that time, however, a problem usually
(but not always) does arise - after the majority of the pointer objects have
been freed, I get (on Win32) the "Free to wrong pool...during global
destruction" error. (That's a problem - but it may be a Win32-specific
issue, so I won't go delving into that just yet. Which OS are you on ? I was
going to give the script a run on Linux .... but my perl on Linux wasn't
built with threads support.)
Anyway ... the output I get looks like this:
Thread started
Thread started
Thread started
200 400 650
All joined
destroying int object
int object destroyed
destroying int object
int object destroyed
..
..
..
destroying int object
int object destroyed
destroying int object
Free to wrong pool b39078 not c5d040 during global destruction.
If you already have (or can be bothered installing) Inline::C then you might
run the script and check that the problem really does occur when you think
it does. Otoh, I might have been way off-beam with my interpretation of what
you've said - and/or my script may be irrelevant to the problem you're
facing - in which case feel free to modify it to better demonstrate the
issue at hand.
(Btw, with that script, I've established that the cleanup problem *is*
associated with the using of threads. If I remove the threads stuff , then
the cleanup proceeds smoothly every time. I also tried replacing malloc/free
with New/Safefree, but it made no difference - which is not surprising.)
Hth - but don't stress too much if it doesn't
Cheers,
Rob
use warnings;
use threads;
package Experimental;
use Inline C => Config =>
BUILD_NOISY => 1;
use Inline C => <<'EOC';
SV * create_int_obj(SV * x) {
int * int_obj, i, s;
SV * obj_ref, * obj;
s = (int)SvUV(x);
/* Allocate space for s ints */
/* New(1, int_obj, s, int); */
int_obj = malloc(sizeof(int) * s);
if(int_obj == NULL) croak("Failed to allocate memory in create_int_obj
function");
obj_ref = newSViv(0);
obj = newSVrv(obj_ref, "Experimental");
sv_setiv(obj, (IV)int_obj);
SvREADONLY_on(obj);
return obj_ref;
}
void DESTROY(SV * m) {
printf("destroying int object\n");
/* Safefree((int *) SvIV(SvRV(m))); */
free((int *) SvIV(SvRV(m)));
printf("int object destroyed\n");
}
EOC
# Create an array of 200 pointer objects
@array_to_read_from_1 = create_em(200);
# Create an array of 400 pointer objects.
@array_to_read_from_2 = create_em(400);
# Create an array of 650 pointers.
@array_to_read_from_3 = create_em(650);
$thread1 = threads->new("start_thread", @array_to_read_from_1);
$thread2 = threads->new("start_thread", @array_to_read_from_2);
$thread3 = threads->new("start_thread", @array_to_read_from_3);
$s1 = $thread1->join;
$s2 = $thread2->join;
$s3 = $thread3->join;
print "$s1 $s2 $s3\n";
print "All joined\n";
sleep(2);
# Then usually crashes at some time during the destruction of
# the pointer objects with the error "Free to wrong pool...during global
destruction"
sub start_thread {
print "Thread started\n";
return scalar(@_);
}
sub create_em {
# Return an array of pointer objects.
my @ret = ();
for(1..$_[0]) { push(@ret, create_int_obj(10 + int(rand(10))))}
return @ret;
}