{"record":{"id":"dd1d634d797278e6","repo":"embassy-rs/embassy","slug":"panicrawmutex-locked-from-multiple-contexts","errorCode":null,"errorMessage":"PanicRawMutex locked from multiple contexts","messagePattern":"PanicRawMutex locked from multiple contexts","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"embassy-sync/src/blocking_mutex/raw.rs","lineNumber":90,"sourceCode":"unsafe impl Send for PanicRawMutex {}\nunsafe impl Sync for PanicRawMutex {}\n\nimpl PanicRawMutex {\n    /// Create a new `PanicRawMutex`.\n    pub const fn new() -> Self {\n        Self {\n            locked: AtomicBool::new(false),\n        }\n    }\n}\n\nunsafe impl RawMutex for PanicRawMutex {\n    const INIT: Self = Self::new();\n\n    fn lock<R>(&self, f: impl FnOnce() -> R) -> R {\n        #[cfg(target_has_atomic = \"8\")]\n        if self.locked.swap(true, Ordering::Relaxed) {\n            panic!(\"PanicRawMutex locked from multiple contexts\")\n        }\n\n        #[cfg(not(target_has_atomic = \"8\"))]\n        critical_section::with(|_| {\n            if self.locked.load(Ordering::Acquire) {\n                panic!(\"PanicRawMutex locked from multiple contexts\")\n            }\n            self.locked.store(true, Ordering::Release);\n        });\n\n        let ret = f();\n\n        self.locked.store(false, Ordering::Relaxed);\n        ret\n    }\n}\n\n// ================","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-sync/src/blocking_mutex/raw.rs#L72-L108","documentation":"PanicRawMutex is a raw mutex intended only for use inside panic handlers and other single-context settings; it does not block or spin. Its lock() detects double acquisition via an atomic flag and panics rather than waiting, because blocking inside a panic handler is forbidden.","triggerScenarios":"Calling lock() on a mutex backed by PanicRawMutex while it is already locked — e.g. the same static shared between a panic handler and normal code, or between two interrupt/NMI contexts, or re-entrant locking in one call path.","commonSituations":"Using a PanicRawMutex-backed channel/format shared with panic printing (defmt-panic / core::fmt buffering) from regular task code; nesting locks of the same mutex; accessing the shared resource in both an exception handler and mainline code.","solutions":["Ensure PanicRawMutex-protected resources are only accessed from one context (the panic handler).","Switch the shared resource to a blocking raw mutex (CriticalSectionRawMutex or ThreadModeRawMutex) if multiple contexts must share it.","Add a re-entrancy guard or restructure code so the same mutex is never acquired twice on one call path."],"exampleFix":"// before\nstatic CONSOLE: Console = Console::new(PanicRawMutex::INIT);\n// after (used from tasks + handlers)\nstatic CONSOLE: Console = Console::new(CriticalSectionRawMutex::INIT);","handlingStrategy":"validation","validationCode":"// Audit call sites: only the panic handler may touch PanicRawMutex resources.\n// Prefer CriticalSectionRawMutex for anything shared across contexts.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never share PanicRawMutex-backed statics with task or ISR code","Use CriticalSectionRawMutex/ThreadModeRawMutex for multi-context data","Avoid nested locking of the same raw mutex","Document which context owns each mutex-protected resource"],"tags":["embedded","concurrency","mutex","panic"],"backgroundTag":"internal-invariant-violation","analyzedSha":"463a07b963419a1bfe61d5d597c44acb810afb8b","analyzedAt":"2026-09-10T13:38:26.660Z","contentChangedAt":"2026-09-10T13:38:26.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}