| 3181 | } |
| 3182 | |
| 3183 | int cbm_parallel_resolve(cbm_pipeline_ctx_t *ctx, const cbm_file_info_t *files, int file_count, |
| 3184 | CBMFileResult **result_cache, _Atomic int64_t *shared_ids, |
| 3185 | int worker_count, CBMLSPDef *all_defs, int def_count, |
| 3186 | char *const *def_modules, struct CBMModuleDefIndex *module_def_index, |
| 3187 | void *cross_registries_v) { |
| 3188 | /* See header: typed as void* across the TU boundary; cast back here. */ |
| 3189 | CBMCrossLspRegistries *cross_registries = (CBMCrossLspRegistries *)cross_registries_v; |
| 3190 | if (file_count == 0) { |
| 3191 | return 0; |
| 3192 | } |
| 3193 | |
| 3194 | cbm_log_info("parallel.resolve.start", "files", itoa_log(file_count), "workers", |
| 3195 | itoa_log(worker_count)); |
| 3196 | |
| 3197 | resolve_worker_state_t *workers = NULL; |
| 3198 | if (cbm_aligned_alloc((void **)&workers, CBM_CACHE_LINE, |
| 3199 | (size_t)worker_count * sizeof(resolve_worker_state_t)) != 0) { |
| 3200 | return CBM_NOT_FOUND; |
| 3201 | } |
| 3202 | memset(workers, 0, (size_t)worker_count * sizeof(resolve_worker_state_t)); |
| 3203 | |
| 3204 | resolve_ctx_t rc = { |
| 3205 | .files = files, |
| 3206 | .file_count = file_count, |
| 3207 | .project_name = ctx->project_name, |
| 3208 | .repo_path = ctx->repo_path, |
| 3209 | .workers = workers, |
| 3210 | .max_workers = worker_count, |
| 3211 | .result_cache = result_cache, |
| 3212 | .main_gbuf = ctx->gbuf, |
| 3213 | .registry = ctx->registry, |
| 3214 | .shared_ids = shared_ids, |
| 3215 | .cancelled = ctx->cancelled, |
| 3216 | .all_defs = all_defs, |
| 3217 | .def_count = def_count, |
| 3218 | .def_modules = def_modules, |
| 3219 | .module_def_index = module_def_index, |
| 3220 | .cross_registries = cross_registries, |
| 3221 | }; |
| 3222 | atomic_init(&rc.next_file_idx, 0); |
| 3223 | atomic_init(&rc.lsp_cross_processed, 0); |
| 3224 | atomic_init(&rc.lsp_cross_skipped_no_source, 0); |
| 3225 | /* F4 lazy shared Rust registry: mutex up before workers spawn. */ |
| 3226 | atomic_init(&rc.rust_shared_reg, NULL); |
| 3227 | cbm_mutex_init(&rc.rust_shared_mu); |
| 3228 | rc.rust_shared_arena_live = false; |
| 3229 | |
| 3230 | /* Sub-phase: Dispatch resolve workers (per-file call/usage resolution, PARALLEL) */ |
| 3231 | CBM_PROF_START(t_resolve_dispatch); |
| 3232 | cbm_parallel_for_opts_t opts = {.max_workers = worker_count, .force_pthreads = false}; |
| 3233 | cbm_scale_begin(&rc.scale, "parallel_resolve", (long)file_count); |
| 3234 | cbm_parallel_for(worker_count, resolve_worker, &rc, opts); |
| 3235 | cbm_scale_end(&rc.scale); |
| 3236 | CBM_PROF_END_N("parallel_resolve", "1_dispatch_workers_parallel", t_resolve_dispatch, |
| 3237 | file_count); |
| 3238 | /* Workers joined: the shared Rust registry (if built) is no longer read. |
| 3239 | * Free its dedicated arena + the lock (registry was self-contained: it strdup'd |
| 3240 | * all QNs, so freeing all_defs afterward is safe). */ |