You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Vladimir D Belousov <ma...@klarnet.ru> on 2005/03/15 18:29:03 UTC

localized lexical varibles

Hallo all!

I'm new to mod_perl, and I see the strange behaviour of local variables 
in functions.
This is my simple test:

==
.htaccess:

SetHandler perl-script
PerlHandler My::Test;

==
package My::Test;
#/usr/local/apache/My/Test.pm

use strict;
use Apache::Constants ':common';

sub handler {
    my $r=Apache->request;
    $r->content_type('text/html');
    $r->send_http_header;
    print "Request: ".$r->uri."<br/>";
    my $s = $r->uri;
    print "From main: $s<br/>";
    Call();
   
    return OK;

    sub Call {
        print "From Call: $s<br/>";
        print "But request: ".$r->uri;
    }
   
}

1;
==

First time I got correct answer:
(request: GET /1111)
Request: /111
 From main: /111
 From Call: /111
But request: /111

But in next times I got a old $s value in the Call() function:

GET /1111/222
Request: /111/222
 From main: /111/222
 From Call: /111
But request: /111/222

GET /1234
Request: /1234
 From main: /1234
 From Call: /111
But request: /1234

Where I am wrong? Or where I can found corresponding documentation?

I beg your pardon for my english.

-- 
Vladimir D Belousov



Re: localized lexical varibles

Posted by Perrin Harkins <pe...@elem.com>.
On Tue, 2005-03-15 at 22:27 +0300, Vladimir D Belousov wrote:
> As I know, my module has been loaded only once and has been loaded by 
> the root httpd process.
> And when any httpd forks exist (prefork), let's present next situation:
> one of the existing httpd forks changes value of any variable (in my 
> example $s).
> Whether value in relation to other existing forks will change?

No.  There is no sharing of variables between mod_perl processes.

> How I understand, the apache creates the new instruction point for each 
> process  - the index to the current instruction (standart in Unix, do 
> not load the code again), but where from does it get the variables and 
> any data?

This is just standard forking stuff.  Forked processes do not share any
data.  There is something called copy-on-write that works to save memory
between forked processes, but no actual sharing of data like you're
talking about here.

- Perrin


Re: localized lexical varibles

Posted by Vladimir D Belousov <ma...@klarnet.ru>.
Michael Peters wrote:

> Vladimir D Belousov wrote:
>
>> [skipped]
>
>
> You're creating a closure with $s and $r. Check out 
> http://perl.apache.org/docs/general/perl_reference/perl_reference.html#Understanding_Closures____the_Easy_Way 
>
> to understand why this causes strange behavior.

Thank you!
I searched for the similar document, but probably again not there.

>
> You wouldn't normally notice this under normal perl since the 
> interpreter gets reloaded and your scripts get re-compiled on each 
> run. mod_perl doesn't recompile your scripts for each run thus letting 
> you see this behaviour that actually exists in perl itself.

I see. Thanks!
As I know, my module has been loaded only once and has been loaded by 
the root httpd process.
And when any httpd forks exist (prefork), let's present next situation:
one of the existing httpd forks changes value of any variable (in my 
example $s).
Whether value in relation to other existing forks will change?
How I understand, the apache creates the new instruction point for each 
process  - the index to the current instruction (standart in Unix, do 
not load the code again), but where from does it get the variables and 
any data?
A new stack? No - in this case all variables would be initialized in 
advance known (prospective) values.
Do all values shared among the existing child process? No - this is the 
chaos.
Where I wrong?

>
> The easiest/cleanest workaround is to always pass those kind of shared 
> resources to your subroutines as arguments.
>


Re: localized lexical varibles

Posted by Michael Peters <mp...@plusthree.com>.
Vladimir D Belousov wrote:
> Hallo all!
> 
> I'm new to mod_perl, and I see the strange behaviour of local variables 
> in functions.
> This is my simple test:
> 
> ==
> .htaccess:
> 
> SetHandler perl-script
> PerlHandler My::Test;
> 
> ==
> package My::Test;
> #/usr/local/apache/My/Test.pm
> 
> use strict;
> use Apache::Constants ':common';
> 
> sub handler {
>    my $r=Apache->request;
>    $r->content_type('text/html');
>    $r->send_http_header;
>    print "Request: ".$r->uri."<br/>";
>    my $s = $r->uri;
>    print "From main: $s<br/>";
>    Call();
>      return OK;
> 
>    sub Call {
>        print "From Call: $s<br/>";
>        print "But request: ".$r->uri;
>    }
>   }

You're creating a closure with $s and $r. Check out 
http://perl.apache.org/docs/general/perl_reference/perl_reference.html#Understanding_Closures____the_Easy_Way
to understand why this causes strange behavior.

You wouldn't normally notice this under normal perl since the 
interpreter gets reloaded and your scripts get re-compiled on each run. 
mod_perl doesn't recompile your scripts for each run thus letting you 
see this behaviour that actually exists in perl itself.

The easiest/cleanest workaround is to always pass those kind of shared 
resources to your subroutines as arguments.

-- 
Michael Peters
Developer
Plus Three, LP


Re: localized lexical varibles

Posted by Vladimir D Belousov <ma...@klarnet.ru>.
Michael Peters wrote:

> Vladimir D Belousov wrote:
>
>> Tom Schindl wrote:
>>
>>> Vladimir D Belousov wrote:
>>
>>
>> [skipped]
>
>
> The variables would get reinitialized if you passed them in as 
> arguments. The link that I sent you explains that once the Call sub is 
> compiled it creates a closure around the $r and $s variables so that 
> even if they are changed in other places, that closure will make sure 
> that Call never sees those changes.

I see, thanks.  Almost :(
What destiny of my closer variable changed in other process?
It will keep the value for current process? And for forked httpd process?
If yes, I cannot understand the difference between the httpd fork and 
the next request working.
Or this values is a "heritage" of the previous tasks only?

>
>> By the way, any compilation time errors are found out only at the 
>> request to the Apache.
>> But how such code Apache loads? I mean if a code has sintax errors, 
>> for example.
>> Or Apache loads code only with first client request?
>
>
> If you preload your modules in a startup.pl or by a PerlLoadModule 
> directive then apache will not start if there are syntax errors. If 
> you don't do that however, you'll have to wait until the first time 
> apache compiles the module, which is normally at request time.
>
> A good idea is to preload all of your modules and then use 
> Apache::Reload inside of the modules you are still developing.
>
> HTH
>


Re: localized lexical varibles

Posted by Michael Peters <mp...@plusthree.com>.
Vladimir D Belousov wrote:
> Tom Schindl wrote:
> 
>> Vladimir D Belousov wrote:

>> You are creating a closure here for $s here. There enough material out 
>> there go and read about closures(See Apache::Registry).
>> Why do you embed a sub into a sub?
> 
> 
> I hope this sub will be mmm... "localized subroutine"  and all varibles 
> in one will be reinitialized :)
> I now - it's nonsense :)

The variables would get reinitialized if you passed them in as 
arguments. The link that I sent you explains that once the Call sub is 
compiled it creates a closure around the $r and $s variables so that 
even if they are changed in other places, that closure will make sure 
that Call never sees those changes.

> By the way, any compilation time errors are found out only at the 
> request to the Apache.
> But how such code Apache loads? I mean if a code has sintax errors, for 
> example.
> Or Apache loads code only with first client request?

If you preload your modules in a startup.pl or by a PerlLoadModule 
directive then apache will not start if there are syntax errors. If you 
don't do that however, you'll have to wait until the first time apache 
compiles the module, which is normally at request time.

A good idea is to preload all of your modules and then use 
Apache::Reload inside of the modules you are still developing.

HTH

-- 
Michael Peters
Developer
Plus Three, LP


Re: localized lexical varibles

Posted by Vladimir D Belousov <ma...@klarnet.ru>.
Tom Schindl wrote:

> Vladimir D Belousov wrote:
>
>> [skipped]
>
>
> You are creating a closure here for $s here. There enough material out 
> there go and read about closures(See Apache::Registry).
> Why do you embed a sub into a sub?

I hope this sub will be mmm... "localized subroutine"  and all varibles 
in one will be reinitialized :)
I now - it's nonsense :)

By the way, any compilation time errors are found out only at the 
request to the Apache.
But how such code Apache loads? I mean if a code has sintax errors, for 
example.
Or Apache loads code only with first client request?

> So this is not bug but a feature :-).
> You code is buggy move the sub Call {...} outside the sub handler {} 
> and you are fine.
>
> Tom
>
>> I beg your pardon for my english.
>>


Re: localized lexical varibles

Posted by Tom Schindl <to...@gmx.at>.
Vladimir D Belousov wrote:
> Hallo all!
> 
> I'm new to mod_perl, and I see the strange behaviour of local variables 
> in functions.
> This is my simple test:
> 
> ==
> .htaccess:
> 
> SetHandler perl-script
> PerlHandler My::Test;
> 
> ==
> package My::Test;
> #/usr/local/apache/My/Test.pm
> 
> use strict;
> use Apache::Constants ':common';
> 
> sub handler {
>    my $r=Apache->request;
>    $r->content_type('text/html');
>    $r->send_http_header;
>    print "Request: ".$r->uri."<br/>";
>    my $s = $r->uri;
>    print "From main: $s<br/>";
>    Call();
>      return OK;
> 

You are creating a closure here for $s here. There enough material out 
there go and read about closures(See Apache::Registry).
Why do you embed a sub into a sub?
So this is not bug but a feature :-).
You code is buggy move the sub Call {...} outside the sub handler {} and 
you are fine.

Tom

>    sub Call {
>        print "From Call: $s<br/>";
>        print "But request: ".$r->uri;
>    }
>   }
> 
> 1;
> ==
> 
> First time I got correct answer:
> (request: GET /1111)
> Request: /111
>  From main: /111
>  From Call: /111
> But request: /111
> 
> But in next times I got a old $s value in the Call() function:
> 
> GET /1111/222
> Request: /111/222
>  From main: /111/222
>  From Call: /111
> But request: /111/222
> 
> GET /1234
> Request: /1234
>  From main: /1234
>  From Call: /111
> But request: /1234
> 
> Where I am wrong? Or where I can found corresponding documentation?
> 
> I beg your pardon for my english.
>