bytecodealliance / wasm-micro-runtime

WebAssembly Micro Runtime (WAMR)
Apache License 2.0
4.96k stars 624 forks source link

How can I use thread with emsdk and wamr #947

Open xingkaiyu opened 2 years ago

xingkaiyu commented 2 years ago

I want to use c++ std::thread and atomic in wasm file but wasi does not support them yet. So I want to try emsdk as I see your sample of tensorflow. But I always get failed when I try my own code. I used WAMR-12-30-2021 and have enable WAMR_BUILD_LIB_PTHREAD, WAMR_BUILD_LIBC_EMCC and WAMR_BUILD_LIBC_UVWASI when building linux wamr. And I removed open.o, mmap.o and munmap.o in emsdk's libc.a. When building wasm app, I add -mbulk-memory, -matomics and other params almost like tf_lite.patch. I got 6 when call pthread_create and got throw_system_error when use std::thread. I also test EMCC_ONLY_FORCED_STDLIBS=1 and MALLOC="none". But will got "unlinked import function" error. My code (including linux CMakelist.txt) is attached. emcc_thread.zip

xujuntwt95329 commented 2 years ago

Hi, @xingkaiyu

Thanks for providing your test case and build script. I reproduced this issue on my machine, I find that the wasm module generated by em++ doesn't call pthread_create_wrapper at all. Then I searched emcc's libc.a, I find that there is a file named library_pthread_stub.o which contains some empty implementation of pthread functions:

0001bc func[23] <pthread_create>:
 0001bd: 41 06                      | i32.const 6
 0001bf: 0b                         | end
0001c1 func[24] <pthread_join>:
 0001c2: 41 1c                      | i32.const 28
 0001c4: 0b                         | end

This is why the pthread_create return 6 in your code.

To let your code work, here are some steps:

  1. remove the library_pthread_stub.o from emcc's libc.a

    cd ${EMSDK_PATH}/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten
    cp libc.a libc.a.back # backup original libc.a
    emar d libc.a library_pthread_stub.o
    emranlib libc.a
  2. implement some missing wrappers in wamr

    • emcc++ generated wasm module will call pthread_cond_broadcast during global construction, which is not supported by wamr currently. So we need to implement it
    • emcc++ generated wasm module call __pthread_self rather than pthread_self, so we need to add a wrapper named __pthread_self

    I write this two wrapper for linux platform, you can use this patch and rebuild iwasm: patch.tar.gz

    cd ${wamr_repo}
    git apply path/to/enable_pthread_cond_broadcast.patch

    I'll submit a PR later because I need to do some test for other platforms

  3. enable shared-memory feature in your build script

    You can use this one:

    em++ -g -s STANDALONE_WASM=1 \
        -o emcc_thread.wasm src/main.cpp \
        -s EXPORTED_FUNCTIONS=[___wasm_call_ctors,_main] \
        -s ERROR_ON_UNDEFINED_SYMBOLS=0 \
        -s TOTAL_STACK=1048576 \
        -s INITIAL_MEMORY=16777216 \
        -s MAXIMUM_MEMORY=167772160 \
        -s ALLOW_MEMORY_GROWTH=1 \
        -s EXPORTED_FUNCTIONS=[___data_end,___heap_base] \
        -Wl,--shared-memory,--no-check-features \
        -mbulk-memory -matomics

Hope you can get your code work according to these steps. Let me know if you encountered any problem

xujuntwt95329 commented 2 years ago

I've updated the emcc compilation command in the document

982

ghhbgtf commented 2 years ago

@xujuntwt95329 I have tried above with C code and it worked fine, but C++ did't _(pthreadcreate return error code 6 still). Should I modify other '.a' file rather than 'libc.a' ?

xujuntwt95329 commented 2 years ago

Yes, maybe em++ link some other libraries with empty pthread_create, you can check if there are any other libs containing pthread_create under ${EMSDK_PATH}/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten