Open yangfangfang1204 opened 3 years ago
I use 'emscripten_cancel_main_loop();' and -s EXIT_RUNTIME=0
;
when the thread exit , there is an error uncaught unwind
?
I believe the message you are seeing in from the resize_offscreencanvas_from_main_thread.cpp
test is just a warning isn't it?
I imagine we could fix that by adding -s EXIT_RUNTIME
to that test.
emscripten_set_main_loop is actually the function that will throw "unwind" if you call it with simulateInfiniteLoop = true
. Normally emscripten_cancel_main_loop
is called from a try/catch context that can handle the "unwind" so it appear as "uncaught", can you post your backtrace so we can see why that is not that case for your example?
resize_offscreencanvas_from_main_thread.cpp:
`#include <pthread.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <emscripten.h>
#include <emscripten/html5.h>
#include <emscripten/threading.h>
#include <unistd.h>
// Tests that the size of an OffscreenCanvas can be queried and set from the main thread.
// Supporting this is needed since it is very common to resize Canvas size on main thread while relayouting DOM in JavaScript code.
// Define the following to test the scenario where the pthread that owns the OffscreenCanvas is running its own synchronously blocking loop (never yields to event loop).
// If not defined, the pthread that owns the OffscreenCanvas is using emscripten_set_main_loop() so periodically yields back to the event loop.
//#define TEST_SYNC_BLOCKING_LOOP
void thread_local_main_loop()
{
int w = 0, h = 0;
emscripten_get_canvas_element_size("#canvas", &w, &h);
if (w == 699 && h == 299)
{
printf("Observed OffscreenCanvas resize to 699x299 from main thread! Test passed!\n");
#ifdef REPORT_RESULT
REPORT_RESULT(1);
#endif
#ifndef TEST_SYNC_BLOCKING_LOOP
emscripten_cancel_main_loop();
#endif
emscripten_force_exit(0);
}
printf("%dx%d\n", w, h);
}
void *thread_main(void *arg)
{
EmscriptenWebGLContextAttributes attr;
emscripten_webgl_init_context_attributes(&attr);
attr.explicitSwapControl = EM_TRUE;
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context("#canvas", &attr);
assert(ctx);
// To start off, change the size of the OffscreenCanvas, main thread will test that it sees this change.
printf("pthread resizing OffscreenCanvas to size 355x233.\n");
emscripten_set_canvas_element_size("#canvas", 355, 233);
// In pthread, keep polling the canvas size until we see it being changed from the main thread.
#ifdef TEST_SYNC_BLOCKING_LOOP
for(;;)
{
//thread_local_main_loop();
int w = 0, h = 0;
emscripten_get_canvas_element_size("#canvas", &w, &h);
printf("%dx%d\n", w, h);
if (w == 699 && h == 299)
{
break;
}
emscripten_current_thread_process_queued_calls();
usleep(16*1000);
}
#else
emscripten_set_main_loop(thread_local_main_loop, 1, 0);
#endif
return 0;
}
void resize_canvas(void *)
{
// Test that on the main thread, we can observe size changes to the canvas size.
int w, h;
emscripten_get_canvas_element_size("#canvas", &w, &h);
assert(w == 355 && "We did not observe the effect of pthread having resized OffscreenCanvas");
assert(h == 233);
printf("Main thread saw canvas to get resized to %dx%d.\n", w, h);
// Test that on the main thread, we can also change the size. (pthread listens to see this)
printf("Main thread resizing OffscreenCanvas to size 699x299.\n");
emscripten_set_canvas_element_size("#canvas", 699, 299);
}
//should be able to do this regardless of offscreen canvas support
void get_canvas_size()
{
int w, h;
emscripten_get_canvas_element_size("#canvas", &w, &h);
assert(h == 150);
assert(w == 300);
}
int main()
{
get_canvas_size();
if (!emscripten_supports_offscreencanvas())
{
printf("Current browser does not support OffscreenCanvas. Skipping the rest of the tests.\n");
#ifdef REPORT_RESULT
REPORT_RESULT(1);
#endif
return 0;
}
pthread_attr_t attr;
pthread_attr_init(&attr);
emscripten_pthread_attr_settransferredcanvases(&attr, "#canvas");
pthread_t thread;
printf("Creating thread.\n");
pthread_create(&thread, &attr, thread_main, NULL);
pthread_detach(thread);
// Wait for a while, then change the canvas size on the main thread.
printf("Waiting for 5 seconds for good measure.\n");
emscripten_async_call(resize_canvas, 0, 5000);
return 1;
}
Secode compile script is
emcc resize_offscreencanvas_from_main_thread.cpp -o resize_offscreencanvas_from_main_thread.html -s USE_PTHREADS=1 -s TOTAL_MEMORY=1000MB -s ALLOW_MEMORY_GROWTH=0 -s MAX_WEBGL_VERSION=2 -s OFFSCREENCANVAS_SUPPORT=1 -s PTHREAD_POOL_SIZE=2 -s EXIT_RUNTIME=1
Then run the resize_offscreencanvas_from_main_thread.html in chrome .
there is a error(not warning):
main thread called exit: keepRuntimeAlive=false (counter=0)
i haven't know how to post my backtrace , i am learning , and could you tell me keepRuntimeAlive=false (counter=0) , how to solve the error?
thanks for the sample code. I'll try to take a look later.
On first inspection it looks like keepRuntimeAlive
should be true because the emscripten_async_call
should increment that counter. So perhaps there is a bug in emscripten_async_call
I believe everything you are seeing is expected behaviour. When the program calls exit()
or emscripten_force_exit()
will see an exception flow out the top level. If you want to program to keep going then you don't call exit()
or emscripten_force_exit()
and you won't see any uncaught exception.
Perhaps you can describe the behaviour you expect to see or the behaviour that you want instead?
I want to exit a detachable thread, when using pthread_exit(0), there is a error "Uncaught ExitStatus {name: "ExitStatus", message: "Program terminated with exit(0)", status: 0}"; so how exit a detachable subThread ?
Can you describe you use case a little more precisely or post some example code.
Tell me if I understand what you are trying to do: You want to create and detach a pthread, then you want your main application to continue to run and have your detached thread exit using pthread_exit
.
If you want your main thread to keep running after it returns you should not set EXIT_RUNTIME=1
setting this option means that the entire application will exit when the main thread returns. Alternatively you can call emscripten_exit_with_live_runtime
to keep the application running after the main function returns.
Where does emscripten_force_exit()
come into play in your application?
As discussed earlier,the example code is resize_offscreencanvas_from_main_thread.cpp
,The function of this CPP is to create a detachable child thread in the main thread.The main thread changes the size of the canvas. When the child thread detects that the canvas size has changed, the child thread exits.The problem is that when the child thread exits using emscripten_force_exit(0), it returns an error. If set EXIT_RUNTIME=1
, the error is main thread called exit: keepRuntimeAlive=false (counter=0)
, if not set EXIT_RUNTIME=1
, the error is Uncaught ExitStatus {name: "ExitStatus", message: "Program terminated with exit(0)", status: 0}
there is another example:
SuperRender.cpp:
#include <stdio.h>
#include <stdlib.h>
#include <GLES2/gl2.h>
#include <emscripten.h>
#include <emscripten/html5.h>
#include <emscripten/threading.h>
#include <unistd.h>
#include <iostream>
#include <string>
int g_nStopFlag = 0;
pthread_t thread2;
#ifdef __cplusplus
extern "C"
{
#endif
EMSCRIPTEN_KEEPALIVE
void requestStaticRender()
{
if(g_nStopFlag)
{
emscripten_cancel_main_loop();
emscripten_force_exit(0);//exit the detached thread
}
else
{
printf("detached thread is running\n");
}
return;
}
EMSCRIPTEN_KEEPALIVE
void* displayThread(void* p)
{
emscripten_set_main_loop(requestStaticRender,0,0);
return p;
}
EMSCRIPTEN_KEEPALIVE
int Start() {
if (!emscripten_supports_offscreencanvas())
{
printf("Current browser does not support OffscreenCanvas. Skipping the rest of the tests.\n");
#ifdef REPORT_RESULT
REPORT_RESULT(1);
#endif
return -1;
}
//create offscreencavas
pthread_attr_t attr;
pthread_attr_init(&attr);
emscripten_pthread_attr_settransferredcanvases(&attr, "#canvas");
//create detached thread
pthread_create(&thread2, &attr, displayThread, NULL);
pthread_detach(thread2);
return 1;
}
EMSCRIPTEN_KEEPALIVE
int Stop()
{
g_nStopFlag = 1;
return 1;
}
#ifdef __cplusplus
}
#endif`
Second, compile script:
CC = emcc
AR = emar
CFLAGS = -O3 -Wall
LDFLAGS = --bind -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'getValue','writeArrayToMemory']" -s EXPORTED_FUNCTIONS="['_Start','_Stop']" -s USE_PTHREADS=1 -s TOTAL_MEMORY=1GB -s ALLOW_MEMORY_GROWTH=0 -s MAX_WEBGL_VERSION=2 -s OFFSCREENCANVAS_SUPPORT=1 -s PTHREAD_POOL_SIZE_STRICT=0 -s GL_PREINITIALIZED_CONTEXT=1
SRCS += ./SuperRender.cpp
OBJS = $(patsubst %.cpp,%.o,$(SRCS))
TARGET = SuperRender.js
OBJ_TARGET = SuperRender.a
all: $(TARGET) $(OBJS) $(OBJ_TARGET)
$(OBJ_TARGET):$(OBJS)
$(AR) rcs $(OBJ_TARGET) $(notdir $(OBJS))
$(TARGET): $(OBJ_TARGET)
$(CC) $(OBJ_TARGET) -o $(TARGET) $(LDFLAGS) $(CFLAGS)
.cpp.o:
$(CC) $(CFLAGS) -c $<
clean:
rm -f *.o *.a *.js *.wasm *.worker.js $(OBJS)
rm -rf $(DIR)
Third , test.html:
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<section>
</section>
<button type="button" onClick="start()">Start</button>
<button type="button" onClick="stop()">Stop</button>
<script async type="text/javascript" src="SuperRender.js"></script>
<div class="button_box">
<canvas id="canvas" width="400px" height="200px" style="border: 2px; background-color:black"></canvas>
</div>
<script>
function start () {
Module._Start();
}
function stop()
{
Module._Stop();
}
</script>
</body>
</html>
To summarize, First compiled the SuperRender.cpp into SuperRender js, SuperRender.wasm, SuperRender.worker.js. Second, in the test.html invokes the interface of the cpp, Performs the start and stop operations of a child thread. when stop the child thread there is a error , Uncaught
ExitStatus {name: "ExitStatus", message: "Program terminated with exit(0)", status: 0}`
Can you use pthread_exit()
instead? I believe that emscripten_force_exit()
is designed to being down the entire program. If you just want to exist the current thread I think pthread_exit()
is the was to go.
I tried to exit the thread using pthread_exit, there is a error 'Uncaught unwind'
SuperRender.js:1 pthread sent an error! http://localhost:8081/SuperRender.js:1: Uncaught unwind
worker.onerror @ SuperRender.js:1
error (async)
loadWasmModuleToWorker @ SuperRender.js:1
getNewWorker @ SuperRender.js:1
spawnThread @ SuperRender.js:1
_pthread_create @ SuperRender.js:1
H @ 00017742:0x4337
Module._Start @ SuperRender.js:1
start @ testMT.html:23
onclick @ testMT.html:8
SuperRender.js:1 Uncaught unwind
maybeExit @ SuperRender.js:1
checkIsRunning @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
requestAnimationFrame (async)
requestAnimationFrame @ SuperRender.js:1
Browser_mainLoop_scheduler_rAF @ SuperRender.js:1
Browser_mainLoop_runner @ SuperRender.js:1
![Uploading console.png…]()
I think the uncaught unwind
issue should be fixed in #13666. Can you verify?
when i run the 'emscripten-main\tests\resize_offscreencanvas_from_main_thread.cpp'; and compile it 'emcc resize_offscreencanvas_from_main_thread.cpp -o resize_offscreencanvas_from_main_thread.html -s USE_PTHREADS=1 -s TOTAL_MEMORY=2000MB -s ALLOW_MEMORY_GROWTH=0 -s MAX_WEBGL_VERSION=2 -s OFFSCREENCANVAS_SUPPORT=1' Then run it in chrome,it take a error: 'emscripten_force_exit cannot actually shut down the runtime, as the build does not have EXIT_RUNTIME set; main thread called exit: keepRuntimeAlive=false (counter=0); Program terminated with exit(0);'
could you tell me why