-static LIBC_MUTEX_KIND_OFFSET_CACHE: AtomicU64 = AtomicU64::new(0);
-
-fn libc_mutex_kind_offset<'mir, 'tcx: 'mir>(
- ecx: &mut MiriEvalContext<'mir, 'tcx>,
-) -> InterpResult<'tcx, u64> {
- // Check if this offset has already been found and memoized
- let cached_value = LIBC_MUTEX_KIND_OFFSET_CACHE.load(Ordering::Relaxed);
- if cached_value != 0 {
- return Ok(cached_value);
- }
-
- // This function infers the offset of the `kind` field of libc's pthread_mutex_t
- // C struct by examining the array inside libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP.
- // At time of writing, it is always all zero bytes except for a one byte at one of
- // four positions, depending on the target OS's C struct layout and the endianness of the
- // target architecture. This offset will then be used in getters and setters below, so that
- // mutexes created from static initializers can be emulated with the correct behavior.
- let initializer_path = ["libc", "PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP"];
- let initializer_instance = ecx.resolve_path(&initializer_path);
- let initializer_cid = GlobalId { instance: initializer_instance, promoted: None };
- let initializer_const_val = ecx.const_eval_raw(initializer_cid)?;
- let array_mplacety = ecx.mplace_field(initializer_const_val, 0)?;
- let array_length = match array_mplacety.layout.fields {
- FieldsShape::Array { count, .. } => count,
- _ => bug!("Couldn't get array length from type {:?}", array_mplacety.layout.ty),
- };
-
- let kind_offset = if array_length < 20 {
- bug!("libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP array was shorter than expected");
- } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 16)?.into())?.to_u8()? != 0 {
- // for little-endian architectures
- 16
- } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 19)?.into())?.to_u8()? != 0 {
- // for big-endian architectures
- // (note that the i32 spans bytes 16 through 19, so the offset of the kind field is 16)
- 16
- } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 12)?.into())?.to_u8()? != 0 {
- // for little-endian architectures
- 12
- } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 15)?.into())?.to_u8()? != 0 {
- // for big-endian architectures
- // (note that the i32 spans bytes 12 through 15, so the offset of the kind field is 12)
- 12
- } else {
- bug!("Couldn't determine offset of `kind` in pthread_mutex_t");
- };
-
- // Save offset to memoization cache for future calls
- LIBC_MUTEX_KIND_OFFSET_CACHE.store(kind_offset, Ordering::Relaxed);
- Ok(kind_offset)
-}
-