You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Steve Hay <st...@uk.radan.com> on 2004/09/21 18:24:08 UTC

BEGIN/END block problems with Win32::Shortcut under mp1

(Non-Win32 users:  The real issue here is not Win32-specific.)

I'm trying to write an mp1/Apache::Registry script on Win32 that uses 
the Win32::Shortcut module, and I find that it works fine under CGI but 
not mod_perl.

I think the problem is this:

Win32::Shortcut in an XS module.  The XS file has a BOOT: section which 
calls a Win32 API function called CoInitialize().  This is called by 
"bootstrap Win32::Shortcut;" when the module is require()'d/use()'d.  
The PM file has an END block which calls an XS routine which calls 
another Win32 API function called CoUninitialize().

Nothing else in this module works unless it is called *between* those 
calls to CoInit and CoUninit.

Under CGI, when my script starts running it runs "use Win32::Shortcut;" 
which calls CoInit, then it does whatever it has to do, then exits, 
causing the END block to be run, which calls CoUninit.  The next time 
the script is run we just do it all again:

----------
CoInit
# do stuff for request 1
CoUninit
----------
CoInit
# do stuff for request 2
CoUninit
----------
...

However, under Apache::Registry the CoInit call only gets done once 
because the module is only loaded once and thereafter gets cached, but 
the END block is still run at the end of every script run, so now we have:

----------
CoInit
# do stuff for request 1
CoUninit
----------
# do stuff for request 2
CoUninit
----------
...

You can see why request 2 doesn't work: CoUninit was called at the end 
of request 1 and CoInit hasn't been called since.

I tried placing a "use Win32::Shortcut;" line in my mp1 startup.pl 
script (and I also tried "PerlModule Win32::Shortcut" in the httpd.conf 
file instead, which I believe amounts to the same thing) to see if this 
would help, but it doesn't:

As explained in the mod_perl manpage, the END block will now only get 
run once (at server shutdown) because it was encountered during server 
startup.  I thought that this would solve the problem since now we have 
one call to CoInit at startup and one call to CoUninit at shutdown and 
neither gets called any other time, but I now find that *no* requests to 
the script work, not even the first request!

I think the reason is that the parent Apache.exe loaded the module, 
doing the CoInit call (and will later run the END block, doing the 
CoUninit too), but the child Apache.exe actually serves the request, and 
the CoInit/CoUninit calls have to be made from the same process that 
wants to be doing stuff in-between, so now the child doesn't work at all 
since it never called CoInit to start with.

The only way that I've got this working so far is to simulate what 
Apache::StatINC would do if the module was changed between every 
request:  I've deleted the loading of the module from server startup, 
and now have this in my script:

    use Win32::Shortcut;
    delete $INC{'Win32/Shortcut.pm'};
    require 'Win32/Shortcut.pm';
    ...

The use() line there gets an END block installed to be run at the end of 
every script run, while the delete()/require() calls force the bootstrap 
code to be re-run at the start of every script run.

This seems to work (so far!), but is there a more elegant way of doing this?

- Steve



------------------------------------------------
Radan Computational Ltd.

The information contained in this message and any files transmitted with it are confidential and intended for the addressee(s) only.  If you have received this message in error or there are any problems, please notify the sender immediately.  The unauthorized use, disclosure, copying or alteration of this message is strictly forbidden.  Note that any views or opinions presented in this email are solely those of the author and do not necessarily represent those of Radan Computational Ltd.  The recipient(s) of this message should check it and any attached files for viruses: Radan Computational will accept no liability for any damage caused by any virus transmitted by this email.


-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html


Re: BEGIN/END block problems with Win32::Shortcut under mp1

