https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127893
--- Comment #14 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The master branch has been updated by Jerry DeLisle <[email protected]>: https://gcc.gnu.org/g:c91294dca7d29682c55c8b989c0197f84eb57e53 commit r17-5826-gc91294dca7d29682c55c8b989c0197f84eb57e53 Author: Jerry DeLisle <[email protected]> Date: Sun Nov 1 12:17:30 2026 -0800 libgfortran: [PR127893] Look up cached units without the unit rwlock Every data transfer statement takes unit_rwlock in get_gfc_unit, even when each thread does I/O on its own unit. On Darwin the rwlock thrashes under that load, so parallel I/O on separate units became many times slower than with the mutex used before r14-6425. The unit cache could not be read without unit_rwlock because closing a unit freed it, so a pointer read from the cache could dangle. Keep closed units on a free list for reuse and free them only at program exit, so a cached pointer always refers to a gfc_unit. Make the cache a direct-mapped table of 64 slots accessed atomically. get_gfc_unit and check_for_recursive trylock the cached unit and use it only if, with its lock held, it is open with the expected number; otherwise they fall back to the tree lookup under unit_rwlock. check_for_recursive now holds unit_rwlock while it searches the tree, and find_file takes it for writing before recycling a closed unit. Assisted-by: Claude Opus 5.5 PR libfortran/127893 libgfortran/ChangeLog: * io/io.h (recycle_unit): Declare. * io/unit.c (CACHE_SIZE): Increase to 64. (CACHE_SLOT): New macro. (unit_free_list): New variable. (insert_unit): Reuse a unit from the free list. (recycle_unit, probe_unit_cache, set_unit_cache): New functions. (check_for_recursive): Probe the unit cache first. Hold unit_rwlock while searching the unit tree. (get_gfc_unit): Probe the unit cache before taking unit_rwlock. Use the direct-mapped cache. Recycle a closed unit instead of freeing it. (close_unit_1): Clear the unit's cache slot. Recycle the unit instead of freeing it. (close_units): Free the units on the free list. * io/unix.c (find_file): Take unit_rwlock for writing and recycle a closed unit instead of freeing it. (flush_all_units): Recycle a closed unit instead of freeing it. libgomp/ChangeLog: * testsuite/libgomp.fortran/unit-cache-1.f90: New test.
