1const std = @import("std.zig"); 2const target = @import("builtin").target; 3 4pub const Ordering = std.builtin.AtomicOrder; 5 6pub const Stack = @import("atomic/stack.zig").Stack; 7pub const Queue = @import("atomic/queue.zig").Queue; 8pub const Atomic = @import("atomic/Atomic.zig").Atomic; 9 10test "std.atomic" { 11 _ = @import("atomic/stack.zig"); 12 _ = @import("atomic/queue.zig"); 13 _ = @import("atomic/Atomic.zig"); 14} 15 16pub inline fn fence(comptime ordering: Ordering) void { 17 switch (ordering) { 18 .Acquire, .Release, .AcqRel, .SeqCst => { 19 @fence(ordering); 20 }, 21 else => { 22 @compileLog(ordering, " only applies to a given memory location"); 23 }, 24 } 25} 26 27pub inline fn compilerFence(comptime ordering: Ordering) void { 28 switch (ordering) { 29 .Acquire, .Release, .AcqRel, .SeqCst => asm volatile ("" ::: "memory"), 30 else => @compileLog(ordering, " only applies to a given memory location"), 31 } 32} 33 34test "fence/compilerFence" { 35 inline for (.{ .Acquire, .Release, .AcqRel, .SeqCst }) |ordering| { 36 compilerFence(ordering); 37 fence(ordering); 38 } 39} 40 41/// Signals to the processor that the caller is inside a busy-wait spin-loop. 42pub inline fn spinLoopHint() void { 43 switch (target.cpu.arch) { 44 // No-op instruction that can hint to save (or share with a hardware-thread) 45 // pipelining/power resources 46 // https://software.intel.com/content/www/us/en/develop/articles/benefitting-power-and-performance-sleep-loops.html 47 .i386, .x86_64 => asm volatile ("pause" ::: "memory"), 48 49 // No-op instruction that serves as a hardware-thread resource yield hint. 50 // https://stackoverflow.com/a/7588941 51 .powerpc64, .powerpc64le => asm volatile ("or 27, 27, 27" ::: "memory"), 52 53 // `isb` appears more reliable for releasing execution resources than `yield` 54 // on common aarch64 CPUs. 55 // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8258604 56 // https://bugs.mysql.com/bug.php?id=100664 57 .aarch64, .aarch64_be, .aarch64_32 => asm volatile ("isb" ::: "memory"), 58 59 // `yield` was introduced in v6k but is also available on v6m. 60 // https://www.keil.com/support/man/docs/armasm/armasm_dom1361289926796.htm 61 .arm, .armeb, .thumb, .thumbeb => { 62 const can_yield = comptime std.Target.arm.featureSetHasAny(target.cpu.features, .{ 63 .has_v6k, .has_v6m, 64 }); 65 if (can_yield) { 66 asm volatile ("yield" ::: "memory"); 67 } else { 68 asm volatile ("" ::: "memory"); 69 } 70 }, 71 // Memory barrier to prevent the compiler from optimizing away the spin-loop 72 // even if no hint_instruction was provided. 73 else => asm volatile ("" ::: "memory"), 74 } 75} 76 77test "spinLoopHint" { 78 var i: usize = 10; 79 while (i > 0) : (i -= 1) { 80 spinLoopHint(); 81 } 82} 83