aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2013-08-09 13:03:37 -0700
committerAlon Zakai <alonzakai@gmail.com>2013-08-09 13:03:37 -0700
commit64b7b12a0496e474f1bcb34a947781dcd4cc0560 (patch)
tree18d9fc6d2faf9ed0d6598c643faef70d4f57ef23
parent4776303a18c49351ce151103629d32dca8949fb1 (diff)
parent39cf1e36ab14c621f1e446010afbec21a8b10dbb (diff)
Merge pull request #1489 from inolen/exit_status_fixes
exit status fixes
-rw-r--r--src/postamble.js61
-rw-r--r--src/preamble.js1
-rwxr-xr-xtests/runner.py30
3 files changed, 58 insertions, 34 deletions
diff --git a/src/postamble.js b/src/postamble.js
index 25a50bfc..c4ca3aae 100644
--- a/src/postamble.js
+++ b/src/postamble.js
@@ -1,8 +1,15 @@
// === Auto-generated postamble setup entry stuff ===
+function ExitStatus(status) {
+ this.name = "ExitStatus";
+ this.message = "Program terminated with exit(" + status + ")";
+ this.status = status;
+};
+ExitStatus.prototype = new Error();
+ExitStatus.prototype.constructor = ExitStatus;
+
var initialStackTop;
-var inMain;
Module['callMain'] = Module.callMain = function callMain(args) {
assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on __ATMAIN__)');
@@ -27,40 +34,36 @@ Module['callMain'] = Module.callMain = function callMain(args) {
argv.push(0);
argv = allocate(argv, 'i32', ALLOC_NORMAL);
+ initialStackTop = STACKTOP;
+
+ try {
#if BENCHMARK
- var start = Date.now();
+ var start = Date.now();
#endif
- initialStackTop = STACKTOP;
- inMain = true;
+ var ret = Module['_main'](argc, argv, 0);
- var ret;
- try {
- ret = Module['_main'](argc, argv, 0);
+#if BENCHMARK
+ Module.realPrint('main() took ' + (Date.now() - start) + ' milliseconds');
+#endif
+
+ // if we're not running an evented main loop, it's time to exit
+ if (!Module['noExitRuntime']) {
+ exit(ret);
+ }
}
catch(e) {
- if (e && typeof e == 'object' && e.type == 'ExitStatus') {
+ if (e instanceof ExitStatus) {
// exit() throws this once it's done to make sure execution
// has been stopped completely
- Module.print('Exit Status: ' + e.value);
- return e.value;
+ return;
} else if (e == 'SimulateInfiniteLoop') {
// running an evented main loop, don't immediately exit
Module['noExitRuntime'] = true;
+ return;
} else {
throw e;
}
- } finally {
- inMain = false;
- }
-
-#if BENCHMARK
- Module.realPrint('main() took ' + (Date.now() - start) + ' milliseconds');
-#endif
-
- // if we're not running an evented main loop, it's time to exit
- if (!Module['noExitRuntime']) {
- exit(ret);
}
}
@@ -110,21 +113,14 @@ Module['run'] = Module.run = run;
function exit(status) {
ABORT = true;
+ EXITSTATUS = status;
STACKTOP = initialStackTop;
- // TODO call externally added 'exit' callbacks with the status code.
- // It'd be nice to provide the same interface for all Module events (e.g.
- // prerun, premain, postmain). Perhaps an EventEmitter so we can do:
- // Module.on('exit', function (status) {});
-
// exit the runtime
exitRuntime();
-
- if (inMain) {
- // if we're still inside the callMain's try/catch, we need to throw an
- // exception in order to immediately terminate execution.
- throw { type: 'ExitStatus', value: status };
- }
+
+ // throw an exception to halt the current execution
+ throw new ExitStatus(status);
}
Module['exit'] = Module.exit = exit;
@@ -134,6 +130,7 @@ function abort(text) {
}
ABORT = true;
+ EXITSTATUS = 1;
throw 'abort() at ' + (new Error().stack);
}
diff --git a/src/preamble.js b/src/preamble.js
index 585db832..95bf2dc2 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -241,6 +241,7 @@ var setjmpLabels = {};
#endif
var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort()
+var EXITSTATUS = 0;
var undef = 0;
// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
diff --git a/tests/runner.py b/tests/runner.py
index 4f2f024e..bd98fe63 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -3189,6 +3189,25 @@ Exiting setjmp function, level: 0, prev_jmp: -1
'''
self.do_run(src, 'caught std::exception')
+ def test_async_exit(self):
+ open('main.c', 'w').write(r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include "emscripten.h"
+
+ void main_loop() {
+ exit(EXIT_SUCCESS);
+ }
+
+ int main() {
+ emscripten_set_main_loop(main_loop, 60, 0);
+ return 0;
+ }
+ ''')
+
+ Popen([PYTHON, EMCC, 'main.c']).communicate()
+ self.assertNotContained('Reached an unreachable!', run_js(self.in_dir('a.out.js'), stderr=STDOUT))
+
def test_exit_stack(self):
if self.emcc_args is None: return self.skip('requires emcc')
if Settings.ASM_JS: return self.skip('uses report_stack without exporting')
@@ -3226,6 +3245,7 @@ Exiting setjmp function, level: 0, prev_jmp: -1
}
var Module = {
postRun: function() {
+ Module.print('Exit Status: ' + EXITSTATUS);
Module.print('postRun');
assert(initialStack == STACKTOP, [initialStack, STACKTOP]);
Module.print('ok.');
@@ -10223,13 +10243,19 @@ def process(filename):
printf("cleanup\n");
}
- int main()
- {
+ int main() {
atexit(cleanup); // this atexit should still be called
printf("hello, world!\n");
exit(118); // Unusual exit status to make sure it's working!
}
'''
+ open('post.js', 'w').write('''
+ Module.addOnExit(function () {
+ Module.print('Exit Status: ' + EXITSTATUS);
+ });
+ Module.callMain();
+ ''')
+ self.emcc_args += ['-s', 'INVOKE_RUN=0', '--post-js', 'post.js']
self.do_run(src, 'hello, world!\ncleanup\nExit Status: 118')
def test_gc(self):