Skip to content

multithreaded collision fixes#7311

Draft
Goober5000 wants to merge 5 commits intoscp-fs2open:masterfrom
Goober5000:claude/multithreaded_collision_fixes
Draft

multithreaded collision fixes#7311
Goober5000 wants to merge 5 commits intoscp-fs2open:masterfrom
Goober5000:claude/multithreaded_collision_fixes

Conversation

@Goober5000
Copy link
Contributor

@Goober5000 Goober5000 commented Mar 22, 2026

Three commits, three four fixes to the multithreaded collision code. These correspond to items 1, 2, 3, and 5 from Claude's audit report.

  1. rename misleading variable check_again to never_check_again

The first element of collision_result means "never check again" per the typedef comment, but was destructured as check_again (opposite meaning). Rename to never_check_again to match the actual semantics and prevent future confusion.

  1. fix data races in ship-weapon collision threading

Two thread-safety bugs in ship_weapon_check_collision, which runs on
worker threads:

  1. update_danger_weapon() wrote to Ai_info[] (danger_weapon_objnum,
    danger_weapon_signature) without synchronization. Multiple weapons
    targeting the same ship would race on the same Ai_info entry.

  2. Homing missile detonation logic wrote wp->lifeleft and
    wp->weapon_flags directly on the Weapons[] global array.

Fix: defer both writes to the main-thread post-processing phase via
new flags in ship_weapon_collision_data. Also convert the collision
data from a 6-element tuple to a named struct for readability.

  1. fix data race in ship-ship collision submodel checking

ship_ship_check_collision() toggled pmi->submodel[].collision_checked
flags on the heavy ship's polymodel_instance to selectively enable/
disable submodel collision checks. When two collision pairs shared the
same heavy ship, worker threads would race on the same pmi entries.

Fix: add a collision_checked_override pointer to mc_info that lets
callers provide a thread-local array of collision_checked values.
model_collide() uses the override when set, falling back to the
pmi->submodel[] field otherwise. ship_ship_check_collision() now
builds a local SCP_vector and passes it via the override,
completely avoiding writes to shared polymodel_instance state.

Also added @BMagnu 's fix for bug 4:

  1. Ensure threads have spun down before continuing non-threaded execution

Goober5000 and others added 3 commits March 21, 2026 21:50
The first element of collision_result means "never check again" per the
typedef comment, but was destructured as check_again (opposite meaning).
Rename to never_check_again to match the actual semantics and prevent
future confusion.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two thread-safety bugs in ship_weapon_check_collision, which runs on
worker threads:

1. update_danger_weapon() wrote to Ai_info[] (danger_weapon_objnum,
   danger_weapon_signature) without synchronization. Multiple weapons
   targeting the same ship would race on the same Ai_info entry.

2. Homing missile detonation logic wrote wp->lifeleft and
   wp->weapon_flags directly on the Weapons[] global array.

Fix: defer both writes to the main-thread post-processing phase via
new flags in ship_weapon_collision_data. Also convert the collision
data from a 6-element tuple to a named struct for readability.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ship_ship_check_collision() toggled pmi->submodel[].collision_checked
flags on the heavy ship's polymodel_instance to selectively enable/
disable submodel collision checks. When two collision pairs shared the
same heavy ship, worker threads would race on the same pmi entries.

Fix: add a collision_checked_override pointer to mc_info that lets
callers provide a thread-local array of collision_checked values.
model_collide() uses the override when set, falling back to the
pmi->submodel[] field otherwise. ship_ship_check_collision() now
builds a local SCP_vector<char> and passes it via the override,
completely avoiding writes to shared polymodel_instance state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Goober5000 Goober5000 requested a review from BMagnu March 22, 2026 03:37
@Goober5000 Goober5000 added the fix A fix for bugs, not-a-bugs, and/or regressions. label Mar 22, 2026
BMagnu and others added 2 commits March 24, 2026 21:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix A fix for bugs, not-a-bugs, and/or regressions.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants