| ... | @@ -24,6 +24,13 @@ const supports_atomic_ops = switch (arch) { | ... | @@ -24,6 +24,13 @@ const supports_atomic_ops = switch (arch) { |
| 24 | // load/store atomically. | 24 | // load/store atomically. |
| 25 | // Objects bigger than this threshold require the use of a lock. | 25 | // Objects bigger than this threshold require the use of a lock. |
| 26 | const largest_atomic_size = switch (arch) { | 26 | const largest_atomic_size = switch (arch) { |
| | 27 | // On SPARC systems that lacks CAS and/or swap instructions, the only |
| | 28 | // available atomic operation is a test-and-set (`ldstub`), so we force |
| | 29 | // every atomic memory access to go through the lock. |
| | 30 | // XXX: Check the presence of CAS/swap instructions and set this parameter |
| | 31 | // accordingly. |
| | 32 | .sparc, .sparcel, .sparcv9 => 0, |
| | 33 | |
| 27 | // XXX: On x86/x86_64 we could check the presence of cmpxchg8b/cmpxchg16b | 34 | // XXX: On x86/x86_64 we could check the presence of cmpxchg8b/cmpxchg16b |
| 28 | // and set this parameter accordingly. | 35 | // and set this parameter accordingly. |
| 29 | else => @sizeOf(usize), | 36 | else => @sizeOf(usize), |
| ... | @@ -38,18 +45,35 @@ const SpinlockTable = struct { | ... | @@ -38,18 +45,35 @@ const SpinlockTable = struct { |
| 38 | const Spinlock = struct { | 45 | const Spinlock = struct { |
| 39 | // Prevent false sharing by providing enough padding between two | 46 | // Prevent false sharing by providing enough padding between two |
| 40 | // consecutive spinlock elements | 47 | // consecutive spinlock elements |
| 41 | v: enum(usize) { Unlocked = 0, Locked } align(cache_line_size) = .Unlocked, | 48 | v: if (arch.isSPARC()) enum(u8) { Unlocked = 0, Locked = 255 } else enum(usize) { Unlocked = 0, Locked } align(cache_line_size) = .Unlocked, |
| 42 | | 49 | |
| 43 | fn acquire(self: *@This()) void { | 50 | fn acquire(self: *@This()) void { |
| 44 | while (true) { | 51 | while (true) { |
| 45 | switch (@atomicRmw(@TypeOf(self.v), &self.v, .Xchg, .Locked, .Acquire)) { | 52 | const flag = if (comptime arch.isSPARC()) |
| | 53 | asm volatile ("ldstub [%[addr]], %[flag]" |
| | 54 | : [flag] "=r" (-> @TypeOf(self.v)), |
| | 55 | : [addr] "r" (&self.v), |
| | 56 | : "memory" |
| | 57 | ) |
| | 58 | else |
| | 59 | @atomicRmw(@TypeOf(self.v), &self.v, .Xchg, .Locked, .Acquire); |
| | 60 | |
| | 61 | switch (flag) { |
| 46 | .Unlocked => break, | 62 | .Unlocked => break, |
| 47 | .Locked => {}, | 63 | .Locked => {}, |
| 48 | } | 64 | } |
| 49 | } | 65 | } |
| 50 | } | 66 | } |
| 51 | fn release(self: *@This()) void { | 67 | fn release(self: *@This()) void { |
| 52 | @atomicStore(@TypeOf(self.v), &self.v, .Unlocked, .Release); | 68 | if (comptime arch.isSPARC()) { |
| | 69 | _ = asm volatile ("clr [%[addr]]" |
| | 70 | : |
| | 71 | : [addr] "r" (&self.v), |
| | 72 | : "memory" |
| | 73 | ); |
| | 74 | } else { |
| | 75 | @atomicStore(@TypeOf(self.v), &self.v, .Unlocked, .Release); |
| | 76 | } |
| 53 | } | 77 | } |
| 54 | }; | 78 | }; |
| 55 | | 79 | |