[now take your time to read the Example::CLONE manpage in [1] which explains all the issues and shows possible solutions]
To save you the hussle, here is the manpage (but you will probably want to see the code and the tests anyway).
__END__
=head1 NAME
Example::CLONE - Demonstrate the CLONE function under perl threads
=head1 Synopsis
use Example::CLONE; my $obj = Example::CLONE->new($expected); my $read = $obj->read; my $count = $obj->count;
=head1 Description
This module demonstrates how to handle objects containing references to C structs under threads. Example::CLONE accepts a string to store as the argument to new() and then it can read() that string and tell how many times it has been via count().
As the module name implies it shows how to write a special CLONE function that takes an object cloned by perl (which doesn't know that the object contains a pointer to a C struct) and replaces the objects guts (_possess()) with a properly cloned C struct. In addition to preventing several perl interpreters accessing and modifying the same object at the same time (race condition) it also prevents the problem when several threads try to free the same C struct.
The only unusual things for module writers are:
=over
=item *
the method _possess(), which takes an object and replaces its guts with new contents, potentially copying the original content. The external object doesn't change, i.e. it still lives inside the same SV.
=item *
the function CLONE(), which is called by perl when perl_clone() is invoked.
When a new object is created its weak-reference copy is put into the object package's storage. When perl_clone() is called, perl clones all perl objects, though it doesn't know how to handle C structs (it doesn't even know that objects contain a pointer to a C struct, since they are merely IV values (numbers) to Perl). Therefore Perl checks whether a package defines a function CLONE, and if it does it calls it. In this function we iterate over all the objects that were created so far (we can do that since we have stored a weak-reference copy of the object in the package scoped storage), and do a proper cloning of the object. We make sure that the object itself looks the same on the outside, so it gets updated in the user space as well.
The weak-reference copy is used so that if the object is destroyed in the user space, the copy won't prevent its destruction. If it was a plain copy the object reference count will be more than one, and the object won't be destroyed till its copy is not destroyed.
When DESTROY is invoked the local storage is removed.
=back
=head1 Other things that need to be CLONEd
META: this probably belongs to some perl*.pod manpage.
=head2 Data stored in PL_modglobal
Every module that stores per-interpreter data in PL_modglobal may need to "clone" it in the CLONE method as well.
This is especially true for modules that use MY_CXT_INIT to allocate the per-interpreter storage. It allocates the buffer as the PVX of an untracked SV and then just stores the pointer as a UV. The SV is freed when the interpreter is destructed.
perl_clone() will copy the UV ptr in PL_modglobal, but if the first interpreter is destroyed before the second one, then the PL_modglobal entry in the second interpreter points to freed memory.
To clone PL_modglobal one could do:
#define MY_CXT_CLONE \
dMY_CXT_SV; \
my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1)); \
Copy(INT2PTR(my_cxt_t, SvUV(my_cxt_sv)), my_extp, 1, my_cxt_t); \
sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))And now any module using the MY_CXT_INIT call, needs to call this macro in an XS CLONE method such as:
void
CLONE(...)
CODE:
MY_CXT_CLONE;
=head1 Debug
To enable Perl debug tracing set: DEBUG => 1 in lib/Example/CLONE.pm
To enable C debug tracing build the module with:
% perl Makefile.PL CCFLAGS="-DEXAMPLE_CLONE_DEBUG"
=head1 Examples
t/basic.t - test the normal module functionality, no threads and demonstration features re involved
t/threads.t - test that the new features (CLONE/_possess) work. For example if you comment out the call to _possess() in CLONE.pm, this test will either hang or segfault.
=head1 XS Specifics
Due to a bug in perl 5.8.2 (fixed in 5.8.3), XSUBs called from CLONE will be called with the parent interpreter context and not clone's one. In which case XSUBs won't receive the correct arguments. Do see this problem, build this module with perl 5.8.2 w/ ithreads and comment out this line in CLONE.xs:
/* #define PERL_NO_GET_CONTEXT */
Now whenever a new perl intereprter is cloned you will get an error:
Usage: Example::CLONE::_possess(ref)
defining C<PERL_NO_GET_CONTEXT> avoids this problem, though may need to adjust your XS module to pass aTHX around as explained in the I<perlguts> manpage. You have to do it if that module will ever be run under perl 5.8.2. The good news is that your code will be faster when C<PERL_NO_GET_CONTEXT> is set, since now the perl context will be passed around instead of being retrieved from the global storage.
=head1 Bugs
Attempt to free unreferenced scalar: SV 0x822ecf8 during global destruction.
This is a bug in Scalar::Util::weaken, hopefully to be fixed in 5.8.3. For now just ignore this warning.
=head1 Author
Stas Bekman <[EMAIL PROTECTED]>
=cut
-- __________________________________________________________________ Stas Bekman JAm_pH ------> Just Another mod_perl Hacker http://stason.org/ mod_perl Guide ---> http://perl.apache.org mailto:[EMAIL PROTECTED] http://use.perl.org http://apacheweek.com http://modperlbook.org http://apache.org http://ticketmaster.com
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
