-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Add pthread based worker custom message support #16239
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
Add pthread based worker custom message support #16239
Conversation
I think this might be reasonable to add, especially since we've had something similar in another mode. @sbc100 what do you think? If we decide to go with this, please update the docs under |
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 like the idea in general! I wonder about the naming though. Is onCustomMessage
the best name? Do we have existing present for using this naming convention? I don't know that I have any great alternatives... maybe onPostMessage
or onUserMessage
(like the void* user_data
from the C world)?
src/library_pthread.js
Outdated
if (Module['onCustomMessage']) { | ||
Module['onCustomMessage'](d); | ||
} else { | ||
throw 'Custom message received but worker Module.onCustomMessage not implemented.'; |
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.
How about:
#if ASSERTIONS
assert(Module['onCustomMessage'], 'Custom message received but worker Module.onCustomMessage not defined.').
#endif
Module['onCustomMessage'](d);
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.
Done for both occurences
</script> | ||
{{{ SCRIPT }}} | ||
</body> | ||
</html> |
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 don't think we should need to add this html file .. I think we can just set Module.onCustomMessage in a pre-js, no? (that way the test will run on node too).
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.
Good point. I got that working for a browser test, but I suppose it shouldn't be a browser test if it's to be ran with node?
Is core OK or should it be a 'other' test? (Or something else entirely?)
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 replaced the shell file with a --pre-js
for now, let me know if I should move the test to another suite
tests/custom_messages_worker.c
Outdated
|
||
EM_JS(void, run_test, (), { | ||
function sendMessageToMainThread(cmd, payload) { | ||
self.postMessage({ |
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.
What is self
here?
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.
The main worker (I believe?), but it appears to be useless, so let's remove it
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.
removed
33c5e99
to
e8cbca2
Compare
I'm fine with |
Hi, Gentle ping on this PR, please let me know if you want the naming, or anything else, to change :) |
@@ -274,6 +274,11 @@ var LibraryPThread = { | |||
if (Module['onAbort']) { | |||
Module['onAbort'](d['arg']); | |||
} | |||
} else if (cmd === 'custom') { |
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.
Can you wrap this new block in #if expectToReceiveOnModule('onCustomMessage')
@@ -293,6 +293,11 @@ self.onmessage = (e) => { | |||
if (Module['_pthread_self']()) { // If this thread is actually running? | |||
Module['_emscripten_proxy_execute_queue'](e.data.queue); | |||
} | |||
} else if (e.data.cmd === 'custom') { |
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.
And this one.
@@ -4263,6 +4263,10 @@ def test_canvas_size_proxy(self): | |||
def test_custom_messages_proxy(self): | |||
self.btest(test_file('custom_messages_proxy.c'), expected='1', args=['--proxy-to-worker', '--shell-file', test_file('custom_messages_proxy_shell.html'), '--post-js', test_file('custom_messages_proxy_postjs.js')]) | |||
|
|||
@requires_threads | |||
def test_custom_message_worker(self): | |||
self.btest(test_file('custom_messages_worker.c'), expected='1', args=['-sUSE_PTHREADS', '-sPTHREAD_POOL_SIZE=2', '--pre-js', test_file('custom_messages_worker_pre.js')]) |
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 don't think you need a pthread pool here do you? Can you remove the PTHREAD_POOL_SIZE
setting?
Can you use btest_exit
here rather than btest
(and remove the expected argument which will default to 0).
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.
Can you also run this test under node in test_other.py?
@@ -4263,6 +4263,10 @@ def test_canvas_size_proxy(self): | |||
def test_custom_messages_proxy(self): | |||
self.btest(test_file('custom_messages_proxy.c'), expected='1', args=['--proxy-to-worker', '--shell-file', test_file('custom_messages_proxy_shell.html'), '--post-js', test_file('custom_messages_proxy_postjs.js')]) | |||
|
|||
@requires_threads | |||
def test_custom_message_worker(self): | |||
self.btest(test_file('custom_messages_worker.c'), expected='1', args=['-sUSE_PTHREADS', '-sPTHREAD_POOL_SIZE=2', '--pre-js', test_file('custom_messages_worker_pre.js')]) |
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.
Should we call this custom_message_pthread
? Does that better describe what its testing?
@@ -163,3 +163,5 @@ Other methods | |||
|
|||
When compiled with ``PROXY_TO_WORKER = 1`` (see `settings.js <https://github.com/emscripten-core/emscripten/blob/main/src/settings.js>`_), this callback (which should be implemented on both the client and worker's ``Module`` object) allows sending custom messages and data between the web worker and the main thread (using the ``postCustomMessage`` function defined in `proxyClient.js <https://github.com/emscripten-core/emscripten/blob/main/src/proxyClient.js>`_ and `proxyWorker.js <https://github.com/emscripten-core/emscripten/blob/main/src/proxyWorker.js>`_). | |||
|
|||
When compiled with ``USE_PTHREADS = 1`` (see `settings.js <https://github.com/emscripten-core/emscripten/blob/main/src/settings.js>`_), this callback will be invoked when a message containing the command ``custom`` is received. It allows to send messages back and forth between workers and the main thread using the ``Worker.postMessage`` 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.
Drop the = 1
here.. its not needed.
Apologies, but I feel strongly against merging this. The issue here is that layering new functionality on There are a number of blog posts that have found themselves wanting to ridicule Emscripten for the fact that the tiniest "hello world" printf apps produce large output code sizes, so there has been a lot of work going in to ensure that what people perceive as bloat is being actively reduced. Because of that, I don't think we should have this kind of addition merged in, since it increases code size for all pthreads users. While the code size increase is "just linear" in the number of bytes added, the cognitive load to read the build output increases superlinearly really fast. I would recommend instead adopting an approach of using existing library functions. We already have a number of different APIs for proxying and sending messages between Workers, couldn't one of those be used instead? |
As for the existing |
We recently developed an approach that allows use to extend/use the incoming module API in an opt-in way that doesn't bloat the code for users unless they explicitly opt into it. The technique was enabled by this change: #16346 And first used here: #16361 This means that we should never need to increase the default Given that we have this opt-in mechanism now, I think these kind of changes are a lot more acceptable. We can have a separate debate about "should we allow users to hook directly into the postMessage loop".. but there is no (default) code size bloat associated with this change if we decide the answer is yes. |
BTW, I totally agree that these kinds of changes are no acceptable if they increase the code size by default. |
It should always have been the case that people can directly inject their own postMessage events. All the One thing in particular is that Emscripten should not be assigning Restricting users from being able to submit custom postMessages would be limiting from site extensibility viewpoint.
I do recall that, and I don't think it is the best solution tbh. It fixes complexity by adding more complexity. While it does fix the final build output in terms of code size, it does so by making Emscripten harder to use (a new (Though now that I read this, I think the code size here does grow, and it is not adhering to the setting in Note that I hope I am not setting up a double standard: I do also leverage custom -s settings like this, e.g. the upcoming However I think the critical difference here is that such settings should be introduced only when we realize there is no other way to get to emit the code/feature otherwise. If that is the case, then I think the complexity is warranted. However in this case I think this use case can be solved with existing JS and C/C++ library functions without needing to add non-DCEing functionality? (Or if not, my apologies, but in that case, I hope we can look a bit more in detail about the specific use case to see why the existing message passing library functions will not cut it) |
See #16239 (comment). I was not planning on having this land without that change. |
Regarding the issue at hand, the ability to receive custom messages on a worker, I didn't know about |
Hi and sorry about the bit of delay. Indeed the
path. I'm not entirely at ease with removing the error in case of an unknown message, and moving the error in a build setting dependent block doesn't seem to user friendly. I'm unsure what's the way to go from here, but it seems that this MR should be closed as most of its code will be removed anyway |
Great, that's good to hear!
Oops, that looks like a bug.. the error message should only trigger if receiving a message that looks like it should be handled by the library_pthread.js message listener. Posted #16450 to fix that. Does that help? |
I agree that using How do you envisage a use calling |
Apparently yes! Thanks However, I spoke too soon when I said that addEventListener is working. I can add some additional listeners from pthread, but I failed to add an extra listener for the main thread. Using AFAIU I should add the event handler to the If I add a listener through the |
I think you would need to somehow attach you even handler to each new worker object that gets created. These event listeners handlers are added in library_pthread.js. See |
This should work indeed, but it would still require the user to be able to inject their handler into emscripten somehow no? I was hopping to achieve something less intrusive through To put it another way, I don't really see the difference between the original attempt in this MR and exposing another event handler to all workers. I'll do another pass at the previous comments with a rested head tomorrow as I might have missed something |
Yes, according to the discussion happening over on #16450 it should be possible for you to call |
That was my initial attempt, but so far From other threads that's not an issue though |
Yes that is expected, the handler would only need to be installed from the main thread and on the workers it owns. |
Doesn't that mean that it's not possible to add a message handler for the main thread? To try and clarify, I'm trying to send a message from a worker to the main thread in order to transfer some objects. The message is sent & correctly received by the Again, sorry if I'm missing something |
Oh I think I'm starting to understand my confusion, feel free to ignore my last comment for the time being, sorry about that |
I can now confirm that this patchset is unrequired. For the sake of explaining my confusion, should it be useful to anyone else, my main mistake was to assume that However in reality, the event handler in invoked on the same worker object, but from a different thread. Meaning that when the handler is invoked, it can access things that are only accessible from the main thread, so it's fairly easy to find the correct worker object knowing the thread ID TL;DR I can do what I want with this kind of code:
and later on invoke the handler through the usual I hope this makes sense and can help someone struggling with starting with emscripten as I am 😅 Thanks a lot for your help and time with this! I'll now close the MR |
Hi,
This MR adds support for handling custom messages in pthread based workers, similar to https://emscripten.org/docs/api_reference/module.html#Module.onCustomMessage but even when building without
PROXY_TO_WORKER