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.
>