| ... | @@ -99,13 +99,30 @@ comptime { | ... | @@ -99,13 +99,30 @@ comptime { |
| 99 | // LLVM emits those iff the object size is known and the pointers are correctly | 99 | // LLVM emits those iff the object size is known and the pointers are correctly |
| 100 | // aligned. | 100 | // aligned. |
| 101 | | 101 | |
| 102 | // The size (in bytes) of the biggest object that the architecture can access | 102 | // The size (in bytes) of the biggest object that the architecture can |
| 103 | // atomically. Objects bigger than this threshold require the use of a lock. | 103 | // load/store atomically. |
| | 104 | // Objects bigger than this threshold require the use of a lock. |
| 104 | const largest_atomic_size = switch (builtin.arch) { | 105 | const largest_atomic_size = switch (builtin.arch) { |
| 105 | .x86_64 => 16, | 106 | .x86_64 => 16, |
| 106 | else => @sizeOf(usize), | 107 | else => @sizeOf(usize), |
| 107 | }; | 108 | }; |
| 108 | | 109 | |
| | 110 | // The size (in bytes) of the biggest object that the architecture can perform |
| | 111 | // an atomic CAS operation with. |
| | 112 | // Objects bigger than this threshold require the use of a lock. |
| | 113 | const largest_atomic_cas_size = switch (builtin.arch) { |
| | 114 | .arm, .armeb, .thumb, .thumbeb => |
| | 115 | // The ARM v6m ISA has no ldrex/strex and so it's impossible to do CAS |
| | 116 | // operations unless we're targeting Linux or the user provides the missing |
| | 117 | // builtin functions. |
| | 118 | if (std.Target.arm.featureSetHas(std.Target.current.cpu.features, .has_v6m) and |
| | 119 | std.Target.current.os.tag != .linux) |
| | 120 | 0 |
| | 121 | else |
| | 122 | @sizeOf(usize), |
| | 123 | else => @sizeOf(usize), |
| | 124 | }; |
| | 125 | |
| 109 | fn atomicLoadFn(comptime T: type) fn (*T, i32) callconv(.C) T { | 126 | fn atomicLoadFn(comptime T: type) fn (*T, i32) callconv(.C) T { |
| 110 | return struct { | 127 | return struct { |
| 111 | fn atomic_load_N(src: *T, model: i32) callconv(.C) T { | 128 | fn atomic_load_N(src: *T, model: i32) callconv(.C) T { |
| ... | @@ -151,7 +168,7 @@ comptime { | ... | @@ -151,7 +168,7 @@ comptime { |
| 151 | fn atomicExchangeFn(comptime T: type) fn (*T, T, i32) callconv(.C) T { | 168 | fn atomicExchangeFn(comptime T: type) fn (*T, T, i32) callconv(.C) T { |
| 152 | return struct { | 169 | return struct { |
| 153 | fn atomic_exchange_N(ptr: *T, val: T, model: i32) callconv(.C) T { | 170 | fn atomic_exchange_N(ptr: *T, val: T, model: i32) callconv(.C) T { |
| 154 | if (@sizeOf(T) > largest_atomic_size) { | 171 | if (@sizeOf(T) > largest_atomic_cas_size) { |
| 155 | var sl = spinlocks.get(@ptrToInt(ptr)); | 172 | var sl = spinlocks.get(@ptrToInt(ptr)); |
| 156 | defer sl.release(); | 173 | defer sl.release(); |
| 157 | const value = ptr.*; | 174 | const value = ptr.*; |
| ... | @@ -174,7 +191,7 @@ comptime { | ... | @@ -174,7 +191,7 @@ comptime { |
| 174 | fn atomicCompareExchangeFn(comptime T: type) fn (*T, *T, T, i32, i32) callconv(.C) i32 { | 191 | fn atomicCompareExchangeFn(comptime T: type) fn (*T, *T, T, i32, i32) callconv(.C) i32 { |
| 175 | return struct { | 192 | return struct { |
| 176 | fn atomic_compare_exchange_N(ptr: *T, expected: *T, desired: T, success: i32, failure: i32) callconv(.C) i32 { | 193 | fn atomic_compare_exchange_N(ptr: *T, expected: *T, desired: T, success: i32, failure: i32) callconv(.C) i32 { |
| 177 | if (@sizeOf(T) > largest_atomic_size) { | 194 | if (@sizeOf(T) > largest_atomic_cas_size) { |
| 178 | var sl = spinlocks.get(@ptrToInt(ptr)); | 195 | var sl = spinlocks.get(@ptrToInt(ptr)); |
| 179 | defer sl.release(); | 196 | defer sl.release(); |
| 180 | const value = ptr.*; | 197 | const value = ptr.*; |
| ... | @@ -205,7 +222,7 @@ comptime { | ... | @@ -205,7 +222,7 @@ comptime { |
| 205 | fn fetchFn(comptime T: type, comptime op: builtin.AtomicRmwOp) fn (*T, T, i32) callconv(.C) T { | 222 | fn fetchFn(comptime T: type, comptime op: builtin.AtomicRmwOp) fn (*T, T, i32) callconv(.C) T { |
| 206 | return struct { | 223 | return struct { |
| 207 | pub fn fetch_op_N(ptr: *T, val: T, model: i32) callconv(.C) T { | 224 | pub fn fetch_op_N(ptr: *T, val: T, model: i32) callconv(.C) T { |
| 208 | if (@sizeOf(T) > largest_atomic_size) { | 225 | if (@sizeOf(T) > largest_atomic_cas_size) { |
| 209 | var sl = spinlocks.get(@ptrToInt(ptr)); | 226 | var sl = spinlocks.get(@ptrToInt(ptr)); |
| 210 | defer sl.release(); | 227 | defer sl.release(); |
| 211 | | 228 | |