Posted by Perrin Harkins <pe...@elem.com>.
On Tue, 2004-09-21 at 12:24, Steve Hay wrote:
> The only way that I've got this working so far is to simulate what 
> Apache::StatINC would do if the module was changed between every 
> request:  I've deleted the loading of the module from server startup, 
> and now have this in my script:
> 
>     use Win32::Shortcut;
>     delete $INC{'Win32/Shortcut.pm'};
>     require 'Win32/Shortcut.pm';
>     ...
> 
> The use() line there gets an END block installed to be run at the end of 
> every script run, while the delete()/require() calls force the bootstrap 
> code to be re-run at the start of every script run.
> 
> This seems to work (so far!), but is there a more elegant way of doing this?

One thing you could do is change your script to a mod_perl handler. 
Then the END blocks will not get run until the server shuts down.

- Perrin


-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html


Re: BEGIN/END block problems with Win32::Shortcut under mp1

Posted by Issac Goldstand <ma...@mirimar.net>.
IMHO, your startup.pl approach is best, although I'm not sure why it would
be calling END.  In any case, you only need to use() the module once at
startup.  Most likely, in the "scripts" which are calling the functions, you
could just import() the module.  Or maybe I misunderstood.

  Issac

BTW: From a developer's standpoint, that doesn't sound like a healthy way
for the module you're using to work.  It sounds like it would be better
designed as an OO module.  To illustrate this, I recently wrote a Perl
application which needed to JavaScript parsing.  As such, I rewrote some
parts of the JAvaScript::SpiderMonkey module (I didn't like the way most of
it was written - I started helping to rewrite it, but it took to long and
eventually I had to get back to work work so I just wrote the parts I needed
in my own module, but I'm getting off track).  Getting to the point, before
I could work with any JavaScript, I also had initialization, and had to do
de-initialization.  To solve this, I made the object OO-oriented, and had it
do XS init stuff in the new() call (before being bless()ed) and de-init
stuff in DESTROY, rather than END.

----- Original Message ----- 
From: "Steve Hay" <st...@uk.radan.com>
To: <mo...@perl.apache.org>
Sent: Tuesday, September 21, 2004 7:24 PM
Subject: BEGIN/END block problems with Win32::Shortcut under mp1


> (Non-Win32 users:  The real issue here is not Win32-specific.)
>
> I'm trying to write an mp1/Apache::Registry script on Win32 that uses
> the Win32::Shortcut module, and I find that it works fine under CGI but
> not mod_perl.
>
> I think the problem is this:
>
> Win32::Shortcut in an XS module.  The XS file has a BOOT: section which
> calls a Win32 API function called CoInitialize().  This is called by
> "bootstrap Win32::Shortcut;" when the module is require()'d/use()'d.
> The PM file has an END block which calls an XS routine which calls
> another Win32 API function called CoUninitialize().
>
> Nothing else in this module works unless it is called *between* those
> calls to CoInit and CoUninit.
>
> Under CGI, when my script starts running it runs "use Win32::Shortcut;"
> which calls CoInit, then it does whatever it has to do, then exits,
> causing the END block to be run, which calls CoUninit.  The next time
> the script is run we just do it all again:
>
> ----------
> CoInit
> # do stuff for request 1
> CoUninit
> ----------
> CoInit
> # do stuff for request 2
> CoUninit
> ----------
> ...
>
> However, under Apache::Registry the CoInit call only gets done once
> because the module is only loaded once and thereafter gets cached, but
> the END block is still run at the end of every script run, so now we have:
>
> ----------
> CoInit
> # do stuff for request 1
> CoUninit
> ----------
> # do stuff for request 2
> CoUninit
> ----------
> ...
>
> You can see why request 2 doesn't work: CoUninit was called at the end
> of request 1 and CoInit hasn't been called since.
>
> I tried placing a "use Win32::Shortcut;" line in my mp1 startup.pl
> script (and I also tried "PerlModule Win32::Shortcut" in the httpd.conf
> file instead, which I believe amounts to the same thing) to see if this
> would help, but it doesn't:
>
> As explained in the mod_perl manpage, the END block will now only get
> run once (at server shutdown) because it was encountered during server
> startup.  I thought that this would solve the problem since now we have
> one call to CoInit at startup and one call to CoUninit at shutdown and
> neither gets called any other time, but I now find that *no* requests to
> the script work, not even the first request!
>
> I think the reason is that the parent Apache.exe loaded the module,
> doing the CoInit call (and will later run the END block, doing the
> CoUninit too), but the child Apache.exe actually serves the request, and
> the CoInit/CoUninit calls have to be made from the same process that
> wants to be doing stuff in-between, so now the child doesn't work at all
> since it never called CoInit to start with.
>
> The only way that I've got this working so far is to simulate what
> Apache::StatINC would do if the module was changed between every
> request:  I've deleted the loading of the module from server startup,
> and now have this in my script:
>
>     use Win32::Shortcut;
>     delete $INC{'Win32/Shortcut.pm'};
>     require 'Win32/Shortcut.pm';
>     ...
>
> The use() line there gets an END block installed to be run at the end of
> every script run, while the delete()/require() calls force the bootstrap
> code to be re-run at the start of every script run.
>
> This seems to work (so far!), but is there a more elegant way of doing
this?
>
> - Steve
>
>
>
> ------------------------------------------------
> Radan Computational Ltd.
>
> The information contained in this message and any files transmitted with
it are confidential and intended for the addressee(s) only.  If you have
received this message in error or there are any problems, please notify the
sender immediately.  The unauthorized use, disclosure, copying or alteration
of this message is strictly forbidden.  Note that any views or opinions
presented in this email are solely those of the author and do not
necessarily represent those of Radan Computational Ltd.  The recipient(s) of
this message should check it and any attached files for viruses: Radan
Computational will accept no liability for any damage caused by any virus
transmitted by this email.
>
>
> -- 
> Report problems: http://perl.apache.org/bugs/
> Mail list info: http://perl.apache.org/maillist/modperl.html
> List etiquette: http://perl.apache.org/maillist/email-etiquette.html
>


-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html


Re: BEGIN/END block problems with Win32::Shortcut under mp1

Posted by Steve Hay <st...@uk.radan.com>.
Steve Hay wrote:

>Jan Dubois wrote:
>  
>
>>The other issue you are seeing is that CoInitialize() needs to be called
>>in each *thread* that wants to make COM calls.  To do this properly, the
>>module needs to provide a CLONE method if you are using Perl threads in
>>5.8.x.
>>
>>    
>>
>That's not an issue for me with mp1 because it's single-threaded on 
>Win32.  I'll have to bear it in mind when moving to mp2, though, 'cos 
>that's multi-threaded on Win32.
>
Actually, it *is* an issue for me :(

mp1 only uses Perl in a single-threaded way on Win32, but the Apache.exe 
process itself has (by default) 50 threads which take turns to serve 
requests.  So I find (with your fixed version of Win32::Shortcut) that 
several consecutive requests all work OK, but then sometime later a 
subsequent request gets served by a different thread and it breaks 
because the CoInit wasn't done there.

Adding a CLONE method to Win32::Shortcut won't help this either because 
it's Apache threads causing the problem, not Perl threads.

So it's back to my nasty %INC hacking now.

Using mod_perl handlers is the only other suggestion so far, but it's 
not so easy in the software concerned for which I have to maintain CGI 
compatibility.

- Steve



------------------------------------------------
Radan Computational Ltd.

The information contained in this message and any files transmitted with it are confidential and intended for the addressee(s) only.  If you have received this message in error or there are any problems, please notify the sender immediately.  The unauthorized use, disclosure, copying or alteration of this message is strictly forbidden.  Note that any views or opinions presented in this email are solely those of the author and do not necessarily represent those of Radan Computational Ltd.  The recipient(s) of this message should check it and any attached files for viruses: Radan Computational will accept no liability for any damage caused by any virus transmitted by this email.


-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html


RE: BEGIN/END block problems with Win32::Shortcut under mp1

Posted by Jan Dubois <ja...@ActiveState.com>.
On Tue, 21 Sep 2004, Steve Hay wrote:
> I'm a little wary of this fix because MSDN docs say "An apartment must
> call CoUninitialize once for each successful call it has made to
> CoInitialize" and "CoUninitialize should be called on application
> shutdown", but it certainly seems to work and is less messy than what
> I was doing.

I believe the reason you should call CoUninitialize() explicitly is to
get proper cleanup of "hanging" COM objects whose reference counts
haven't been properly maintained.  Once the thread or process shuts down,
it is no longer possible to properly finalize those objects.  If
all your COM objects have been properly disposed, then you should be fine.
Win32::Shortcut doesn't maintain reference counts itself, so I wouldn't worry
about this too much.

There is also a race condition when 2 modules try to call CoUninitialize(),
e.g. Win32::Shortcut and Win32::OLE.  If Win32::Shortcut has been loaded last,
then its END block will be executed first, and the DESTROY methods of all
still existing Win32::OLE methods will fail.

Cheers,
-Jan



-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html


Re: BEGIN/END block problems with Win32::Shortcut under mp1

Posted by Steve Hay <st...@uk.radan.com>.
Jan Dubois wrote:

>On Tue, 21 Sep 2004, Steve Hay wrote:
>  
>
>>(Non-Win32 users:  The real issue here is not Win32-specific.)
>>    
>>
>
>As to Win32::Shortcut: you should just delete the END block from the module.
>I see that Sarathy already did this over a year for the version that ships
>with ActivePerl.  He also gave me his mailbox with accumulated libwin32
>patches and asked me to put out another libwin32 release to CPAN.
>Unfortunately I haven't found time to get around to it yet.
>
Oh - I looked on CPAN for a newer libwin32 or Win32::Shortcut (and even 
tried dada.perl.it), but didn't think of looking in the latest ActivePerl!

I'm a little wary of this fix because MSDN docs say "An apartment must 
call CoUninitialize once for each successful call it has made to 
CoInitialize" and "CoUninitialize should be called on application 
shutdown", but it certainly seems to work and is less messy than what I 
was doing.

>
>The other issue you are seeing is that CoInitialize() needs to be called
>in each *thread* that wants to make COM calls.  To do this properly, the
>module needs to provide a CLONE method if you are using Perl threads in
>5.8.x.
>
That's not an issue for me with mp1 because it's single-threaded on 
Win32.  I'll have to bear it in mind when moving to mp2, though, 'cos 
that's multi-threaded on Win32.

>
>I have no clue how all this relates to MP1; it is just the subject line that
>made me take a brief peek at this message.
>
Thanks for the tip.

It's interesting to note that the purveyors of PerlEx watch this list :) ...

- Steve



------------------------------------------------
Radan Computational Ltd.

The information contained in this message and any files transmitted with it are confidential and intended for the addressee(s) only.  If you have received this message in error or there are any problems, please notify the sender immediately.  The unauthorized use, disclosure, copying or alteration of this message is strictly forbidden.  Note that any views or opinions presented in this email are solely those of the author and do not necessarily represent those of Radan Computational Ltd.  The recipient(s) of this message should check it and any attached files for viruses: Radan Computational will accept no liability for any damage caused by any virus transmitted by this email.


-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html


RE: BEGIN/END block problems with Win32::Shortcut under mp1

Posted by Jan Dubois <ja...@ActiveState.com>.
On Tue, 21 Sep 2004, Steve Hay wrote:
> (Non-Win32 users:  The real issue here is not Win32-specific.)

As to Win32::Shortcut: you should just delete the END block from the module.
I see that Sarathy already did this over a year for the version that ships
with ActivePerl.  He also gave me his mailbox with accumulated libwin32
patches and asked me to put out another libwin32 release to CPAN.
Unfortunately I haven't found time to get around to it yet.

The other issue you are seeing is that CoInitialize() needs to be called
in each *thread* that wants to make COM calls.  To do this properly, the
module needs to provide a CLONE method if you are using Perl threads in
5.8.x.

I have no clue how all this relates to MP1; it is just the subject line that
made me take a brief peek at this message.

Cheers,
-Jan



-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html