Can you elaborate which you think is the right interpreter?
The right interpreter, is whichever one the perl callback address originated in. That is, if your perl code--running in your main (perl.exe) thread, is the one that passes the address of a perl sub into your C code, then that is the right interpreter.
Because, whilst call code and data--perl or C--is accessible to every thread at the C level, at the Perl source level, perl relies upon segregating memory and code on a per interpreter/thread basis. It does this for both internal reasons, and for those of simplifying the use of threads by imposing this "restricted view" on the programmer. That is the raison d'etre of the iThread model.
To restate that another way; the reason Perl won't allow you to pass a coderef from one thread to another via shared memory, is because allowing you to do so would require imposing even greater performance penalties upon threads than currently. It would be necessary to apply internal locking to every perl subroutine, because they might be called concurrently on two or more threads.
The approach iThreads uses to preventing both the programmer discipline that would be required were coderefs shareable (see the :lock keyword in the 5005 threads model), and the additional internal locking that would be required, is to require each interpreter/thread to only use subroutines compiled within that interpreter.
Your use of C/XS is bypassing that protection mechanism--hence the crashes.
I just forced a PERL_SET_CONTEXT() to the interpreter created by perl.exe.... but does this surprise you?
No. By forcing the same context as was in use when the coderef was taken, you ensure that the code and data (closures etc.) behind that coderef is accessible. I would anticipate that, so long as your program remains single-threaded, that using this method to force the "correct context" for the callback will work reliably.
If you wanted to ensure multi-threaded compatibility--then you can extend this mechanism by:
- When your C/XS code receives the callback address from Perl, take a copy of the current context and save it away in a suitable place.
- Later, when the triggering event occurs, save a copy of the then current context in a local var;
- do a set_context() using the context you saved earlier;
- call the coderef.
- when the coderef returns; reset the current context.
Note: All of the above is untested--by me; and probably by anyone else--so you are the pathfinder here. I'll willingly try and help with any problems that arise, but please understand that at this point, the only test-bed I have is my brain. And that is a poor substitute for a modern processor :)
As an (interesting to me but probably not to you at this point) aside, this discussion leads to the possibility that could further reduce the overheads of the iThreads model. If coderefs explicitly carried their compile-time contexts with them, then it might be possible to allow a single copy of a Perl coderef--opcode tree--to be safely shared by multiple interpreters. But that's a thought to explore another time.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.