-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Don't execute the proxy queue while adding to it from same thread. #24565
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
base: main
Are you sure you want to change the base?
Changes from 7 commits
835e918
91fa30f
a76f7e2
973f709
9528e48
7c24ee8
2b6857c
1b8ce30
1fd8cb8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// Copyright 2025 The Emscripten Authors. All rights reserved. | ||
// Emscripten is available under two separate licenses, the MIT license and the | ||
// University of Illinois/NCSA Open Source License. Both these licenses can be | ||
// found in the LICENSE file. | ||
|
||
#include <pthread.h> | ||
#include <stdlib.h> | ||
#include <unistd.h> | ||
#include <emscripten/console.h> | ||
#include <emscripten/heap.h> | ||
#include <emscripten/proxying.h> | ||
#include <emscripten/threading.h> | ||
|
||
bool should_quit = false; | ||
pthread_t looper; | ||
|
||
// In the actual implementation of malloc the system queue may be executed | ||
// non-deterministically if malloc is waiting on a mutex. This wraps malloc and | ||
// executes the system queue during every allocation to make the behavior | ||
// deterministic. | ||
void *malloc(size_t size) { | ||
if (emscripten_proxy_get_system_queue() && emscripten_is_main_runtime_thread()) { | ||
emscripten_proxy_execute_queue(emscripten_proxy_get_system_queue()); | ||
} | ||
void *ptr = emscripten_builtin_malloc(size); | ||
return ptr; | ||
} | ||
|
||
void run_on_looper(void* arg) { | ||
emscripten_out("run_on_looper\n"); | ||
should_quit = true; | ||
} | ||
|
||
void* looper_main(void* arg) { | ||
while (!should_quit) { | ||
emscripten_proxy_execute_queue(emscripten_proxy_get_system_queue()); | ||
sched_yield(); | ||
} | ||
return NULL; | ||
} | ||
|
||
int main() { | ||
pthread_create(&looper, NULL, looper_main, NULL); | ||
emscripten_proxy_async(emscripten_proxy_get_system_queue(), looper, run_on_looper, NULL); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this ever set should_quit before looper_main actually starts running? Can you add some comments somewhere in this file about exactly that case we are testing for. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I kind of assumed the thread start would be guaranteed to run before any proxy messages, but now I'm not sure. Even if it does run before, we'd still hit a deadlock since the main thread will be locked during task creation and trying to run the queue and lock again. It doesn't really matter what the other thread is doing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed the test a bit more and removed the looper thread and just sends the task to the same thread. This makes the test a little less realistic, but highlights it doesn't really matter what the thread is doing. |
||
pthread_join(looper, NULL); | ||
emscripten_out("done\n"); | ||
} |
Uh oh!
There was an error while loading. Please reload this page.