[e-lang] propUtils#testProp/2: not synchronously callable
Thomas Leonard
talex5 at gmail.com
Wed Dec 30 06:16:27 PST 2009
2009/12/29 Thomas Leonard <talex5 at gmail.com>:
[...]
> After adding some more information to the error message, it seems that
> __matchBind is sometimes only a promise. The error message can be made
> easily reproducible by adding a delay to the top of
> elang/expand/__matchBind.emaker
[...]
> I thought the problem might be in LazyEvalSlot, which is used to get
> the value of __matchBind when needed. A comment in the code says:
>
> synchronized (myLock) {
> // If it's asked for while it's doing its own evaluation, it
> // returns a promise for what it'll evaluate to.
> myOptValue = promise[0];
> myOptScope = null;
> myOptSource = null;
> }
>
> However, making the whole method synchronised didn't help. I also
> thought it might be something to do with ImportLoader, which does a
> similar trick, but I can't see why either of these would be shared
> between threads; ScopeSetup seems to make a new ImportLoader in
> privileged/7. Why are they "synchronized"?
To answer my own question: lazy slots and import loaders are shared
between threads when using Vat.seed(rec). Its comment says:
* This is safe only when all the mutable
* state transitively reachable from <tt>rec</tt> is no longer reachable
* from any other vat (typically, not from the current vat -- the vat of
* origin), or that any possibly shared mutable state is managed in a
* conventionally thread-safe manner.
eLauncherAuthor.emaker does this:
def parseFunc :rcvr := parserVat.seed(fn{
def input := if (fname =~ `-` || fname.startsWith("-.")) {
auths["metain"]
} else {
def <file> := auths["file__uriGetter"]
<file>[fname].textReader()
}
def optPromptOut := if (isInteractive) {
auths["metaout"]
} else {
null
}
def lineFeeder := auths["makeFileFeeder"](fname,
input,
optPromptOut)
makeParseFunc(lineFeeder, props, auths["metaerr"])
})
I don't understand how this is supposed to work. The function uses the
start thread's scope to look up __matchBind (for the =~), which isn't
safe because it will cause this to resolve to a promise briefly if the
start thread tries to load it too (using their shared LazyEvalSlot).
However, even if this were fixed, the code is still using a number of
objects from the start thread, including some passed as arguments. It
seems unlikely that these are all thread-safe (given that importing
any E code or using many things in safeScope is unsafe).
Perhaps it should use seedVatAuthor instead, and hard-code the
required objects (makeFileFeeder, makeELexer, etc) rather than taking
them as inputs?
Could someone explain how this is intended to work? I'm hoping to make
a package of the current svn version of E, but I need a version that
compiles and runs reliably first. I'm thinking of just doing the
parsing and repl in the start thread, as a workaround to avoid these
issues; is that sensible?
Thanks,
--
Dr Thomas Leonard ROX desktop / Zero Install
GPG: 9242 9807 C985 3C07 44A6 8B9A AE07 8280 59A5 3CC1
More information about the e-lang
mailing list