rust-embedded/rust-raspberrypi-OS-tutorials · error

transition_to_single_core_main() called while state != Init

Error message

transition_to_single_core_main() called while state != Init

What it means

transition_to_single_core_main() performs an atomic compare_exchange from INIT to SINGLE_CORE_MAIN; if the exchange fails the current state was not INIT, so the kernel panics. This enforces a one-way, exactly-once state transition: the kernel may enter single-core-main mode only once, from the init state. Calling it twice, or after another transition, triggers this panic.

Source

Thrown at 20_timer_callbacks/kernel/src/state.rs:89

    /// Return if the kernel is init state.
    pub fn is_init(&self) -> bool {
        self.state() == State::Init
    }

    /// Transition from Init to SingleCoreMain.
    pub fn transition_to_single_core_main(&self) {
        if self
            .0
            .compare_exchange(
                Self::INIT,
                Self::SINGLE_CORE_MAIN,
                Ordering::Acquire,
                Ordering::Relaxed,
            )
            .is_err()
        {
            panic!("transition_to_single_core_main() called while state != Init");
        }
    }
}

View on GitHub (pinned to 644474cc09)

Solutions

  1. Call the transition exactly once, from a single designated boot path/core.
  2. Guard the call: check `state() == State::Init` (or use is_init()) before attempting the transition, and skip if already transitioned.
  3. If multiple cores race, elect one main core (core id check) before calling.
  4. If re-init is genuinely needed, reset the state atom back to INIT first (only where safe/designed).

Example fix

// before
kernel_state.transition_to_single_core_main();
// after
if kernel_state.is_init() {
    kernel_state.transition_to_single_core_main();
}
Defensive patterns

Strategy: validation

Validate before calling

fn can_transition_to_single_core_main(current: State) -> bool {
    current == State::Init
}

Type guard

fn is_init_state(raw: u8) -> bool {
    raw == INIT
}

Try / catch

// The transition panics on failure; check first:
if kernel_state.is_init() {
    kernel_state.transition_to_single_core_main();
} else {
    log::warn!("skipping transition, already initialized");
}

Prevention

When it happens

Trigger: Calling transition_to_single_core_main() twice (e.g. re-running boot logic, a second CPU entering the same path); calling it after transition_to_multi_core_main(); calling it on an already-initialized kernel in a restart/re-init attempt.

Common situations: Boot code executed on multiple cores racing to transition (only the INIT->SINGLE_CORE_MAIN winner succeeds); a test harness or reboot path re-invoking init routines; duplicate initialization of the kernel driver; state already advanced by a prior subsystem init.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of rust-embedded/rust-raspberrypi-OS-tutorials@644474cc09 (2026-09-06). Data as JSON: /api/errors/b17100820379643e. Report an issue: GitHub.