
Issue #20456 has been updated by byroot (Jean Boussier).
but it sounds to me like it can't.
It could, and there's precedent. For instance Ruby unlock mutexes owned by dead threads. This would require to keep a list of the threads that incremented a hash's `iterlevel`, so definitely not free, but perhaps acceptable overhead. Would be worth trying IMO. One possible implementation could be for each threads (or fiber?) to have a stack of `VALUE`, in which to store the threads for which it bumped the iterlevel. The overhead would be an extra RArray `push/pop` when starting and exiting iterating on a Hash, which I think may not matter that much in the grand scheme of things. ---------------------------------------- Bug #20456: Hash can get stuck marked as iterating through process forking https://bugs.ruby-lang.org/issues/20456#change-108127 * Author: blowfishpro (Talia Wong) * Status: Open * ruby -v: 3.3.0 * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- # Steps to Reproduce 1. Iterate over a hash 1. While that iteration is happening, fork the process a. This should be done in a way that causes the iteration to never finish from the child process's view, e.g. fork with a block, or iteration is happening in a different thread than fork 1. Attempt to add a new key to the hash in the child process a. This can be before or after the iteration finishes in the parent process, doesn't matter # Observed Behavior The child process can never add a new key to the hash, always fails with `RuntimeError: can't add a new key into hash during iteration` # Desired The hash is no longer iterating in the child process, so it can be modified as needed # Examples ## With threads: ```ruby h = { a: 1 } t = Thread.new do sleep 0.05 pid = fork do sleep 0.1 puts 'child: before' h[:b] = 2 puts 'child: after' end Process.wait2(pid) end puts 'parent: before' h.each do sleep 0.1 end puts 'parent: after' puts t.join.value.inspect ``` produces: ``` parent: before parent: after child: before can't add a new key into hash during iteration (RuntimeError) [34450, #<Process::Status: pid 34450 exit 1>] ``` ## Without threads: ``` ruby h = { a: 1 } pid = nil puts 'parent: before' h.each do pid = fork do sleep 0.05 puts 'child: before' h[:b] = 2 puts 'child: after' end end puts 'parent: after' puts Process.wait2(pid).inspect ``` produces: ``` parent: before parent: after child: before can't add a new key into hash during iteration (RuntimeError) [17809, #<Process::Status: pid 17809 exit 1>] ``` # Platform information This behavior has been observed in the following environments - Ruby 3.3.0 on Mac OS 14.4.1 (Apple M1 Max) installed via [asdf](https://asdf-vm.com/) - Ruby 2.7.5 on Mac OS 14.4.1 (Apple M1 Max) installed via [asdf](https://asdf-vm.com/) - Ruby 3.2.3 on RockyLinux 8.4 (x86_64) installed from [Fullstaq](https://fullstaqruby.org/) -- https://bugs.ruby-lang.org/