Your skill will accomplish what the force of many cannot |
|
PerlMonks |
Re: Tkx after coderef problemby huck (Prior) |
on Jun 03, 2018 at 21:09 UTC ( [id://1215797]=note: print w/replies, xml ) | Need Help?? |
Ok, i think i know what is going wrong At https://github.com/gisle/tcl.pm/blob/master/Tcl.pm line 553 you find Notice that line 551-552 notes plan deleting that entry, hence Tcl command during Tcl::Code::DESTROY TODO - this +1000 is wrong... should and at line 635 we find delete $anon_refs{$k};. That is what destroys the "majic" needed to call that perl code. To backtrack a little, at https://st.aticpan.org/source/SREZIC/Tk-804.034/demos/timer i found a simple timer in Tk. after some heavy handed munging to Tkx i got Running that, then pressing start caused the "invalid command name "::perl::CODE" error too. Ahah, something else fails too! pressing stop , then start again makes it fail again. doing this a few times i noticed that every time the error came after 1.05 seconds of "timer on" status. So i modified my code to have a constant rather than random delay time. And lo and behold the failures became regular, The failure occurs 1 second after the first call to Tkx::After with the scalar coderef. one second became interesting so i modifed my test code and added then added after_dump(); to the end of accept_out_cclose_after. Thats when i noticed lines like Thats what gave me to clue(_code_dispose) to find out where the argument processing was for Tcl calls from perl, and i found that 1 second after the my Tkx::after call terminates _code_dispose was destroying the majic that allowed it to call that perl subroutine coderef, even though that coderef was a "static scalar". See at 464, $args[$argcnt] = $interp->create_tcl_sub($arg, undef, undef, $current_r); the second undef is a non-defined $tclname, at 605-608 it stringifys the coderef as $tclname = "::perl::$sub"; then at 611 it registers that $tclname as a tcl interpreter command via $interp->CreateCommand($tclname, $sub, undef, undef, 1); and then at 620 blesses that $tclname as a Tcl::Code in $anon_refs. Then at 545 the code is called my $id = $interp->icall(@args);, then at 549 a composite $anon_refs is made of all the $anon_refs for that call $anon_refs{"$interp;$id"} = \@codes; then at 553 that composite is scheduled for deletion in 1 second $interp->invoke('after',$args[1]+1000, "perl::Eval {Tcl::_code_dispose('$interp;$id')}"); ok so far. but then when the composite deletion is activated all its parts are Tcl::Code objects so they go thru the DESTROY at 652-658. now each time create_tcl_sub ran it made a new Tcl::Code object, but the first element to that object is a reference to the $sub coderef, the same $sub coderef that i will be calling again. BUT DESTROY uses that ref to $sub-coderef to create a $tclname my $tclname = "::perl::$$rsub"; that is then unregistered as a tcl command via $interp->DeleteCommand($tclname) SO once the first after has run to delete the composite list of tcl_coderefs (@codes) my sub gets unregistered, and can no longer be called again by after until l i run Tkx::after again. But i have an after event pending and i wont run Tkx::after again until it triggers, and when it does trigger Tcl is unable to process its coderef because it has been unregistered. I kinda have a clue how to fix this, but ive been digging around so much me brain is all jumbled right now. as for why it worked in win but not ubuntu my windows has $Tcl::VERSION = '1.02'; which was installed when i installed 5.20, but ubuntu 14.04/16.04/18.04 has $Tcl::VERSION = '1.05'; installed just a few days ago. I suspected the version were different, but still wanted to understand why it failed.
In Section
Seekers of Perl Wisdom
|
|