Ticket #833 (closed bug: fixed)
Exception from :init sub in PIR compreg causes problems
|Reported by:||whiteknight||Owned by:||whiteknight|
Actually, this is just one more example of the inferior runloops problem, although pmichaud++ has been able to narrow it down to a pure-PIR test case:
.sub main $S0 = <<'END' .sub 'abc' :load :init say 'run abc' .end .sub 'def' :load :init die 'died in def' .end .sub 'ghi' :load :init say 'run ghi' .end .sub 'main' :main say 'run main' .end END $P0 = compreg 'PIR' push_eh trap1 $P0($S0) trap1: pop_eh push_eh trap2 $P0($S0) trap2: pop_eh .end
What happens, in a nutshell, is this: The :init functions from the compiled code string are executed immediately in an child runloop. function 'def' throws an exception which is handled by a handler from outside the compiled code string. Execution continues in the child runloop until the end of the program. Once that terminates, the C stack is unwound back up to the parent runloop and execution continues, but now with a corrupted context.
This isn't just a problem with IMCC, although the problem does manifest inside IMCC in this case. It's a problem any time we mix child runloops with exceptions.
We now know what causes this problem, and there are a handful of examples of manifestations of it throughout the Trac and RT ticket queues by various names. Resolving this issue won't be difficult if we can agree on a sane way to do it.
Here's my proposal, which could easily be made to work for this particular case but would require more planning and implementation effort to make it work for the larger class of all related failures: Instead of executing the :init functions in a new runloop from IMCC, we add them to the scheduler and schedule them to execute in the parent runloop after IMCC returns (in this case, directly after the invokecc opcode on the PIR compreg). In this way we integrate this better with the scheduler and prevent ever creating a child runloop, which prevents problems from multi-runloop interaction.
This type of solution could also be extended to almost every other case where a child runloop is created such as in vtable overrides for Object PMC instead of calling the override directly, we add it to the scheduler and execute some sort of continuation that takes us into the override and then returns to the point in the parent control flow where the vtable was called). Again, more details needed to be worked out for this idea to become a reality.
Once we decide how we want to resolve this problem (and there are other options besides the one I mention here), it should be straight-forward to resolve it. I would like to hear ideas from people so we can start planning a path forward.