Re: propUtils#testProp/2: not synchronously callable
Thomas Leonard <[email protected]>
| Newsgroups | gmane.comp.lang.e.general |
|---|---|
| Message-ID | <[email protected]> |
2009/12/29 Thomas Leonard <[email protected]>: [...] > 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