/* 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:49
That 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]