std/atomic — Critical sections

import std/atomic

A critical section guards a sequence of operations from being interrupted. This matters whenever the main program and an interrupt service routine share a multi-byte variable: an interrupt could fire between the two byte accesses of a 16-bit read, yielding a torn value. The pattern here disables interrupts, does the shared access, then restores the previous interrupt state — so it nests correctly and never enables interrupts that were not already on.

@atomic_start() -> u8

Begin a critical section. Saves the current status register (SREG, which holds the global interrupt-enable bit), disables interrupts, and returns the saved SREG value. Pass that value to @atomic_end.

@atomic_end($sreg_val: u8)

End a critical section by restoring the SREG value returned from @atomic_start. Interrupts are re-enabled only if they were enabled before the matching @atomic_start.

Example

Safely snapshot a 16-bit counter shared with an ISR:

import std/atomic

ram mut $ticks: u16 = 0          # written by an ISR elsewhere

@read_ticks() -> u16 {
    ram imut $saved: u8 = @atomic_start()  # disable interrupts, remember old state
    ram imut $snap: u16 = $ticks           # read both bytes with no ISR in between
    @atomic_end($saved)                    # restore interrupts to how they were
    return $snap                           # hand back the consistent snapshot
}

Keep critical sections as short as possible: every cycle spent with interrupts disabled adds latency to every other interrupt in the system.