diff --git a/src/engine/engine_crossplatform.h b/src/engine/engine_crossplatform.h index ee9ad61c..7fa8478b 100644 --- a/src/engine/engine_crossplatform.h +++ b/src/engine/engine_crossplatform.h @@ -69,6 +69,16 @@ #endif #endif +// Atomics helper for size_t. +#if defined(_MSC_VER) && !defined(__clang__) + #include + #define mj_atomic_add_size_t(ptr, val) \ + (size_t)_InterlockedExchangeAdd64((__int64 volatile*)(ptr), (__int64)(val)) +#else + #define mj_atomic_add_size_t(ptr, val) \ + __atomic_fetch_add(ptr, val, __ATOMIC_RELAXED) +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/src/engine/engine_memory.c b/src/engine/engine_memory.c index 9ecdea1e..d0c044e0 100644 --- a/src/engine/engine_memory.c +++ b/src/engine/engine_memory.c @@ -16,7 +16,6 @@ #include // IWYU pragma: keep #include -#include #include #include #include @@ -216,8 +215,7 @@ static inline void* stackalloc(mjData* d, size_t size, size_t alignment, // call in mju_dispatch: atomically reserve space on the stack if (d->threadlock) { size_t alloc_size = size + alignment - 1 + 2 * mjREDZONE; - size_t old_pstack = atomic_fetch_add_explicit( - (_Atomic size_t*)&d->pstack, alloc_size, memory_order_relaxed); + size_t old_pstack = mj_atomic_add_size_t(&d->pstack, alloc_size); // check for stack overflow size_t stack_available_bytes = (size_t)d->narena - d->parena; diff --git a/src/engine/engine_thread.cc b/src/engine/engine_thread.cc index 3f521d21..7eeae5cb 100644 --- a/src/engine/engine_thread.cc +++ b/src/engine/engine_thread.cc @@ -24,6 +24,10 @@ #include #include "engine/engine_memory.h" +#if defined(__cpp_lib_atomic_wait) + +// ----------------------------- multithreaded implementation -------------------------------------- + // context for thread pool stored on mjData class ThreadPoolContext { public: @@ -129,7 +133,6 @@ class ThreadPoolContext { }; - // create a thread pool with nthread threads void mju_threadpool(mjData* d, int nthread) { if (d->threadpool) { @@ -188,3 +191,23 @@ int mju_numThread(const mjData* d) { ThreadPoolContext* ctx = reinterpret_cast(d->threadpool); return ctx ? ctx->ThreadCount() + 1 : 1; } + +#else + +// -------------------------------------- fallback ------------------------------------------------ + +void mju_threadpool(mjData* d, int nthread) { + // No-op +} + +void mju_dispatch(const mjModel* m, mjData* d, mjTaskFunc func, void* arg, int ntask) { + for (int i = 0; i < ntask; i++) { + func(m, d, arg, 0, i); + } +} + +int mju_numThread(const mjData* d) { + return 1; +} + +#endif // __cpp_lib_atomic_wait