[dancer-users] Dancer::Plugin::Auth::Extensible - possible backwards-incompatible change

Aaron Crane perl at aaroncrane.co.uk
Tue Dec 11 19:42:15 GMT 2012


David Precious <davidp at preshweb.co.uk> wrote:
> One particularly good point made is that the current implementation
> stores the attributes for a given route handler by the refaddr, which
> could be problematic if run under threads (not sure if anyone really
> does that, though).

Moreover, if the coderef is a closure, refaddr isn't stable between
compile time (when the attribute is applied) and run time (when the
closure is created).  But I believe this offers a workaround:

# Returns an arbitrary non-reference value that should be stable across all
# closures which are clones of (the same thing as) $coderef.
sub subroutine_identity {
    my $coderef = shift;
    die "Not a CODE reference\n" if ref $coderef ne 'CODE';
    my $cv = svref_2object($coderef);
    die "Not a CV\n" if !$cv->isa('B::CV');
    my $op = $cv->START;
    return $$op;
}

What's this doing?  B::svref_2object takes an arbitrary Perl
reference, and returns an instance of the appropriate B class (B::CV
in this case), representing the underlying object in the perl VM.
Then $cv->START returns (a reference to) an integer representing the
address of the first op in the subroutine.  So this extracts a stable
value that's guaranteed to refer to the underlying code rather than
any of its closures.

See also this thread on the perl-qa list:
http://www.nntp.perl.org/group/perl.qa/2012/11/msg13303.html

I haven't tried this in a threaded Perl, but it should work fine,
because, AIUI, optrees are shared across cloned threads (even for
closures created in different threads).

Personally, I do like the attribute-based API in D::P::A::E, so I'd
like to put in a plea for sticking with it.  Unless I'm wrong about
this approach working well enough, of course. :-)

-- 
Aaron Crane ** http://aaroncrane.co.uk/


More information about the dancer-users mailing list