Skip to content
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
17ef4e3
NO_EXIT_RUNTIME=1 by default: avoid including runtime shutdown overhe…
kripken Nov 28, 2017
f3eb364
fixes
kripken Nov 28, 2017
1106aed
more tests
kripken Nov 28, 2017
05f07be
fixes
kripken Nov 28, 2017
3d623eb
bonus: the new default of NO_EXIT_RUNTIME=1 is the common case on the…
kripken Nov 28, 2017
7ca10a1
fix
kripken Nov 28, 2017
ac6a066
fix
kripken Nov 28, 2017
fa0f631
docs
kripken Nov 28, 2017
9e299c5
fix
kripken Nov 28, 2017
890c5ea
fix
kripken Nov 28, 2017
bc3abe8
fix FORCE_FILESYSTEM: it actually never had any code to make it work …
kripken Nov 28, 2017
1655df2
fix
kripken Nov 28, 2017
268a781
fixes
kripken Nov 28, 2017
1da0890
fix
kripken Nov 29, 2017
b80bdf7
fix
kripken Nov 29, 2017
0f6e8fa
fix
kripken Nov 29, 2017
2672778
better test
kripken Nov 29, 2017
49a5234
fixes
kripken Nov 29, 2017
b8daf47
fixes
kripken Nov 29, 2017
ce7b4f4
warn on exitin with a non-zero code when NO_EXIT_RUNTIME (as then we …
kripken Nov 29, 2017
15a7083
fixes
kripken Nov 29, 2017
1af3ea8
if we exit with a non-zero code, emit it even if NO_EXIT_RUNTIME (use…
kripken Nov 29, 2017
04ce11d
fixes
kripken Nov 29, 2017
6ac52fb
fix flush assertion for c++ code, add testing
kripken Nov 29, 2017
748f2eb
fixes
kripken Nov 29, 2017
d2c4f19
Merge remote-tracking branch 'origin/incoming' into no-exit-runtime
kripken Nov 29, 2017
0611661
update Changelog
kripken Nov 29, 2017
096f7ec
fix
kripken Nov 29, 2017
e040af1
fix browser.test_asm_swapping
kripken Nov 30, 2017
39ef944
fix browser.test_emterpreter_async_sleep2_safeheap
kripken Nov 30, 2017
e6e1bc4
fixes
kripken Nov 30, 2017
f04b0cd
always exit pthreads: if we do not, the main thread simply hangs on t…
kripken Nov 30, 2017
5e81d11
emrun sets NO_EXIT_RUNTIME=0. it is a mode where we specifically want…
kripken Nov 30, 2017
43401c9
Merge remote-tracking branch 'origin/incoming' into no-exit-runtime
kripken Nov 30, 2017
72e7255
add faq entry, and mention the faq
kripken Dec 1, 2017
4dc9381
explain flushing check
kripken Dec 1, 2017
6bf8d53
fix an existing emterpreter-async bug: if we are unwinding the stack …
kripken Dec 1, 2017
195a99c
improve text
kripken Dec 5, 2017
04c3a9a
Merge remote-tracking branch 'origin/incoming' into no-exit-runtime
kripken Dec 5, 2017
be26e6b
warn on calling emscripten_force_exit when NO_EXIT_RUNTIME
kripken Dec 5, 2017
f6167e7
whitespace
kripken Dec 5, 2017
f8dadc6
Merge branch 'incoming' into no-exit-runtime
kripken Dec 6, 2017
9821ad7
Merge branch 'incoming' into no-exit-runtime
kripken Dec 15, 2017
9aa1ddb
metadce is now more effective, update test
kripken Dec 15, 2017
66345ff
faq entry on Module.* is not a function [ci skip]
kripken Dec 16, 2017
7d5e86c
Merge branch 'followups' into no-exit-runtime
kripken Dec 16, 2017
83059d2
improve message
kripken Dec 16, 2017
4299787
fix browser.test_emscripten_main_loop - the pthreads part needs the r…
kripken Dec 16, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion ChangeLog.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ To browse or download snapshots of old tagged versions, visit https://github.com

Not all changes are documented here. In particular, new features, user-oriented fixes, options, command-line parameters, usage changes, deprecations, significant internal modifications and optimizations etc. generally deserve a mention. To examine the full set of changes between versions, visit the link to full changeset diff at the end of each section.

Current trunk code
Current Trunk
-------------
- Breaking change: Change `NO_EXIT_RUNTIME` to 1 by default. This means that by default we don't include code to shut down the runtime, flush stdio streams, run atexits, etc., which is better for code size. When `ASSERTIONS` is on, we warn at runtime if there is text buffered in the streams that should be flushed, or atexits are used.

v1.37.17: 7/25/2017
------------------
- Updated to libc++'s "v2" ABI, which provides better alignment for string data and other improvements. This is an ABI-incompatible change, so bitcode files from previous versions will not be compatible.
- To see a list of commits in the active development branch 'incoming', which have not yet been packaged in a release, see
Expand Down
19 changes: 11 additions & 8 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,9 @@ def filter_emscripten_options(argv):
# The preprocessor define EMSCRIPTEN is deprecated. Don't pass it to code in strict mode. Code should use the define __EMSCRIPTEN__ instead.
if not shared.Settings.STRICT:
cmd += ['-DEMSCRIPTEN']
if use_js: cmd += ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1'] # configure tests should fail when an undefined symbol exists
if use_js:
cmd += ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1'] # configure tests should fail when an undefined symbol exists
cmd += ['-s', 'NO_EXIT_RUNTIME=0'] # configure tests want a more shell-like style, where we emit return codes on exit()

logging.debug('just configuring: ' + ' '.join(cmd))
if debug_configure: open(tempout, 'a').write('emcc, just configuring: ' + ' '.join(cmd) + '\n\n')
Expand Down Expand Up @@ -659,6 +661,8 @@ def detect_fixed_language_mode(args):
if options.emrun:
options.pre_js += open(shared.path_from_root('src', 'emrun_prejs.js')).read() + '\n'
options.post_js += open(shared.path_from_root('src', 'emrun_postjs.js')).read() + '\n'
# emrun mode waits on program exit
shared.Settings.NO_EXIT_RUNTIME = 0

if options.cpu_profiler:
options.post_js += open(shared.path_from_root('src', 'cpuprofiler.js')).read() + '\n'
Expand Down Expand Up @@ -1068,9 +1072,12 @@ def check(input_file):

if not shared.Settings.NO_FILESYSTEM and not shared.Settings.ONLY_MY_CODE:
shared.Settings.EXPORTED_FUNCTIONS += ['___errno_location'] # so FS can report errno back to C
if not shared.Settings.NO_EXIT_RUNTIME:
shared.Settings.EXPORTED_FUNCTIONS += ['_fflush'] # to flush the streams on FS quit
# TODO this forces 4 syscalls, maybe we should avoid it?
# to flush streams on FS exit, we need to be able to call fflush
# we only include it if the runtime is exitable, or when ASSERTIONS
# (ASSERTIONS will check that streams do not need to be flushed,
# helping people see when they should have disabled NO_EXIT_RUNTIME)
if not shared.Settings.NO_EXIT_RUNTIME or shared.Settings.ASSERTIONS:
shared.Settings.EXPORTED_FUNCTIONS += ['_fflush']

if shared.Settings.USE_PTHREADS:
if not any(s.startswith('PTHREAD_POOL_SIZE=') for s in settings_changes):
Expand Down Expand Up @@ -1200,10 +1207,6 @@ def check(input_file):
if 'interpret' in shared.Settings.BINARYEN_METHOD:
logging.warning('disabling EVAL_CTORS as the bundled interpreter confuses the ctor tool')
shared.Settings.EVAL_CTORS = 0
else:
# for wasm, we really want no-exit-runtime, so that atexits don't stop us
if final_suffix in JS_CONTAINING_SUFFIXES and not shared.Settings.NO_EXIT_RUNTIME:
logging.warning('you should enable -s NO_EXIT_RUNTIME=1 so that EVAL_CTORS can work at full efficiency (it gets rid of atexit calls which might disrupt EVAL_CTORS)')

# memory growth does not work in dynamic linking, except for wasm
if not shared.Settings.WASM and (shared.Settings.MAIN_MODULE or shared.Settings.SIDE_MODULE):
Expand Down
2 changes: 1 addition & 1 deletion site/source/docs/getting_started/FAQ.rst
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ Another option is to define an ``onRuntimeInitialized`` function,

Module['onRuntimeInitialized'] = function() { ... };

That method will be called when the runtime is ready and it is ok for you to call compiled code. In practice, that is exactly the same time at which ``main()`` would be called, so ``onRuntimeInitialized`` doesn't let you do anything new, but it can be convenient in some cases - for example, if you use ``onRuntimeInitialized`` and don't define a ``main()`` function, then the runtime will not be shut down after ``main()`` exits, and you can keep calling compiled methods (you can also have a ``main()`` and build with ``-s NO_EXIT_RUNTIME=1`` to keep the runtime from being shut down). Thus, for libraries, ``onRuntimeInitialized`` can be convenient.
That method will be called when the runtime is ready and it is ok for you to call compiled code. In practice, that is exactly the same time at which ``main()`` would be called, so ``onRuntimeInitialized`` doesn't let you do anything new, but you can set it from JavaScript at runtime in a flexible way.

Here is an example of how to use it:

Expand Down
12 changes: 0 additions & 12 deletions site/source/docs/optimizing/Optimizing-Code.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,6 @@ Advanced compiler settings

There are several flags you can :ref:`pass to the compiler <emcc-s-option-value>` to affect code generation, which will also affect performance — for example :ref:`DISABLE_EXCEPTION_CATCHING <optimizing-code-exception-catching>`. These are documented in `src/settings.js <https://github.com/kripken/emscripten/blob/master/src/settings.js>`_. Some of these will be directly affected by the optimization settings (you can find out which ones by searching for ``apply_opt_level`` in `tools/shared.py <https://github.com/kripken/emscripten/blob/1.29.12/tools/shared.py#L958>`_).

A few useful flags are:

-
.. _optimizing-code-no-exit-runtime:

``NO_EXIT_RUNTIME``: Building with ``-s NO_EXIT_RUNTIME=1`` lets the compiler know that you don't want to shut down the runtime environment after the ``main()`` function finishes. This allows it to discard the ``atexit`` and global destructor calls it would otherwise make, improving code size and startup speed.

This is useful if your ``main()`` function finishes but you still want to execute code, for example in an app that uses a :ref:`main loop function <emscripten-runtime-environment-main-loop>`.

.. note:: Emscripten will not shut down the runtime if it detects :c:func:`emscripten_set_main_loop`, but it is better to optimise away the unnecessary code.



Code size
=========
Expand Down
2 changes: 1 addition & 1 deletion site/source/docs/tools_reference/emcc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ Options that are modified or new in *emcc* are listed below:
.. _emcc-emrun:

``--emrun``
Enables the generated output to be aware of the :ref:`emrun <Running-html-files-with-emrun>` command line tool. This allows ``stdout``, ``stderr`` and ``exit(returncode)`` capture when running the generated application through *emrun*.
Enables the generated output to be aware of the :ref:`emrun <Running-html-files-with-emrun>` command line tool. This allows ``stdout``, ``stderr`` and ``exit(returncode)`` capture when running the generated application through *emrun*. (This enables `NO_EXIT_RUNTIME=0`, allowing normal runtime exiting with return code passing.)

``--cpuprofiler``
Embeds a simple CPU profiler onto the generated page. Use this to perform cursory interactive performance profiling.
Expand Down
5 changes: 5 additions & 0 deletions src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,11 @@ LibraryManager.library = {
atexit__proxy: 'sync',
atexit__sig: 'ii',
atexit: function(func, arg) {
#if ASSERTIONS
#if NO_EXIT_RUNTIME == 1
Runtime.warnOnce('atexit() called, but NO_EXIT_RUNTIME, so atexits() will not be called. set NO_EXIT_RUNTIME to 0');
Copy link
Member

Choose a reason for hiding this comment

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

This could probably use some more detail or a link to a doc. Also in C++, if the user has any static objects with destructors, then those destructors get registered with atexit under the hood. so the doc or message should probably mention that case explicitly.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point, added a FAQ entry about that, and mentioned the FAQ in those messages.

#endif
#endif
__ATEXIT__.unshift({ func: func, arg: arg });
},
__cxa_atexit: 'atexit',
Expand Down
4 changes: 4 additions & 0 deletions src/library_fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -1919,3 +1919,7 @@ mergeInto(LibraryManager.library, {
}
});

if (FORCE_FILESYSTEM) {
DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push('$FS');
}

15 changes: 14 additions & 1 deletion src/library_syscall.js
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,20 @@ var SyscallsLibrary = {
return SYSCALLS.doReadv(stream, iov, iovcnt);
},
#if NO_FILESYSTEM
__syscall146__postset: '/* flush anything remaining in the buffer during shutdown */ __ATEXIT__.push(function() { var fflush = Module["_fflush"]; if (fflush) fflush(0); var printChar = ___syscall146.printChar; if (!printChar) return; var buffers = ___syscall146.buffers; if (buffers[1].length) printChar(1, {{{ charCode("\n") }}}); if (buffers[2].length) printChar(2, {{{ charCode("\n") }}}); });',
$flush_NO_FILESYSTEM: function() {
// flush anything remaining in the buffers during shutdown
var fflush = Module["_fflush"];
if (fflush) fflush(0);
var printChar = ___syscall146.printChar;
if (!printChar) return;
var buffers = ___syscall146.buffers;
if (buffers[1].length) printChar(1, {{{ charCode("\n") }}});
if (buffers[2].length) printChar(2, {{{ charCode("\n") }}});
},
__syscall146__deps: ['$flush_NO_FILESYSTEM'],
#if NO_EXIT_RUNTIME == 0
__syscall146__postset: '__ATEXIT__.push(flush_NO_FILESYSTEM);',
#endif
#endif
__syscall146: function(which, varargs) { // writev
#if NO_FILESYSTEM == 0
Expand Down
49 changes: 45 additions & 4 deletions src/postamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,17 +311,58 @@ function run(args) {
Module['run'] = run;

function exit(status, implicit) {
if (implicit && Module['noExitRuntime']) {
#if ASSERTIONS
Module.printErr('exit(' + status + ') implicitly called by end of main(), but noExitRuntime, so not exiting the runtime (you can use emscripten_force_exit, if you want to force a true shutdown)');
#if NO_EXIT_RUNTIME == 1
// compiler settings do not allow exiting the runtime, so flushing
// the streams is not possible. but in ASSERTIONS mode we check
// if there was something to flush, and if so tell the user they
// should request that the runtime be exitable.
// how we flush the streams depends on whether we are in NO_FILESYSTEM
// mode (which has its own special function for this; otherwise, all
// the code is inside libc)
#if NO_FILESYSTEM
var flush = {{{ '$flush_NO_FILESYSTEM' in addedLibraryItems ? 'flush_NO_FILESYSTEM' : 'null' }}};
#else
var flush = {{{ '$FS' in addedLibraryItems ? 'FS.quit' : "Module['_fflush']" }}};
#endif
if (flush) {
Copy link
Member

Choose a reason for hiding this comment

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

I don't quite understand why we are doing this dance with module.print. If it's ok to just call the users's fflush, why can't we just call it and let it flush for real?

Copy link
Member Author

@kripken kripken Dec 1, 2017

Choose a reason for hiding this comment

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

We don't normally even include fflush anymore, we only include it in ASSERTIONS builds. So we don't want to show the proper output here, we want to see if there would be a problem, had we not been in an ASSERTIONS build. So we just check if flushing would have emitting something (and we do so very carefully, as shutting down the FS may throw an error if it hit an error previously or something like that).

I can add more of an explanation to the code?

Copy link
Member Author

Choose a reason for hiding this comment

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

Reading that again it does seem less than obvious, good point. Added a comment.

var print = Module['print'];
var printErr = Module['printErr'];
var has = false;
Module['print'] = Module['printErr'] = function(x) {
has = true;
}
try { // it doesn't matter if it fails
flush(0);
} catch(e) {}
Module['print'] = print;
Module['printErr'] = printErr;
if (has) {
Runtime.warnOnce('stdio streams had content in them that was not flushed. you should set NO_EXIT_RUNTIME to 0');
}
}
#endif // NO_EXIT_RUNTIME
#endif // ASSERTIONS

// if this is just main exit-ing implicitly, and the status is 0, then we
// don't need to do anything here and can just leave. if the status is
// non-zero, though, then we need to report it.
// (we may have warned about this earlier, if a situation justifies doing so)
if (implicit && Module['noExitRuntime'] && status === 0) {
return;
}

if (Module['noExitRuntime']) {
#if ASSERTIONS
Module.printErr('exit(' + status + ') called, but noExitRuntime, so halting execution but not exiting the runtime or preventing further async execution (you can use emscripten_force_exit, if you want to force a true shutdown)');
#endif
// if exit() was called, we may warn the user if the runtime isn't actually being shut down
if (!implicit) {
#if NO_EXIT_RUNTIME
Module.printErr('exit(' + status + ') called, but compiled with NO_EXIT_RUNTIME, so halting execution but not exiting the runtime or preventing further async execution (build with NO_EXIT_RUNTIME=0, if you want a true shutdown)');
#else
Module.printErr('exit(' + status + ') called, but noExitRuntime, so halting execution but not exiting the runtime or preventing further async execution (you can use emscripten_force_exit, if you want to force a true shutdown)');
Copy link
Member

Choose a reason for hiding this comment

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

same here

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, done.

#endif // NO_EXIT_RUNTIME
}
#endif // ASSERTIONS
} else {
#if USE_PTHREADS
PThread.terminateAllThreads();
Expand Down
3 changes: 1 addition & 2 deletions src/pthread-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,7 @@ this.onmessage = function(e) {
}
// The thread might have finished without calling pthread_exit(). If so, then perform the exit operation ourselves.
// (This is a no-op if explicit pthread_exit() had been called prior.)
if (!Module['noExitRuntime']) PThread.threadExit(result);
else console.log('pthread noExitRuntime: not quitting.');
PThread.threadExit(result);
} else if (e.data.cmd === 'cancel') { // Main thread is asking for a pthread_cancel() on this thread.
if (threadInfoStruct && PThread.thisThreadCancelState == 0/*PTHREAD_CANCEL_ENABLE*/) {
PThread.threadCancel();
Expand Down
8 changes: 6 additions & 2 deletions src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,12 @@ var VERBOSE = 0; // When set to 1, will generate more verbose output during comp
var INVOKE_RUN = 1; // Whether we will run the main() function. Disable if you embed the generated
// code in your own, and will call main() yourself at the right time (which you
// can do with Module.callMain(), with an optional parameter of commandline args).
var NO_EXIT_RUNTIME = 0; // If set, the runtime is not quit when main() completes (allowing code to
// run afterwards, for example from the browser main event loop).
var NO_EXIT_RUNTIME = 1; // If 1, the runtime is not quit when main() completes (allowing code to
// run afterwards, for example from the browser main event loop). atexit()s
// are also not executed, and we can avoid including code for runtime shutdown,
// like flushing the stdio streams.
// Set this to 0 if you do want atexit()s or stdio streams to be flushed
// on exit.
var MEM_INIT_METHOD = 0; // How to represent the initial memory content.
// 0: embed a base64 string literal representing the initial memory data
// 1: create a *.mem file containing the binary data of the initial memory;
Expand Down
1 change: 0 additions & 1 deletion tests/test_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ def process(filename):
OPTIMIZATIONS,
'--memory-init-file', '0', '--js-transform', 'python hardcode.py',
'-s', 'TOTAL_MEMORY=256*1024*1024',
'-s', 'NO_EXIT_RUNTIME=1',
'-s', 'NO_FILESYSTEM=1',
'-s', 'EXPORTED_RUNTIME_METHODS=[]',
'-s', 'BENCHMARK=%d' % (1 if IGNORE_COMPILATION and not has_output_parser else 0),
Expand Down
Loading