You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In multithreading environment using `emscripten::val` is very error-prone and hard to debug. The reason for that is that, on one hand, `val` represents JavaScript values which cannot be (easily) shared between threads, but, on another, `val` itself is a thin wrapper around an integer handle which can be shared across threads way too easily.
As a result, accessing `val` from the wrong thread sometimes succeeds by accident (such as for built-in constants like `undefined`/`false`/`true`), sometimes crashes with invalid handle, and sometimes just quietly returns completely different JS value because a handle with the same ID happened to be valid on both threads, but points to different underlying values.
In the last scenario code can even keep going forward for some time, using and making changes on the incorrect JS value before it's apparent that something went very wrong.
To make it easier to catch such cases, in this PR I'm adding a `pthread_t` field to the `val` class that stores the owner thread of the given handle. User can still store `val` and send it across threads, but the moment they try to operate on the underlying JS value on the wrong thread, an assertion will fire with a clear message.
This check is activated only when code is compiled with pthread support, and only if user didn't disable assertions via `NDEBUG` (we can't use the `-sASSERTIONS` setting here because it's a header not compiled code). This still adds a tiny size overhead if the user is not passing `-DNDEBUG`, but typical build systems (e.g. CMake) pass it automatically in release builds, and overall I believe benefits outweigh the overhead in this scenario.
In the future we might also automatically proxy all operations to the correct thread so that `emscripten::val` behaves like any other native object. However, that's out of scope of this particular PR, so for now just laying the groundwork and making those failure scenarios more visible.
// If code is not being compiled with GNU extensions enabled, typeof() is not a reserved keyword, so support that as a member function.
570
573
#if __STRICT_ANSI__
571
574
val typeof() const {
572
-
returnval(internal::_emval_typeof(handle));
575
+
returnval(internal::_emval_typeof(as_handle()));
573
576
}
574
577
#endif
575
578
576
579
// Prefer calling val::typeOf() over val::typeof(), since this form works in both C++11 and GNU++11 build modes. "typeof" is a reserved word in GNU++11 extensions.
0 commit comments