Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

SpinlockTable

atomics.SpinlockTable
const SpinlockTable = struct

File

lib/compiler_rt/atomics.zig:53

Code

const SpinlockTable = struct {
    // Allocate ~4096 bytes of memory for the spinlock table
    const max_spinlocks = 64;

    const Spinlock = struct {
        // SPARC ldstub instruction will write a 255 into the memory location.
        // We'll use that as a sign that the lock is currently held.
        // See also: Section B.7 in SPARCv8 spec & A.29 in SPARCv9 spec.
        const sparc_lock: type = enum(u8) { Unlocked = 0, Locked = 255 };
        const other_lock: type = enum(usize) { Unlocked = 0, Locked };

        // Prevent false sharing by providing enough padding between two
        // consecutive spinlock elements
        v: if (arch.isSPARC()) sparc_lock else other_lock align(cache_line_size) = .Unlocked,

        fn acquire(self: *@This()) void {
            while (true) {
                const flag = if (comptime arch.isSPARC()) flag: {
                    break :flag asm volatile ("ldstub [%[addr]], %[flag]"
                        : [flag] "=r" (-> @TypeOf(self.v)),
                        : [addr] "r" (&self.v),
                        : .{ .memory = true });
                } else flag: {
                    break :flag @atomicRmw(@TypeOf(self.v), &self.v, .Xchg, .Locked, .acquire);
                };

                switch (flag) {
                    .Unlocked => break,
                    .Locked => {},
                }
            }
        }
        fn release(self: *@This()) void {
            if (comptime arch.isSPARC()) {
                _ = asm volatile ("clrb [%[addr]]"
                    :
                    : [addr] "r" (&self.v),
                    : .{ .memory = true });
            } else {
                @atomicStore(@TypeOf(self.v), &self.v, .Unlocked, .release);
            }
        }
    };

    list: [max_spinlocks]Spinlock = @splat(.{}),

    // The spinlock table behaves as a really simple hash table, mapping
    // addresses to spinlocks. The mapping is not unique but that's only a
    // performance problem as the lock will be contended by more than a pair of
    // threads.
    fn get(self: *@This(), address: usize) *Spinlock {
        var sl = &self.list[(address >> 3) % max_spinlocks];
        sl.acquire();
        return sl;
    }
}