You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by mgraham <mg...@toronto.circadence.com> on 2000/07/31 02:58:23 UTC

Package Lexicals and PerlModule

I'm experiencing a strange variable scope issue.

Normally, I expect that lexical 'my' vars declared at the package
scope (i.e. at the top of a file), should be visible to subroutines
declared in the same package, and should maintain their values between
calls to those subroutines.

Under mod_perl, I find inconsistent behaviour.  It works fine when a
module is loaded via the PerlModule directive in httpd.conf.  However
when a module is loaded via startup.pl, the package lexicals "forget"
their values between calls.

    # Foo.pm
    package Foo;
    use strict;

    my $PACKAGE_LEXICAL;

    warn "I'm being loaded";

    sub load_var {
        my $param = shift;

        $PACKAGE_LEXICAL = $param if $param;

        warn "PACKAGE_LEXICAL: $PACKAGE_LEXICAL\n";
    }
    1;

    # startup.pl

    use Foo;
    Foo::load_var('wubba');


With the above I expect to be able to call the following in some
handler:

    Foo::load_var()

...and $PACKAGE_LEXICAL should still be 'wubba'.

The strange thing is that this works when Foo is required in
httpd.conf via a "PerlModule Foo" directive.  But when Foo is pulled
in via a "use Foo" in startup.pl, $PACKAGE_LEXICAL does not keep it's
value.

In both cases, Foo.pm gets loaded twice at startup, (there are two
"I'm being loaded messages" in the logs which I'm assuming this is
because PerlFreshRestart is On by default).  Also in both cases,
Foo.pm is being loaded by uid 0, so I'm assuming this is not a
parent/child sharing problem.

Can anybody see what I'm missing?

The Eagle book suggests that it's best to load modules from startup.pl
rather than httpd.conf.  Is this not such a good idea after all?

Michael





Re: Package Lexicals and PerlModule

Posted by Perrin Harkins <pe...@primenet.com>.
On Fri, 4 Aug 2000, darren chamberlain wrote:
> Sharing a variable among children is difficult; you need to use IPC::Sharable
> or something similar.

Not if it's read-only after the fork, which this one appears to be.  You
can load it with a value at startup and it will be shared.

- Perrin


Re: Package Lexicals and PerlModule

Posted by darren chamberlain <da...@boston.com>.
mgraham (mgraham@toronto.circadence.com) said something to this effect:
> That's a neat trick!  However, for my purposes, I don't want each
> child to have a separate $PACKAGE_LEXICAL.  I want to set the variable
> with the parent process (actually from setup.pl) and I want children
> to be able to call the sub without any parameters.  And I want the
> variable to be visible to subs in the same package, but not to code
> outside the package.  It's kind of like a class variable without
> objects.

Sharing a variable among children is difficult; you need to use IPC::Sharable
or something similar. There is an example in the Apache::Session perldocs of
using a "session" to store global data that gets shared among the children
as well.

The problem with sharing stuff between the parent and children, if I
understand it correctly, is that once a child forks, it has a copy of the
variable, not a reference to it. So, modifications to this copy affect that
child only.

I've never gotten the shm version to work, but I have gotten the
Apache::Session version to work. This is straight from the perldoc:

    use Apache;
    use Apache::Session::File;
    use DBI;

    use strict;

    my %global_data;

    eval {
        tie %global_data, 'Apache::Session::File', 1,
           {Directory => '/tmp/sessiondata'};
    };
    if ($@) {
       die "Global data is not accessible: $@";
    }

    my $dbh = DBI->connect($global_data{datasource},
       $global_data{username}, $global_data{password}) || die $DBI::errstr;

    undef %global_data;

    #program continues...

Pretty useful stuff.

(darren)

-- 
I'd rather have my own game show than enough votes to become president.

RE: Package Lexicals and PerlModule

Posted by mgraham <mg...@toronto.circadence.com>.

darren chamberlain wrote:
> ...Except that by calling Foo:load_var() you are setting
> $PACKAGE_LEXICAL
> to undef (by passing in an empty list via ()), rather than
> retrieving it.

Well, actually, I was checking to see if it was set first:

    sub load_var {
        my $param = shift;
        $PACKAGE_LEXICAL = $param if $param;
    }

Your example does essentially the same thing, but is interesting
because it puts the sub and the lexical variable in a nested block
scope, and as you say:

> Each child will have its own $PACKAGE_LEXICAL.

That's a neat trick!  However, for my purposes, I don't want each
child to have a separate $PACKAGE_LEXICAL.  I want to set the variable
with the parent process (actually from setup.pl) and I want children
to be able to call the sub without any parameters.  And I want the
variable to be visible to subs in the same package, but not to code
outside the package.  It's kind of like a class variable without
objects.  Maybe it would be clearer with two subs:

    package Foo;
    my $PACKAGE_LEXICAL;
    sub set_var {
        $PACKAGE_LEXICAL = shift;
    }
    sub do_stuff {
        # do something with $PACKAGE_LEXICAL;
    }

I want to be able to call Foo::set_var('wubba') from startup.pl, and
then call Foo::do_stuff() from some child process.

