I've played with it some more. The following program demonstrates some of the problems I've discovered. Notice that on my OS the limit for thread keys is 1024.

/* 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]



Reply via email to