emscripten-core / emscripten-core/emscripten
Namespace-level thread can cause other threads to not start sometimes
- Dominant language
- C++
- Stars
- 27.6k
- Forks
- 3.6k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 105
Description
**Version of emscripten/emsdk:**
```
3.1.46
```
**Failing command line in full:**
The script will build and run the page, refreshing until the thread fails to start for some time. Due to the namespace-level object, it is random whether `runThread()` runs successfully. When it breaks, it seems to deadlock when attempting to execute the `cout` line.
```
#!/bin/sh
set -e
set -v
cat << EOF > mywrapper.cpp
#include
#include
#include
class MyWrapper
{
public:
explicit MyWrapper();
~MyWrapper();
bool isThreadReady() const;
private:
void runThread();
std::unique_ptr m_ThreadPtr;
std::atomic_bool m_IsThreadReady;
};
#include
#include
struct StaticInitStruct
{
StaticInitStruct() : m_thread_id(0)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 1024 * 1024);
const int thread_created = pthread_create(&m_thread_id, &attr, _start, this);
pthread_attr_destroy(&attr);
}
static void* _start(void* context)
{
std::cout << "STARTED\n";
return nullptr;
}
pthread_t m_thread_id;
};
int i1;
std::string s1;
std::string s2;
int i2;
std::string s3;
std::string s4;
unsigned int s5;
StaticInitStruct statInit;
int main(int argc, char** argv)
{
return 0;
}
MyWrapper::MyWrapper() :
m_IsThreadReady(false)
{
m_ThreadPtr.reset(
new std::thread(&MyWrapper::runThread, this));
}
MyWrapper::~MyWrapper()
{
if (m_ThreadPtr)
{
m_ThreadPtr->join();
m_ThreadPtr.reset();
}
}
void MyWrapper::runThread()
{
std::cout << "runThread\n";
m_IsThreadReady.store(true);
}
bool MyWrapper::isThreadReady() const
{
return m_IsThreadReady.load();
}
// clang-format off
EMSCRIPTEN_BINDINGS(my_wrapper)
{
emscripten::class_("MyWrapper")
.constructor()
.function("isThreadReady", &MyWrapper::isThreadReady)
;
}
// clang-format on
EOF
cat << EOF > index.html
</head>
<body>
<script>
console.log("Get started");
MyWrapperModule().then(module => {
var wrapper = new module.MyWrapper();
var refreshPageNow = false;
setTimeout(() => {
refreshPageNow = true;
}, 1750);
var threadCheckInterval = setInterval(() => {
if (wrapper.isThreadReady())
{
console.trace("READY");
clearInterval(threadCheckInterval);
location.reload();
} else if (refreshPageNow) {
console.log("BROKEN");
clearInterval(threadCheckInterval);
document.getElementById("result").innerHTML = "BROKEN";
} else {
console.log("WAIT");
}
}, 500);
});
TESTING
EOF
cat << EOF > pre.js
Module['mainScriptUrlOrBlob'] = self.location.origin + '/myWrapperModule.js';
EOF
em++ -sUSE_PTHREADS -fwasm-exceptions -O2 -g -o mywrapper.cpp.o -c mywrapper.cpp
em++ -sUSE_PTHREADS -fwasm-exceptions -O2 -g -sWASM=1 \
-sPROXY_TO_PTHREAD -sINITIAL_MEMORY=128MB -sPTHREAD_POOL_SIZE=1 -sMODULARIZE=1 \
-sEXPORT_NAME=MyWrapperModule --pre-js=pre.js --minify=0 --bind \
-sENVIRONMENT=web,worker mywrapper.cpp.o -o myWrapperModule.js
emrun index.html
```
This likely can't be made to work, so it should maybe be documented, diagnosed and possibly fail-early if pthread_create is called before `main()`.
Contributor guide
Assessment
This issue has not been assessed yet.