{"record":{"id":"4c20142988d62196","repo":"rust-lang/rust-analyzer","slug":"profiler-already-started","errorCode":null,"errorMessage":"profiler already started","messagePattern":"profiler already started","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/profile/src/google_cpu_profiler.rs","lineNumber":29,"sourceCode":"#[allow(non_snake_case)]\nunsafe extern \"C\" {\n    fn ProfilerStart(fname: *const c_char) -> i32;\n    fn ProfilerStop();\n}\n\nconst OFF: usize = 0;\nconst ON: usize = 1;\nconst PENDING: usize = 2;\n\nfn transition(current: usize, new: usize) -> bool {\n    static STATE: AtomicUsize = AtomicUsize::new(OFF);\n\n    STATE.compare_exchange(current, new, Ordering::SeqCst, Ordering::SeqCst).is_ok()\n}\n\npub(crate) fn start(path: &Path) {\n    if !transition(OFF, PENDING) {\n        panic!(\"profiler already started\");\n    }\n    let path = CString::new(path.display().to_string()).unwrap();\n    if unsafe { ProfilerStart(path.as_ptr()) } == 0 {\n        panic!(\"profiler failed to start\")\n    }\n    assert!(transition(PENDING, ON));\n}\n\npub(crate) fn stop() {\n    if !transition(ON, PENDING) {\n        panic!(\"profiler is not started\")\n    }\n    unsafe { ProfilerStop() };\n    assert!(transition(PENDING, OFF));\n}\n","sourceCodeStart":11,"sourceCodeEnd":45,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/crates/profile/src/google_cpu_profiler.rs#L11-L45","documentation":"The google_cpu_profiler wrapper in the `profile` crate is single-instance: an atomic STATE machine enforces OFF -> PENDING -> ON transitions. `start` panics with 'profiler already started' if the profiler is not in the OFF state when starting, i.e. a previous session was never stopped.","triggerScenarios":"Calling `profile::start()` twice without an intervening `stop()`; a prior `stop()` failed or was skipped; concurrent startup from two threads (the compare_exchange ensures only one wins).","commonSituations":"Long-lived processes toggling CPU profiling where an early error path skipped `stop()`; tests or tools that start profiling in each iteration without cleanup; two profiling entry points racing.","solutions":["Ensure every `start()` is paired with `stop()`, including on error paths (use a guard or defer pattern)","Check current state before starting, or restructure to start profiling once and toggle collection instead","Fix the exception/interrupt path that skipped the previous `stop()` call"],"exampleFix":"// before\nprofiler::start(&path);\nrun_work(); // early return skips stop\nprofiler::start(&path); // panics\n// after\nprofiler::start(&path);\nlet result = run_work();\nprofiler::stop();\nresult","handlingStrategy":"try-catch","validationCode":"// no public state accessor; guard at call site\nstatic PROFILING: AtomicBool = AtomicBool::new(false);\nfn can_start() -> bool { !PROFILING.load(Ordering::SeqCst) }","typeGuard":null,"tryCatchPattern":"std::panic::catch_unwind(|| profiler::start(&path))\n    .err()\n    .map(|_| eprintln!(\"profiler already running; skipping start\"));","preventionTips":["Pair every start() with exactly one stop(), including on early-return paths","Use a guard type (Drop impl) that calls stop automatically","Never start profiling twice in one process; toggle at a higher level instead","Avoid concurrent profiling start from multiple threads"],"tags":["rust","profiling","state-machine","panic"],"backgroundTag":"profiler-already-running","analyzedSha":"e8f7e90aa3e7b26aa9a000200f606c1078da99ec","analyzedAt":"2026-09-03T21:08:06.959Z","contentChangedAt":"2026-09-03T21:08:06.959Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}