perl-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Stas Bekman <s...@stason.org>
Subject Re: [PATCH] libperl leaks a THREAD_KEY each time it is reloaded
Date Mon, 10 Jan 2005 17:50:23 GMT
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:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org


Mime
View raw message