| 3155 | } |
| 3156 | |
| 3157 | int cbm_parallel_resolve(cbm_pipeline_ctx_t *ctx, const cbm_file_info_t *files, int file_count, |
| 3158 | CBMFileResult **result_cache, _Atomic int64_t *shared_ids, |
| 3159 | int worker_count, CBMLSPDef *all_defs, int def_count, |
| 3160 | char *const *def_modules, struct CBMModuleDefIndex *module_def_index, |
| 3161 | void *cross_registries_v) { |
| 3162 | /* See header: typed as void* across the TU boundary; cast back here. */ |
| 3163 | CBMCrossLspRegistries *cross_registries = (CBMCrossLspRegistries *)cross_registries_v; |
| 3164 | if (file_count == 0) { |
| 3165 | return 0; |
| 3166 | } |
| 3167 | |
| 3168 | cbm_log_info("parallel.resolve.start", "files", itoa_log(file_count), "workers", |
| 3169 | itoa_log(worker_count)); |
| 3170 | |
| 3171 | resolve_worker_state_t *workers = NULL; |
| 3172 | if (cbm_aligned_alloc((void **)&workers, CBM_CACHE_LINE, |
| 3173 | (size_t)worker_count * sizeof(resolve_worker_state_t)) != 0) { |
| 3174 | return CBM_NOT_FOUND; |
| 3175 | } |
| 3176 | memset(workers, 0, (size_t)worker_count * sizeof(resolve_worker_state_t)); |
| 3177 | |
| 3178 | resolve_ctx_t rc = { |
| 3179 | .files = files, |
| 3180 | .file_count = file_count, |
| 3181 | .project_name = ctx->project_name, |
| 3182 | .repo_path = ctx->repo_path, |
| 3183 | .workers = workers, |
| 3184 | .max_workers = worker_count, |
| 3185 | .result_cache = result_cache, |
| 3186 | .main_gbuf = ctx->gbuf, |
| 3187 | .registry = ctx->registry, |
| 3188 | .shared_ids = shared_ids, |
| 3189 | .cancelled = ctx->cancelled, |
| 3190 | .all_defs = all_defs, |
| 3191 | .def_count = def_count, |
| 3192 | .def_modules = def_modules, |
| 3193 | .module_def_index = module_def_index, |
| 3194 | .cross_registries = cross_registries, |
| 3195 | }; |
| 3196 | atomic_init(&rc.next_file_idx, 0); |
| 3197 | atomic_init(&rc.lsp_cross_processed, 0); |
| 3198 | atomic_init(&rc.lsp_cross_skipped_no_source, 0); |
| 3199 | /* F4 lazy shared Rust registry: mutex up before workers spawn. */ |
| 3200 | atomic_init(&rc.rust_shared_reg, NULL); |
| 3201 | cbm_mutex_init(&rc.rust_shared_mu); |
| 3202 | rc.rust_shared_arena_live = false; |
| 3203 | |
| 3204 | /* Sub-phase: Dispatch resolve workers (per-file call/usage resolution, PARALLEL) */ |
| 3205 | CBM_PROF_START(t_resolve_dispatch); |
| 3206 | cbm_parallel_for_opts_t opts = {.max_workers = worker_count, .force_pthreads = false}; |
| 3207 | cbm_parallel_for(worker_count, resolve_worker, &rc, opts); |
| 3208 | CBM_PROF_END_N("parallel_resolve", "1_dispatch_workers_parallel", t_resolve_dispatch, |
| 3209 | file_count); |
| 3210 | /* Workers joined: the shared Rust registry (if built) is no longer read. |
| 3211 | * Free its dedicated arena + the lock (registry was self-contained: it strdup'd |
| 3212 | * all QNs, so freeing all_defs afterward is safe). */ |
| 3213 | if (rc.rust_shared_arena_live) { |
| 3214 | cbm_arena_destroy(&rc.rust_shared_arena); |