/* destruct.c */ #include <EXTERN.h> #include <perl.h>
/*
* gcc -o destruct destruct.c `perl-5.8.6-ithread -MExtUtils::Embed -e ccopts -e ldopts` -Wall -g
*/
static void keys_add(int add)
{
pthread_key_t key;
int i = 0;
for (i=0; i<add; i++) {
if (pthread_key_create(&key, 0) == 0) {
fprintf(stderr, "%d\n", i+1);
}
else {
fprintf(stderr, "failed to create the key %d\n", i+1);
}
}
}int main(int argc, char **argv, char **env)
{
char *embedding[] = { "", "-e", "0" };
PerlInterpreter *perl1, *perl2;
dTHX; perl1 = perl_alloc();
aTHX = perl1; PERL_SET_CONTEXT(perl1);
perl_construct(perl1);
perl_parse(perl1, NULL, 3, embedding, (char **)NULL);
Perl_warn(aTHX_ "Perl %p\n", perl1); aTHX = NULL; PL_curinterp = NULL;
perl2 = perl_alloc();
aTHX = perl1; PERL_SET_CONTEXT(perl2);
perl_construct(perl2);
perl_parse(perl2, NULL, 3, embedding, (char **)NULL);
Perl_warn(aTHX_ "Perl %p\n", perl2); /* 2 keys added by perl_alloc */
keys_add(1023); perl_destruct(perl2);
perl_free(perl2); aTHX = perl1; PERL_SET_CONTEXT(perl1);
perl_destruct(perl1);
perl_free(perl1); FREE_THREAD_KEY;
FREE_THREAD_KEY;exit(0); }
1) It's not simple to create a new independent interpreter w/o being affected by any previous creation. Notice that if I don't do:
PL_curinterp = NULL;
before calling perl_alloc() second time, ALLOC_THREAD_KEY doesn't happen at all (which is called by INIT_TLS_AND_INTERP).
If you comment out that line in my test program you will see that 1023 keys will be created - meaning that perl has used only one key. With that hackish reset of PL_curinterp a proper perl_alloc() happens and this program allocates 2 keys by perl, and keys_add(1023) fails.
So this is certainly something that needs to be fixed. there should be a way to call perl_alloc as if it was the first time it was ever called. Should there be a wrapper perl_alloc_pristine or something like that ensures first to reset anything perl_alloc may rely on?
2) As you can see if I call both FREE_THREAD_KEY at the end after everything was destroyed, it works. However if I do:
perl_destruct(perl2);
FREE_THREAD_KEY;
perl_free(perl2); aTHX = perl1; PERL_SET_CONTEXT(perl1);
perl_destruct(perl1);
FREE_THREAD_KEY;
perl_free(perl1);which is normally how things work, we get a segfault:
#0 0x40099919 in S_mess_alloc (my_perl=0x0) at util.c:832
832 if (!PL_dirty)
(gdb) bt
#0 0x40099919 in S_mess_alloc (my_perl=0x0) at util.c:832
#1 0x40099bf3 in Perl_vmess (my_perl=0x0,
pat=0x8048da8 "panic: pthread_setspecific (%d) [%s:%d]", args=0xbffff29c)
at util.c:960
#2 0x4009a459 in S_vdie_croak_common (my_perl=0x0,
pat=0x8048da8 "panic: pthread_setspecific (%d) [%s:%d]", args=0xbffff29c,
msglen=0xbffff268, utf8=0xbffff264) at util.c:1055
#3 0x4009ad19 in Perl_vcroak (my_perl=0x0,
pat=0x8048da8 "panic: pthread_setspecific (%d) [%s:%d]", args=0xbffff29c)
at util.c:1175
#4 0x4009ae80 in Perl_croak_nocontext (
pat=0x8048da8 "panic: pthread_setspecific (%d) [%s:%d]") at util.c:1196
#5 0x08048c67 in main (argc=1, argv=0xbffff384, env=0xbffff38c)
at destruct.c:49That happens because the context relies on PL_thr_key being right, and FREE_THREAD_KEY blows that. So if I manually store the values of PL_thr_key and restore those before calling PERL_SET_CONTEXT(), there is no more segfault. The following adjustment works:
/* destruct.c */ #include <EXTERN.h> #include <perl.h>
/*
* gcc -o destruct destruct.c `perl-5.8.6-ithread -MExtUtils::Embed -e ccopts -e ldopts` -Wall -g
*/
static void keys_add(int add)
{
pthread_key_t key;
int i = 0;
for (i=0; i<add; i++) {
if (pthread_key_create(&key, 0) == 0) {
fprintf(stderr, "%d\n", i+1);
}
else {
fprintf(stderr, "failed to create the key %d\n", i+1);
}
}
}int main(int argc, char **argv, char **env)
{
char *embedding[] = { "", "-e", "0" };
PerlInterpreter *perl1, *perl2;
pthread_key_t key1, key2;
dTHX; perl1 = perl_alloc();
key1 = PL_thr_key;
aTHX = perl1; PERL_SET_CONTEXT(perl1);
perl_construct(perl1);
perl_parse(perl1, NULL, 3, embedding, (char **)NULL);
Perl_warn(aTHX_ "Perl %p\n", perl1); aTHX = NULL; PL_curinterp = NULL;
perl2 = perl_alloc();
key1 = PL_thr_key;
aTHX = perl1; PERL_SET_CONTEXT(perl2);
perl_construct(perl2);
perl_parse(perl2, NULL, 3, embedding, (char **)NULL);
Perl_warn(aTHX_ "Perl %p\n", perl2); /* 2 keys added by perl_alloc */
keys_add(1023); PL_thr_key = key2;
perl_destruct(perl2);
FREE_THREAD_KEY;
perl_free(perl2); PL_thr_key = key1;
aTHX = perl1; PERL_SET_CONTEXT(perl1);
perl_destruct(perl1);
FREE_THREAD_KEY;
perl_free(perl1);exit(0); }
So again perl doesn't provide enough public API to properly juggle perl interpreters. In particular PERL_SET_CONTEXT() has a problem as the above program demonstrates.
Suggestions?
-- __________________________________________________________________ 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]
