It turns out that using `->symbol and some other minor magic can be used to solve all of the problems I've been concerned about. I've run some simple tests that show two different threads with independent module/program paths that seem to be (almost) completely isolated from each other. The only code they share with each other is the standard set of static modules (which is an acceptable situation that could also be changed).
I'll need to test this quite a bit, but the initial results are encouraging.
Bill
On Mar 14, 2012, at 1:01 PM, Bill Welliver wrote:
Yes, I think it will have to be something a bit more involved.
My original plan was to override all of the functions that are in play here (all of the methods defined in CompilationHandler, plus a number of others) so that they use the appropriate data.
However, as I think about this, perhaps the answer is even simpler:
The problem isn't strictly the methods themselves, it's more a matter of making them use the right set of data. Therefore, would it not be just as effective to implement getters/setters on the appropriate datasources:
class ResolutionEnvironment { array pike_module_path = ({}); array pike_include_path = ({}); mapping objects; // etc... }
mapping(Pike.Thread|string:ResolutionEvironment) _multitenant_threads = (["default": ResolutionEvironment()]);
`->pike_module_path() { array x; // do we have a special environment for this thread? if(x = _multitenant_threads[Thread.this_thread()]) { return x->pike_module_path; } // otherwise return the global environment else return _multitentant_threads["default"]->pike_module_path; }
My understanding is that the getter/setters operate at a lower level than standard `->(), so it's impossible to avoid them being called, which is desirable in this case.
Of course, this is all in addition to the necessary machinery to register a given configuration with one or more threads.
Bill