If Perl assume all UVs were really pointers to SVs, it would crash left and right.
Remember, I'm only suggesting this can happen during cloning, not normal operations. Remember that SvRVs & SvIVs used to be different types. Maybe the cloning code, written before this amalgamation, only checked for SvTYPE and has never been updated to further distinguish RVs from IV/UVs?
Maybe you have a better explanation for this observed behaviour:
...
package main;
use threads;
use Devel::Peek;
my $o = O->new();
print $o;
$o->set( "abcde" );
print $o->get();
print "\nthreaded\n";
async {
print $o->get( );
$o->set( 12345 );
print $o->get( );
}->join;
print $o->get();
__END__
C:\test>xso
N:rv:000000000035E128 o:0000000003FFA818
O=SCALAR(0x3ffa818)
S:rv;000000000035E248 o:0000000003C318F0
G:rv;000000000035E248 o:0000000003C318F0 old:000000000035E128
abcde
threaded
G:rv;0000000004258CA8 o:0000000004229090 old:0000000000000000
S:rv;0000000004258CA8 o:0000000004229090
G:rv;0000000004258CA8 o:0000000004229090 old:0000000004259920
12345
G:rv;000000000035E248 o:0000000003C318F0 old:000000000035E128
abcde
Before the thread, I set a value into the struct, and get it back.
Then I move into the thread, the RV gets cloned, the SvUV it points to gets cloned; but the value within the SvUV (labelled 'o:' in the printfs), also changes. And as the numeric value inside the UV (which we know is a pointer but Perl shouldn't), has also changed. It no longer points to the original struct. Hence, 'old:' no longer has a value.
I then insert a different value into the struct, and successfully retrieve that value. I then exit the thread and, and get the value again, and lo, I get the original value set, not the one I modified inside the thread.
No, the *only* explanation that I can come up with for that behaviour is that when the RV and UV get cloned, it also clones the thing that the UV points to; even though it shouldn't know that the numberic value in the UV is a pointer. Do you have a better explanation?
The full code: #! perl -slw
use strict;
package O;
use Inline C => Config => BUILD_NOISY => 1;
use Inline C => <<'END_C', NAME => 'xso', CLEAN_AFTER_BUILD => 0;
typedef struct {
SV**sv;
} O;
void *mem( size_t size ) {
void *p;
Newx( p, size, char );
return p;
}
SV *new( char *package ) {
O *o = (O*)mem( sizeof( O ) );
SV *rv = newRV( (SV*)o );
o->sv = mem( sizeof( SV* ) );
sv_bless( rv, gv_stashpv( package, 0 ) );
SvREADONLY_on( rv );
printf( "N:rv:%p o:%p\n", rv, o );
return rv;
}
int set( SV *rv, SV *in ) {
O *o = ( *(O**)SvUV( rv ) ) - 1;
printf( "S:rv;%p o:%p\n", rv, o );
o->sv = newSVsv( in );
return 1;
}
SV *get( SV *rv ) {
O *o = ( *(O**)SvUV( rv ) ) - 1;
SV *old = newSVsv( o->sv );
SvREFCNT_inc( old );
printf( "G:rv;%p o:%p old:%p\n", rv, o, o->sv );
return old;
}
END_C
package main;
use threads;
use Devel::Peek;
my $o = O->new();
print $o;
$o->set( "abcde" );
print $o->get();
print "\nthreaded\n";
async {
print $o->get( );
$o->set( 12345 );
print $o->get( );
}->join;
print $o->get();
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
|