Weirdness with Perl callbacks

Russ Allbery rra at stanford.edu
Mon Nov 29 02:40:00 UTC 1999


Jeremy <jeremy at exit109.com> writes:

> Recently I installed INN on my workstation, mostly to test Cleanfeed.
> In testing, I've found something strange with the callbacks.

> I've implemented persistent, saved-to-disk EMP histories that can
> survive a server restart.  So, when the filter starts up, and when it's
> unthrottled, if persistence is wanted and there is data on the disk, I
> load it up.  Then, I do this:

>     if ($SERVER eq 'inn' and defined($INN::{syslog})) {
>         INN::syslog('N', 'Restored EMP database.');
>     }

> At startup time, this results in:

> Nov 27 15:09:34 hideout.gunslinger.net innd: SERVER perl loading
>  /usr/local/news/bin/filter/filter_innd.pl failed: Undefined subroutine
>  &INN::syslog called at /usr/local/news/bin/filter/filter_innd.pl line 2120.

What version of INN are you using?

There's an interesting ordering and timing problem involved in building
the Perl intepretor.  In INN 2.2, the only callbacks initialized before
the loading of the filter code are the DynaLoader ones, so you can't use
any INN callbacks in code that's executed at load time.  Recently in INN
2.3 I moved the syslog callback into the core filtering code (since it's
usable in both innd and nnrpd) and it's therefore initialized before the
loading of any filter code.  So the above should now work fine in INN 2.3
if I understand how this works right.

Second, you're testing whether the syslog element of the %INN:: hash is
defined at run-time, but Perl is going to try to compile the subroutine
call at compile time.  So your check is too late; Perl will try to compile
the call whether the sub is defined or not.  You need to defer the call
until run-time.  Try:

    if ($SERVER eq 'inn' and defined($INN::{syslog})) {
        &INN::syslog('N', 'Restored EMP database.');
    }

instead and see if that works better.  My guess is that your original code
wouldn't have worked with any non-INN server either.

I'm also not sure you're checking what you want to check with that defined
call; I'd tend to try calling defined on &INN::syslog instead.  Right now,
you'll find that defined call will return true if you (or something else)
have assigned to $INN::syslog, even if no &INN::syslog() sub is defined.

I still need to dig into the guts of lib/perl.c and redo how it does a lot
of things, since right now it's rather odd.  (The person who wrote it
originally apparently didn't know about perl_eval_pv(), for example.)
I'll try to get all of the callbacks defined before any filter code is
loaded when I do that.

-- 
Russ Allbery (rra at stanford.edu)         <URL:http://www.eyrie.org/~eagle/>


More information about the inn-workers mailing list