//! Atomic intrinsics are implemented using a global lock for now, as Cranelift doesn't support //! atomic operations yet. // FIXME implement atomic instructions in Cranelift. use crate::prelude::*; #[cfg(all(feature = "jit", unix))] #[no_mangle] static mut __cg_clif_global_atomic_mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; pub(crate) fn init_global_lock( module: &mut impl Module, bcx: &mut FunctionBuilder<'_>, use_jit: bool, ) { if use_jit { // When using JIT, dylibs won't find the __cg_clif_global_atomic_mutex data object defined here, // so instead we define it in the cg_clif dylib. return; } let mut data_ctx = DataContext::new(); data_ctx.define_zeroinit(1024); // 1024 bytes should be big enough on all platforms. data_ctx.set_align(16); let atomic_mutex = module .declare_data( "__cg_clif_global_atomic_mutex", Linkage::Export, true, false, ) .unwrap(); module.define_data(atomic_mutex, &data_ctx).unwrap(); let pthread_mutex_init = module .declare_function( "pthread_mutex_init", Linkage::Import, &cranelift_codegen::ir::Signature { call_conv: module.target_config().default_call_conv, params: vec![ AbiParam::new( module.target_config().pointer_type(), /* *mut pthread_mutex_t */ ), AbiParam::new( module.target_config().pointer_type(), /* *const pthread_mutex_attr_t */ ), ], returns: vec![AbiParam::new(types::I32 /* c_int */)], }, ) .unwrap(); let pthread_mutex_init = module.declare_func_in_func(pthread_mutex_init, bcx.func); let atomic_mutex = module.declare_data_in_func(atomic_mutex, bcx.func); let atomic_mutex = bcx .ins() .global_value(module.target_config().pointer_type(), atomic_mutex); let nullptr = bcx.ins().iconst(module.target_config().pointer_type(), 0); bcx.ins().call(pthread_mutex_init, &[atomic_mutex, nullptr]); } pub(crate) fn init_global_lock_constructor( module: &mut impl Module, constructor_name: &str, ) -> FuncId { let sig = Signature::new(CallConv::SystemV); let init_func_id = module .declare_function(constructor_name, Linkage::Export, &sig) .unwrap(); let mut ctx = Context::new(); ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig); { let mut func_ctx = FunctionBuilderContext::new(); let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); let block = bcx.create_block(); bcx.switch_to_block(block); crate::atomic_shim::init_global_lock(module, &mut bcx, false); bcx.ins().return_(&[]); bcx.seal_all_blocks(); bcx.finalize(); } module .define_function( init_func_id, &mut ctx, &mut cranelift_codegen::binemit::NullTrapSink {}, ) .unwrap(); init_func_id } pub(crate) fn lock_global_lock(fx: &mut FunctionCx<'_, '_, impl Module>) { let atomic_mutex = fx .cx .module .declare_data( "__cg_clif_global_atomic_mutex", Linkage::Import, true, false, ) .unwrap(); let pthread_mutex_lock = fx .cx .module .declare_function( "pthread_mutex_lock", Linkage::Import, &cranelift_codegen::ir::Signature { call_conv: fx.cx.module.target_config().default_call_conv, params: vec![AbiParam::new( fx.cx.module.target_config().pointer_type(), /* *mut pthread_mutex_t */ )], returns: vec![AbiParam::new(types::I32 /* c_int */)], }, ) .unwrap(); let pthread_mutex_lock = fx .cx .module .declare_func_in_func(pthread_mutex_lock, fx.bcx.func); let atomic_mutex = fx.cx.module.declare_data_in_func(atomic_mutex, fx.bcx.func); let atomic_mutex = fx .bcx .ins() .global_value(fx.cx.module.target_config().pointer_type(), atomic_mutex); fx.bcx.ins().call(pthread_mutex_lock, &[atomic_mutex]); } pub(crate) fn unlock_global_lock(fx: &mut FunctionCx<'_, '_, impl Module>) { let atomic_mutex = fx .cx .module .declare_data( "__cg_clif_global_atomic_mutex", Linkage::Import, true, false, ) .unwrap(); let pthread_mutex_unlock = fx .cx .module .declare_function( "pthread_mutex_unlock", Linkage::Import, &cranelift_codegen::ir::Signature { call_conv: fx.cx.module.target_config().default_call_conv, params: vec![AbiParam::new( fx.cx.module.target_config().pointer_type(), /* *mut pthread_mutex_t */ )], returns: vec![AbiParam::new(types::I32 /* c_int */)], }, ) .unwrap(); let pthread_mutex_unlock = fx .cx .module .declare_func_in_func(pthread_mutex_unlock, fx.bcx.func); let atomic_mutex = fx.cx.module.declare_data_in_func(atomic_mutex, fx.bcx.func); let atomic_mutex = fx .bcx .ins() .global_value(fx.cx.module.target_config().pointer_type(), atomic_mutex); fx.bcx.ins().call(pthread_mutex_unlock, &[atomic_mutex]); }