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.

Reply via email to