| 640 | /* ── Public API ──────────────────────────────────────────────────────── */ |
| 641 | |
| 642 | bool cbm_diag_start(void) { |
| 643 | char env_buf[CBM_SZ_32] = ""; |
| 644 | cbm_safe_getenv("CBM_DIAGNOSTICS", env_buf, sizeof(env_buf), NULL); |
| 645 | if (env_buf[0] == '\0' || (strcmp(env_buf, "1") != 0 && strcmp(env_buf, "true") != 0) || |
| 646 | g_diag_started || g_diag_abandoned) { |
| 647 | return false; |
| 648 | } |
| 649 | |
| 650 | g_start_time = time(NULL); |
| 651 | g_diag_ndjson_size = 0; |
| 652 | atomic_store_explicit(&g_diag_stop, false, memory_order_release); |
| 653 | atomic_store_explicit(&g_diag_done, false, memory_order_release); |
| 654 | #ifdef CBM_DIAGNOSTICS_ENABLE_TEST_API |
| 655 | atomic_store_explicit(&g_diag_test_writer_reached, false, memory_order_release); |
| 656 | #endif |
| 657 | if (!diag_directory_prepare()) { |
| 658 | return false; |
| 659 | } |
| 660 | if (cbm_thread_create(&g_diag_thread, 0, diag_thread_fn, NULL) != 0) { |
| 661 | diag_directory_close(true); |
| 662 | return false; |
| 663 | } |
| 664 | |
| 665 | g_diag_started = true; |
| 666 | char interval[CBM_SZ_32]; |
| 667 | (void)snprintf(interval, sizeof(interval), "%d", DIAG_INTERVAL_MS / 1000); |
| 668 | /* Discovery must survive CBM_LOG_LEVEL suppression and paths containing |
| 669 | * spaces: a control record is the only announced copy of these paths. */ |
| 670 | cbm_log_control("diagnostics.start", "snapshot", g_diag_path, "trajectory", g_diag_ndjson_path, |
| 671 | "interval_s", interval); |
| 672 | return true; |
| 673 | } |
| 674 | |
| 675 | void cbm_diag_stop(void) { |
| 676 | if (!g_diag_started) { |
no test coverage detected