The weird thing is, this works as I expect when I put "PerlModule Foo"
in httpd.conf, but not when I put "use Foo;" in startup.pl.

Does everybody else use PerlModule to pull in their modules, or
startup.pl?

Michael



Re: Package Lexicals and PerlModule

Posted by darren chamberlain <da...@boston.com>.
mgraham (mgraham@toronto.circadence.com) said something to this effect:
> With the above I expect to be able to call the following in some
> handler:
> 
>     Foo::load_var()
> 
> ...and $PACKAGE_LEXICAL should still be 'wubba'.

...Except that by calling Foo:load_var() you are setting $PACKAGE_LEXICAL
to undef (by passing in an empty list via ()), rather than retrieving it.
You should do something like:

package Foo;

{ # Block scope this stuff just to ensure that no other subroutine besides
  # var can modify $PACKAGE_LEXICAL.
    my $PACKAGE_LEXICAL;
    sub var {
        return
          (@_)
            ? $PACKAGE_LEXICAL = shift
            : $PACKAGE_LEXICAL;
    }
}

# More of package Foo here...
1;

This will set $PACKAGE_LEXICAL if you pass something in, and return it, or
just return it otherwise.  Each child will have its own $PACKAGE_LEXICAL.

(darren)

-- 
All things are possible, except for skiing through a revolving door.

RE: Package Lexicals and PerlModule

Posted by Vivek Khera <kh...@kciLink.com>.
>>>>> "PH" == Perrin Harkins <pe...@primenet.com> writes:

PH> On Fri, 4 Aug 2000, mgraham wrote:
>> Why should PerlFreshRestart be on, anyway?  Ostensibly, it's so you
>> can make sure that your modules can survive a soft restart, but can't
>> you also gather that from 'apachectl graceful'?

PH> With PerlFreshRestart turned off, a graceful restart will not reload
PH> changed code.  You have to do a full stop/start to pick up changes.

Unless you are using mod_perl as a DSO in which case PerlFreshRestart
is irrelevent -- it is always freshly started.

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Vivek Khera, Ph.D.                Khera Communications, Inc.
Internet: khera@kciLink.com       Rockville, MD       +1-301-545-6996
GPG & MIME spoken here            http://www.khera.org/~vivek/

RE: Package Lexicals and PerlModule

Posted by Perrin Harkins <pe...@primenet.com>.
On Fri, 4 Aug 2000, mgraham wrote:
> Why should PerlFreshRestart be on, anyway?  Ostensibly, it's so you
> can make sure that your modules can survive a soft restart, but can't
> you also gather that from 'apachectl graceful'?

With PerlFreshRestart turned off, a graceful restart will not reload
changed code.  You have to do a full stop/start to pick up changes.

- Perrin


RE: Package Lexicals and PerlModule

Posted by mgraham <mg...@toronto.circadence.com>.


Perrin Harkins wrote:
> This sounds like a bad interaction with PerlFreshRestart and closure
> variables.  Does it work if you turn off PerlFreshRestart?
> Can you live
> with that?

Yes!  It works with PerlFreshRestart Off.  I think you're right - it
probably has something to do with the timing of when various bits get
compiled and executed.

> By the way, PerlFreshRestart is not supposed to be on by default,
but
> using mod_perl compiled as DSO causes similar behavior in
> recent versions
> (1.22 on).

I had it turned on for some reason.  Why should PerlFreshRestart be
on, anyway?  Ostensibly, it's so you can make sure that your modules
can survive a soft restart, but can't you also gather that from
'apachectl graceful'?

Michael



Re: Package Lexicals and PerlModule

Posted by Perrin Harkins <pe...@primenet.com>.
On Sun, 30 Jul 2000, mgraham wrote:
> Under mod_perl, I find inconsistent behaviour.  It works fine when a
> module is loaded via the PerlModule directive in httpd.conf.  However
> when a module is loaded via startup.pl, the package lexicals "forget"
> their values between calls.
[...]
> The strange thing is that this works when Foo is required in
> httpd.conf via a "PerlModule Foo" directive.  But when Foo is pulled
> in via a "use Foo" in startup.pl, $PACKAGE_LEXICAL does not keep it's
> value.

This sounds like a bad interaction with PerlFreshRestart and closure
variables.  Does it work if you turn off PerlFreshRestart?  Can you live
with that?

By the way, PerlFreshRestart is not supposed to be on by default, but
using mod_perl compiled as DSO causes similar behavior in recent versions
(1.22 on).

- Perrin


Re: Package Lexicals and PerlModule

Posted by Philip Mak <pm...@aaanime.net>.
On Sun, 30 Jul 2000, mgraham wrote:

> Normally, I expect that lexical 'my' vars declared at the package
> scope (i.e. at the top of a file), should be visible to subroutines
> declared in the same package, and should maintain their values between
> calls to those subroutines.

If you are running perl v5.6 or later, I think you can use "our" instead
of "my" and it will do what you want it to do.

As for why it acts this way, I'm not sure...perhaps someone else on this
mailing list can shed some light on this issue.

-Philip Mak (pmak@aaanime.net)