Files
Mujoco_WASM/src/engine/engine_crossplatform.h
T
Georg Ostrovski bb80b55ae1 Fix data race in mju_getLogConfigPtr lazy init
The lazy init of log_config used a single atomic flag (env_checked) with
a load-then-store pattern, allowing two threads to both enter the init
path and concurrently write to the non-atomic log_config.topics field.

Replace with a two-phase atomic init: an atomic exchange on
env_init_claimed ensures exactly one thread enters the init, while
env_init_done (with acquire/release semantics) signals completion and
provides the happens-before edge that makes log_config writes visible to
other threads.

Also adds mj_atomic_exchange_bool to engine_crossplatform.h (both MSVC
and GCC/Clang variants).

PiperOrigin-RevId: 941202181
Change-Id: I59b6801c7b4b8b0e1647d82d2aeb534a90fb66fb
2026-07-01 11:24:36 -07:00

116 lines
3.4 KiB
C

// Copyright 2021 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MUJOCO_SRC_ENGINE_ENGINE_CROSSPLATFORM_H_
#define MUJOCO_SRC_ENGINE_ENGINE_CROSSPLATFORM_H_
// IWYU pragma: begin_keep
#if !defined(__cplusplus)
#include <stddef.h>
#include <stdlib.h>
#else
#include <cstddef>
#include <cstdlib>
#endif
// IWYU pragma: end_keep
// Case-insensitive comparison functions.
#ifdef _WIN32
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#else // assumes POSIX
#include <strings.h>
#endif
// Environment variable handling.
#ifdef _WIN32
#define setenv(name, value, overwrite) _putenv_s(name, value)
#define unsetenv(name) _putenv_s(name, "")
#endif
// Switch-case fallthrough annotation.
#if defined(__cplusplus)
#define mjFALLTHROUGH [[fallthrough]]
#elif defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 7)
#define mjFALLTHROUGH __attribute__((fallthrough))
#else
#define mjFALLTHROUGH ((void) 0)
#endif
// MSVC only provides max_align_t in C++.
#if defined(_MSC_VER) && !defined(__clang__) && !defined(__cplusplus)
typedef long double mjtMaxAlign;
#else
typedef max_align_t mjtMaxAlign;
#endif
// Branch prediction hints.
#if defined(__GNUC__)
#define mjLIKELY(x) __builtin_expect(!!(x), 1)
#define mjUNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define mjLIKELY(x) (x)
#define mjUNLIKELY(x) (x)
#endif
// Define ADDRESS_SANITIZER if implied by other macros.
#if !defined(ADDRESS_SANITIZER)
#if defined(__SANITIZE_ADDRESS__)
#define ADDRESS_SANITIZER
#elif defined(__has_feature)
#if __has_feature(address_sanitizer)
#define ADDRESS_SANITIZER
#endif
#endif
#endif
// Atomics helper for size_t.
#if defined(_MSC_VER) && !defined(__clang__)
#include <intrin.h>
#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
// Atomics helpers for mjtBool (1-byte _Bool) with acquire/release semantics.
#if defined(_MSC_VER) && !defined(__clang__)
#define mj_atomic_load_bool(ptr) \
(mjtBool) _InterlockedCompareExchange8((volatile char*)(ptr), 0, 0)
#define mj_atomic_store_bool(ptr, val) \
(void)_InterlockedExchange8((volatile char*)(ptr), (char)(val))
#define mj_atomic_exchange_bool(ptr, val) \
(mjtBool) _InterlockedExchange8((volatile char*)(ptr), (char)(val))
#else
#define mj_atomic_load_bool(ptr) __atomic_load_n(ptr, __ATOMIC_ACQUIRE)
#define mj_atomic_store_bool(ptr, val) __atomic_store_n(ptr, val, __ATOMIC_RELEASE)
#define mj_atomic_exchange_bool(ptr, val) __atomic_exchange_n(ptr, val, __ATOMIC_ACQ_REL)
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef ADDRESS_SANITIZER
int mj__comparePcFuncName(void* pc1, void* pc2);
const char* mj__getPcDebugInfo(void* pc);
#endif
#ifdef __cplusplus
} // extern "C"
#endif
#endif // MUJOCO_SRC_ENGINE_ENGINE_CROSSPLATFORM_H_