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