| 2837 | } |
| 2838 | |
| 2839 | int cbm_parallel_resolve(cbm_pipeline_ctx_t *ctx, const cbm_file_info_t *files, int file_count, |
| 2840 | CBMFileResult **result_cache, _Atomic int64_t *shared_ids, |
| 2841 | int worker_count, CBMLSPDef *all_defs, int def_count, |
| 2842 | char *const *def_modules, struct CBMModuleDefIndex *module_def_index, |
| 2843 | void *cross_registries_v) { |
| 2844 | /* See header: typed as void* across the TU boundary; cast back here. */ |
| 2845 | CBMCrossLspRegistries *cross_registries = (CBMCrossLspRegistries *)cross_registries_v; |
| 2846 | if (file_count == 0) { |
| 2847 | return 0; |
| 2848 | } |
| 2849 | |
| 2850 | cbm_log_info("parallel.resolve.start", "files", itoa_log(file_count), "workers", |
| 2851 | itoa_log(worker_count)); |
| 2852 | |
| 2853 | resolve_worker_state_t *workers = NULL; |
| 2854 | if (cbm_aligned_alloc((void **)&workers, CBM_CACHE_LINE, |
| 2855 | (size_t)worker_count * sizeof(resolve_worker_state_t)) != 0) { |
| 2856 | return CBM_NOT_FOUND; |
| 2857 | } |
| 2858 | memset(workers, 0, (size_t)worker_count * sizeof(resolve_worker_state_t)); |
| 2859 | |
| 2860 | resolve_ctx_t rc = { |
| 2861 | .files = files, |
| 2862 | .file_count = file_count, |
| 2863 | .project_name = ctx->project_name, |
| 2864 | .repo_path = ctx->repo_path, |
| 2865 | .workers = workers, |
| 2866 | .max_workers = worker_count, |
| 2867 | .result_cache = result_cache, |
| 2868 | .main_gbuf = ctx->gbuf, |
| 2869 | .registry = ctx->registry, |
| 2870 | .shared_ids = shared_ids, |
| 2871 | .cancelled = ctx->cancelled, |
| 2872 | .all_defs = all_defs, |
| 2873 | .def_count = def_count, |
| 2874 | .def_modules = def_modules, |
| 2875 | .module_def_index = module_def_index, |
| 2876 | .cross_registries = cross_registries, |
| 2877 | }; |
| 2878 | atomic_init(&rc.next_file_idx, 0); |
| 2879 | atomic_init(&rc.lsp_cross_processed, 0); |
| 2880 | atomic_init(&rc.lsp_cross_skipped_no_source, 0); |
| 2881 | /* F4 lazy shared Rust registry: mutex up before workers spawn. */ |
| 2882 | atomic_init(&rc.rust_shared_reg, NULL); |
| 2883 | cbm_mutex_init(&rc.rust_shared_mu); |
| 2884 | rc.rust_shared_arena_live = false; |
| 2885 | |
| 2886 | /* Sub-phase: Dispatch resolve workers (per-file call/usage resolution, PARALLEL) */ |
| 2887 | CBM_PROF_START(t_resolve_dispatch); |
| 2888 | cbm_parallel_for_opts_t opts = {.max_workers = worker_count, .force_pthreads = false}; |
| 2889 | cbm_parallel_for(worker_count, resolve_worker, &rc, opts); |
| 2890 | CBM_PROF_END_N("parallel_resolve", "1_dispatch_workers_parallel", t_resolve_dispatch, |
| 2891 | file_count); |
| 2892 | /* Workers joined: the shared Rust registry (if built) is no longer read. |
| 2893 | * Free its dedicated arena + the lock (registry was self-contained: it strdup'd |
| 2894 | * all QNs, so freeing all_defs afterward is safe). */ |
| 2895 | if (rc.rust_shared_arena_live) { |
| 2896 | cbm_arena_destroy(&rc.rust_shared_arena); |