-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Disallow blocking on the main thread by default #9579
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
Conversation
Thinking about this a little more, it might makes sense to get some more eyes/discussion on this issue before we land it, since it is potentially a fairly-disruptive change. Also it might make sense to have our hypothesized |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a great idea.
I'm surprised how many tests rely on ALLOW_BLOCKING_ON_MAIN_THREAD.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than the part about ALLOW_BLOCKING_ON_MAIN THREAD, there's probably no reason to wait on this documentation though.
It's probably even worth expanding a bit more, to include e.g. to distinguish between the Module
thread (or main runtime thread, or ??) vs the browser main thread?
src/library_pthread.js
Outdated
@@ -790,7 +790,16 @@ var LibraryPThread = { | |||
if (canceled == 2) throw 'Canceled!'; | |||
}, | |||
|
|||
{{{ USE_LSAN ? 'emscripten_builtin_' : '' }}}pthread_join__deps: ['_cleanup_thread', '_pthread_testcancel_js', 'emscripten_main_thread_process_queued_calls', 'emscripten_futex_wait'], | |||
emscripten_block_on_main_thread: function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a nit pick, but I don't really like the name of this function. To me it sounds like this blocks on the main thread, when it actually either aborts of does nothing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree emscripten_block_on_main_thread
is not the best, but I couldn't find a better one - ideas?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure. The only thing I can think of would be emscripten_block_on_main_thread_or_die (in the same vain as functions like malloc_or_die), but I'm not sure if that's actually any better. Either way it's not that big of a deal in my opinion.
Thanks for the feedback, should be addressed in those commits. In particular this adds |
I was actually wondering - rather than disallowing blocking on the main thread and giving an escape hatch in form of a setting that still allows it, could we transform Such Asyncify transform should also be perfectly compatible with the new UPD: I've read a bit further and see you already mentioned similar option in the docs 🤦♂️ It really seems preferable to do this automatically IMO both from developer's perspective (no change to the code) and from browser/user perspective (no escape hatch to do real blocking). |
@RReverser I agree that is good solution, but I think it should certainly be opt-in in it, at least by adding Mentioning this solution in the doc seems fine to me. |
I'd argue not as much overhead as blocking the main thread. That is, I agree it should be an opt-in, but I'm suggesting it as a potentially better fallback instead of
For start it would need to be implemented (AFAIK it's not yet). |
@RReverser interesting idea, yeah, Asyncify integration sounds worth looking into. A slightly-weird idea might even be to create two wasm files, one with Asyncify and one without, and the Asyncify one would only be used on the main thread where it is needed... anyhow, something to think about in followups. |
@surma Sounds good, updated to just warn by default. We can consider flipping the flag added here to make it an error later on. |
@kripken , actually, it looks like the warning only appears when compiling in debug mode (that is, with ASSERTIONS=1) and not in any other modes (when optimizations are set, ASSERTIONS=0). Maybe the intent would have been to display the message in all cases, otherwise people might never see it ! So this new flag might not bring any new information :/ I am just saying this because I was wondering why I did not see the warning, even though I knew I did dangerous things on purpose :) Just a suggestion |
Hmm, that seems odd - the code is emscripten_check_blocking_allowed: function() {
#if ASSERTIONS
assert(ENVIRONMENT_IS_WEB);
warnOnce('Blocking on the main thread is very dangerous, see https://emscripten.org/docs/porting/pthreads.html#blocking-on-the-main-browser-thread');
#endif
#if !ALLOW_BLOCKING_ON_MAIN_THREAD
abort('Blocking on the main thread is not allowed by default. See https://emscripten.org/docs/porting/pthreads.html#blocking-on-the-main-browser-thread');
#endif
}, That should abort in a release build. Is that code not even reached for you? |
(also that warnOnce looks redundant, maybe we should remove it...) |
No, for some reason that is not reached! So maybe there is a bug (?) In my code, ASSERTIONS are turned off (due to -O2/-Os build), and ALLOW_BLOCKING_ON_MAIN_THREADS is not set (and so, according to settings.js, it is set to "1"). But this behavior looks like to be consistent with the code. If ASSERTIONS=0, then no warning messages, if ALLOW_BLOCKING_ON_MAIN_THREAD=1, then no abort. Or I am missing something ? |
Oh, no, that is the intended behavior: by default we do allow blocking (we decided it was too disruptive to disallow by default). And also by default we do not show extra warnings when ASSERTIONS are off (in production builds people don't want those, usually). |
Ok, got it. Then that's what my suggestion was about: to enable the warning even on production builds (so that developers not working in Debug have an opportunity to see it at least once), but still letting them disabling the warning if they judge it is OK for their use case. So I imagined having the default value of the flag to be something like =2 (show the warning in all cases, even on production, but do not abort). Well, nothing dramatic, I can live without this :) |
Maybe we should have different levels of |
Ok, that's right. I'll now enable emscripten ASSERTIONS on non-debug builds, only disabling them for production. Definitively looks like to be good practice. |
Add a new ALLOW_BLOCKING_ON_MAIN_THREAD option, set to 1 by default. If unset, it will throw when blocking on the main thread. If 1 as in the default case, we warn in the console about possible issues and link to the docs about that. This ignores things like mutexes which are usually brief, and checks for pthread_join or pthread_cond_wait operations, which tend to be longer and run the risk of Web-specific proxying-related deadlocks. Add pthread_tryjoin_np which does a non-blocking join, which always works on the main thread. Improve the docs in this area.
If
ALLOW_BLOCKING_ON_MAIN_THREAD
is not set by the user, throw an error ifpthread_join
orpthread_cond_wait
are called on the main browser thread, which is bad for responsiveness and at risk of deadlocks. If the error is shown it points to our docs, which explain the issue and mention the flag that can allow blocking at your own risk.