Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Module['onRuntimeInitializeFailed'] #5357

Merged
merged 9 commits into from
Jul 6, 2017

Conversation

buu700
Copy link
Contributor

@buu700 buu700 commented Jul 3, 2017

As discussed in #5338.

src/preamble.js Outdated
@@ -2509,7 +2509,7 @@ function integrateWasmJS(Module) {
} else if (curr === 'interpret-asm2wasm' || curr === 'interpret-s-expr' || curr === 'interpret-binary') {
if (exports = doWasmPolyfill(global, env, providedBuffer, curr)) break;
} else {
throw 'bad method: ' + curr;
Module['quit'](1, 'bad method: ' + curr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think calling quit here is not the best thing. quit is the lowest layer here, and by calling it, you are forced to add logic into shell.js which is higher than it should be. Instead, how about calling abort here, and in abort (in postamble.js), checking if onRuntimeInitializeFailed exists and if so, call it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thanks; just took care of this in a force push over the original commit.

@kripken
Copy link
Member

kripken commented Jul 3, 2017

This will also need testing. Perhaps add other.test_runtime_initialize_failed, in which we cause init to fail somehow (e.g., maybe delete the wasm file before running the code?)

@buu700 buu700 force-pushed the onruntimeinitializefailed branch from 4cf6fe1 to 8030e3b Compare July 3, 2017 23:03
src/postamble.js Outdated
@@ -316,6 +316,10 @@ Module['exit'] = Module.exit = exit;
var abortDecorators = [];

function abort(what) {
if (Module['onRuntimeInitializeFailed']) {
setTimeout(function () { Module['onRuntimeInitializeFailed'](what); }, 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is there a setTimeout here? it needs an explanation, but also I don't think it's needed, unless I'm missing something?

Copy link
Contributor Author

@buu700 buu700 Jul 3, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably not really needed; I can either remove it or add a comment depending on your preference. The reason I put it in a setTimeout was to avoid having an exception in the callback interfere with the rest of abort or anything else that may come afterwards (just being conservative and erring on the side of not changing existing behavior).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, let's take it out then, I think it adds unnecessary complexity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, done.

src/postamble.js Outdated
@@ -316,6 +316,10 @@ Module['exit'] = Module.exit = exit;
var abortDecorators = [];

function abort(what) {
if (Module['onRuntimeInitializeFailed']) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we want this callback to be just for runtime initialization failures, then we should erase Module['onRuntimeInitializeFailed'] after initialization succeeds (so aborts later on don't cause it to be called).

alternatively, if you want a general callback when the problem aborts for any reason, including after initialization, then we should rename this. (or, perhaps we should just recommend people set Module.abort to this callback? right now we'd override that, but we could change that)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, good catch; just took care of this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder though if we shouldn't add onAbort instead of this. Would it handle your use case? If so, then since it handles more use cases too, and avoids the complexity of needing to unset onRuntimeInitializeFailed, it seems superior.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, yeah, I wouldn't have any problem with that. As long as keeping my change of calling abort in the WebAssembly.instantiate catch isn't an issue, it'd be practically the same for my purposes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think that change is more correct regardless - we should call abort when forced to abort execution. (It's more important after execution starts, since abort makes sure we stop running events afterwards; but it's better for consistency to do it in all places.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect, makes sense to me. Just pushed a commit that changes this to onAbort.

@buu700 buu700 force-pushed the onruntimeinitializefailed branch from 45f488e to c3f533d Compare July 3, 2017 23:45
buu700 added a commit to buu700/emscripten that referenced this pull request Jul 3, 2017
@buu700 buu700 force-pushed the onruntimeinitializefailed branch from c3f533d to 1f73bb5 Compare July 3, 2017 23:54
buu700 added a commit to buu700/emscripten that referenced this pull request Jul 5, 2017
@buu700 buu700 force-pushed the onruntimeinitializefailed branch from 9c11d41 to 47875d6 Compare July 5, 2017 21:44

expectedOutput = "Module['onAbort'] was called"

os.remove('a.out.wasm')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a comment on this line, about it making startup fail

f.write("Module['onAbort'] = function () { console.log('%s') }" % expectedOutput)
f.close()

devnull = open(os.devnull, 'w')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we remove the devnull parts? it's out if stderr is logged to the console as the test runs (easier to debug, when necessary)

@kripken
Copy link
Member

kripken commented Jul 5, 2017

Nice, lgtm with those test changes. Also, we need you in AUTHORS to merge (which I think is in your other PR, but not merged yet, so perhaps add it here if you want this merged earlier).

buu700 added a commit to buu700/emscripten that referenced this pull request Jul 5, 2017
buu700 added a commit to buu700/emscripten that referenced this pull request Jul 5, 2017
@buu700
Copy link
Contributor Author

buu700 commented Jul 5, 2017

Nice, thanks! Just pushed those test changes and the AUTHORS update.

@buu700 buu700 force-pushed the onruntimeinitializefailed branch from e42bc90 to c36e4d7 Compare July 5, 2017 22:09
@kripken
Copy link
Member

kripken commented Jul 5, 2017

Does the test pass for you? I get

Module['onAbort'] = function () { console.log('Module['onAbort'] was called') }
                                              ^^^^^^^^^

SyntaxError: missing ) after argument list

I think you need to change one set of quotation marks there to double-quotes.

@buu700
Copy link
Contributor Author

buu700 commented Jul 5, 2017

Oops, sorry about that. I'll fix it and confirm that it passes before pushing again.

@kripken
Copy link
Member

kripken commented Jul 5, 2017

Another concern I just realized is that your test assumes the default js engine used by run_js has wasm support. That's typically node.js, and it doesn't have wasm support unless it's very recent. Running with BINARYEN_METHOD="interpret-binary" would be better, as the interpreter is guaranteed to work.

@buu700
Copy link
Contributor Author

buu700 commented Jul 5, 2017

Got it, thanks; I'll fix that too.

@buu700
Copy link
Contributor Author

buu700 commented Jul 6, 2017

How should callbacks like onAbort and onRuntimeInitialized be defined when the loading method is synchronous? The test worked with native-wasm because it got to Module['onAbort'] = ... before abort was actually called, but that isn't the case with interpret-binary.

@kripken
Copy link
Member

kripken commented Jul 6, 2017

Synchronous loading of wasm should abort if the wasm binary is not present (i.e. I don't think it being synchronous or asynchronous should make a difference in error handling). If that's not currently an abort, then it might need to be turned into one.

Should be easy, I think. If not, maybe there's another way to test this. Another option which is more work would be to add infrastructure in the test harness to check which js engine(s) have wasm support, then use that engine (or skip) in this test. We need that anyhow, and I could look into doing it soon if it would help here.

@buu700
Copy link
Contributor Author

buu700 commented Jul 6, 2017

It is aborting if synchronous loading/compilation fails, but the issue is that I don't know how my onAbort callback is meant to be correctly attached to Module in that case.

Right now, I'm just appending Module['onAbort'] = ... to the end of the file, which never gets executed because the call to abort happens before that line is ever reached.

@kripken
Copy link
Member

kripken commented Jul 6, 2017

Oh, ok. Then you should define the Module before the program, instead of at the end, prepend something like

var Module = {
  onAbort: ..
};

@buu700
Copy link
Contributor Author

buu700 commented Jul 6, 2017

Ah, thanks. I'd actually tried that and it didn't seem to work, but maybe something else was causing the test to fail; I'll unstash it and try again.

@buu700
Copy link
Contributor Author

buu700 commented Jul 6, 2017

Okay, so the issue I had before was that it was asserting a return code of 0 by default. After disabling that, now the issue is that it's returning no output for some reason (Exception: Expected to find 'Module.onAbort was called' in ''). Any ideas?

This is what the test currently looks like:

  def test_on_abort(self):
    cmd = [PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-s', 'WASM=1', '-s', 'BINARYEN_METHOD="interpret-binary"']

    self.clear()
    proc = Popen(cmd, stdout=PIPE, stderr=PIPE)
    output, err = proc.communicate()

    expectedOutput = 'Module.onAbort was called'

    # trigger onAbort by intentionally causing startup to fail
    os.remove('a.out.wasm')

    f = open('a.out.js', 'r')
    js = f.read()
    f.close()
    f = open('a.out.js', 'w')
    f.write("var Module = {onAbort: function() { console.log('%s') }};\n" % expectedOutput)
    f.write(js)
    f.close()

    self.assertContained(expectedOutput, run_js('a.out.js', assert_returncode=None))

@kripken
Copy link
Member

kripken commented Jul 6, 2017

Is anything printed to the console through stderr? Maybe it's throwing an error before it reaches your code. You should see it printed in your console, or could tell run_js to redirect stderr to stdout (something like stderr=subprocess.stdout).

@buu700
Copy link
Contributor Author

buu700 commented Jul 6, 2017

Thanks! That was it. Apparently I'd misremembered the "bad method" abortion as a synchronous compilation abortion. Added an try/catch to abort in getBinary and now the test is passing.

@kripken
Copy link
Member

kripken commented Jul 6, 2017

Looks good, thanks!

@kripken kripken merged commit 8404d94 into emscripten-core:incoming Jul 6, 2017
@buu700 buu700 deleted the onruntimeinitializefailed branch July 6, 2017 05:16
@dschuff
Copy link
Member

dschuff commented Jul 6, 2017

This is nice, can we update the emscripten docs as well?

@kripken
Copy link
Member

kripken commented Jul 6, 2017

I'll do that, I have some other followups here as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants