Skip to content
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

Strange behaviour when detecting ENVIRONMENT_IS_PTHREAD #22541

Open
turran opened this issue Sep 9, 2024 · 4 comments
Open

Strange behaviour when detecting ENVIRONMENT_IS_PTHREAD #22541

turran opened this issue Sep 9, 2024 · 4 comments

Comments

@turran
Copy link

turran commented Sep 9, 2024

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.61 (67fa4c16496b157a7fc3377afd69ee0445e8a6e3)
clang version 19.0.0git (https:/github.com/llvm/llvm-project 7cfffe74eeb68fbb3fb9706ac7071f8caeeb6520)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /home/jl/w/github/gst.wasm/build/gst.wasm_web_wasm32/emsdk/upstream/bin

I am porting a multithreaded library and when creating (and transferring the canvas to) a thread I get the following error:

pthread_create: could not find canvas with ID "#canvas" to transfer to thread!
pthread_create: cannot transfer canvas with ID "canvas" to thread, since the current thread does not have control over it!

My code is creating a new thread from another thread already created. If I use the main thread, everything works as expected.
I first thought that it was not possible to create a thread from another thread but there is this code:

      // Synchronously proxy the thread creation to main thread if possible. If we
      // need to transfer ownership of objects, then proxy asynchronously via
      // postMessage.
      if (ENVIRONMENT_IS_PTHREAD && (transferList.length === 0 || error)) {
        return pthreadCreateProxied(pthread_ptr, attr, startRoutine, arg);
      }

Which made me discard that idea, reviewing the .js code I see this:

} else if (!ENVIRONMENT_IS_PTHREAD) {                                                           
          
            var canvas = (Module['canvas'] && Module['canvas'].id === name) ? Module['canvas'] : document.querySelector(name);
            if (!canvas) {
              err(`pthread_create: could not find canvas with ID "${name}" to transfer to thread!`);      
              error = 28;
              break;
            } 
            if (canvas.controlTransferredOffscreen) {                                                     
              err(`pthread_create: cannot transfer canvas with ID "${name}" to thread, since the current thread does not have control over it!`);
              error = 63; // Operation not permitted, some other thread is accessing the canvas.          
              break;
            }

For some reason, the thread I'm creating the new thread on is evaluating to True in ENVIRONMENT_IS_PTHREAD
Any idea what is going on? My understanding is that it should evaluate to False and then recall this proxied from the main thread.

Important topic, this only happens with -sPROXY_TO_PTHREAD set

@sbc100
Copy link
Collaborator

sbc100 commented Sep 9, 2024

If you are seeing the pthread_create: could not find canvas with ID error message then that means that ENVIRONMENT_IS_PTHREAD is False which means that call has been correctly proxied back to the main thread.

I suppose the question is why isn't Module['canvas'] set correctly here the main thread. Can you set a break point and see if Module['canvas'] exists at all.

Can you share the full set of link flags you are using?

@turran
Copy link
Author

turran commented Sep 10, 2024

Yes, you are right. I read the condition the other way around.

Module['canvas'] is correctly set, the problem is on the second condition canvas.controlTransferredOffscreen, it is true. Like if the canvas has been shared already.

About link flags:

-sERROR_ON_UNDEFINED_SYMBOLS=1 -sWASM_BIGINT -O3 -pthread -fexceptions -sAUTO_JS_LIBRARIES=0 -sAUTO_NATIVE_LIBRARIES=0 -sPTHREAD_POOL_SIZE=32 -sINITIAL_MEMORY=536870912 -lembind -sASYNCIFY -sPROXY_TO_PTHREAD -sFETCH=1 -g3 -lhtml5 -lGL -sOFFSCREENCANVAS_SUPPORT

@sbc100
Copy link
Collaborator

sbc100 commented Sep 10, 2024

I see, can the canvas only be transfer to one thread? I guess that why PROXY_TO_PTHREAD breaks your use case because likely the canvas has already be transferred to the thread that is running your main function.

It looks like you can override OFFSCREENCANVASES_TO_PTHREAD perhaps? See

// Pass special ID -1 to the list of transferred canvases to denote that the
// thread creation should instead take a list of canvases that are specified
// from the command line with -sOFFSCREENCANVASES_TO_PTHREAD linker flag.
emscripten_pthread_attr_settransferredcanvases(&attr, (const char*)-1);
and https://emscripten.org/docs/tools_reference/settings_reference.html#offscreencanvases-to-pthread

@turran
Copy link
Author

turran commented Sep 10, 2024

Hmmm, the situation is similar but not the same.
With PROXY_TO_PTHREAD, the following sequence happens if I create my thread requesting (attr set) "#canvas":

Main Thread -> Proxied Thread (the canvas is transferred) -> Thread 2 Creation
                                                          -> Thread 3 Creation with attr

In this case, the canvas is initially transferred to the proxied thread (AFAIK, due to the special 4294967295 value in the code), and it successfully works on thread 3's creation requesting a canvas.

But in this case,

Main Thread -> Proxied Thread (the canvas is transferred) -> Thread 2 Creation -> Thread 3 Creation with attr

It is printing the above errors. It has something to do with the fact that the Thread 3 canvas transferring process it detects that the canvas was already transferred, which is correct, but to the main thread, not thread 2 or any other thread.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants